// Copyright 2017 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "fxjs/xfa/cjx_object.h" #include #include "core/fxcrt/cfx_decimal.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/xml/cfx_xmltext.h" #include "fxjs/cfxjse_engine.h" #include "fxjs/cfxjse_value.h" #include "fxjs/cjs_return.h" #include "fxjs/xfa/cjx_boolean.h" #include "fxjs/xfa/cjx_draw.h" #include "fxjs/xfa/cjx_field.h" #include "fxjs/xfa/cjx_instancemanager.h" #include "third_party/base/ptr_util.h" #include "xfa/fxfa/cxfa_ffnotify.h" #include "xfa/fxfa/cxfa_ffwidget.h" #include "xfa/fxfa/parser/cxfa_border.h" #include "xfa/fxfa/parser/cxfa_document.h" #include "xfa/fxfa/parser/cxfa_edge.h" #include "xfa/fxfa/parser/cxfa_fill.h" #include "xfa/fxfa/parser/cxfa_layoutprocessor.h" #include "xfa/fxfa/parser/cxfa_measurement.h" #include "xfa/fxfa/parser/cxfa_node.h" #include "xfa/fxfa/parser/cxfa_object.h" #include "xfa/fxfa/parser/cxfa_occur.h" #include "xfa/fxfa/parser/cxfa_proto.h" #include "xfa/fxfa/parser/cxfa_subform.h" #include "xfa/fxfa/parser/cxfa_validate.h" #include "xfa/fxfa/parser/cxfa_value.h" #include "xfa/fxfa/parser/xfa_utils.h" namespace { void XFA_DeleteWideString(void* pData) { delete static_cast(pData); } void XFA_CopyWideString(void*& pData) { if (!pData) return; pData = new WideString(*reinterpret_cast(pData)); } XFA_MAPDATABLOCKCALLBACKINFO deleteWideStringCallBack = {XFA_DeleteWideString, XFA_CopyWideString}; enum XFA_KEYTYPE { XFA_KEYTYPE_Custom, XFA_KEYTYPE_Element, }; void* GetMapKey_Custom(const WideStringView& wsKey) { uint32_t dwKey = FX_HashCode_GetW(wsKey, false); return (void*)(uintptr_t)((dwKey << 1) | XFA_KEYTYPE_Custom); } void* GetMapKey_Element(XFA_Element eType, XFA_Attribute eAttribute) { return (void*)(uintptr_t)((static_cast(eType) << 16) | (static_cast(eAttribute) << 8) | XFA_KEYTYPE_Element); } void XFA_DefaultFreeData(void* pData) {} XFA_MAPDATABLOCKCALLBACKINFO gs_XFADefaultFreeData = {XFA_DefaultFreeData, nullptr}; std::tuple StrToRGB(const WideString& strRGB) { int32_t r = 0; int32_t g = 0; int32_t b = 0; size_t iIndex = 0; for (size_t i = 0; i < strRGB.GetLength(); ++i) { wchar_t ch = strRGB[i]; if (ch == L',') ++iIndex; if (iIndex > 2) break; int32_t iValue = ch - L'0'; if (iValue >= 0 && iValue <= 9) { switch (iIndex) { case 0: r = r * 10 + iValue; break; case 1: g = g * 10 + iValue; break; default: b = b * 10 + iValue; break; } } } return {r, g, b}; } } // namespace struct XFA_MAPDATABLOCK { uint8_t* GetData() const { return (uint8_t*)this + sizeof(XFA_MAPDATABLOCK); } XFA_MAPDATABLOCKCALLBACKINFO* pCallbackInfo; int32_t iBytes; }; struct XFA_MAPMODULEDATA { XFA_MAPMODULEDATA() {} ~XFA_MAPMODULEDATA() {} std::map m_ValueMap; std::map m_BufferMap; }; CJX_Object::CJX_Object(CXFA_Object* obj) : object_(obj) {} CJX_Object::~CJX_Object() { ClearMapModuleBuffer(); } void CJX_Object::DefineMethods(const CJX_MethodSpec method_specs[], size_t count) { for (size_t i = 0; i < count; ++i) method_specs_[method_specs[i].pName] = method_specs[i].pMethodCall; } CXFA_Document* CJX_Object::GetDocument() const { return object_->GetDocument(); } void CJX_Object::className(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (bSetting) { ThrowInvalidPropertyException(); return; } pValue->SetString( FX_UTF8Encode(GetXFAObject()->GetClassName()).AsStringView()); } int32_t CJX_Object::Subform_and_SubformSet_InstanceIndex() { int32_t index = 0; for (CXFA_Node* pNode = ToNode(GetXFAObject())->GetNodeItem(XFA_NODEITEM_PrevSibling); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_PrevSibling)) { if ((pNode->GetElementType() != XFA_Element::Subform) && (pNode->GetElementType() != XFA_Element::SubformSet)) { break; } index++; } return index; } bool CJX_Object::HasMethod(const WideString& func) const { return pdfium::ContainsKey(method_specs_, func.UTF8Encode()); } CJS_Return CJX_Object::RunMethod( const WideString& func, const std::vector>& params) { auto it = method_specs_.find(func.UTF8Encode()); if (it == method_specs_.end()) return CJS_Return(false); return it->second(this, GetXFAObject()->GetDocument()->GetScriptContext(), params); } void CJX_Object::ThrowTooManyOccurancesException(const WideString& obj) const { ThrowException( L"The element [%ls] has violated its allowable number of occurrences.", obj.c_str()); } void CJX_Object::ThrowInvalidPropertyException() const { ThrowException(L"Invalid property set operation."); } void CJX_Object::ThrowIndexOutOfBoundsException() const { ThrowException(L"Index value is out of bounds."); } void CJX_Object::ThrowParamCountMismatchException( const WideString& method) const { ThrowException(L"Incorrect number of parameters calling method '%.16s'.", method.c_str()); } void CJX_Object::ThrowArgumentMismatchException() const { ThrowException(L"Argument mismatch in property or function argument."); } void CJX_Object::ThrowException(const wchar_t* str, ...) const { va_list arg_ptr; va_start(arg_ptr, str); WideString wsMessage = WideString::FormatV(str, arg_ptr); va_end(arg_ptr); ASSERT(!wsMessage.IsEmpty()); FXJSE_ThrowMessage(wsMessage.UTF8Encode().AsStringView()); } bool CJX_Object::HasAttribute(XFA_Attribute eAttr) { void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr); return HasMapModuleKey(pKey); } bool CJX_Object::SetAttribute(XFA_Attribute eAttr, const WideStringView& wsValue, bool bNotify) { switch (ToNode(GetXFAObject())->GetAttributeType(eAttr)) { case XFA_AttributeType::Enum: { pdfium::Optional item = CXFA_Node::NameToAttributeEnum(wsValue); return SetEnum( eAttr, item ? *item : *(ToNode(GetXFAObject())->GetDefaultEnum(eAttr)), bNotify); } case XFA_AttributeType::CData: return SetCData(eAttr, WideString(wsValue), bNotify, false); case XFA_AttributeType::Boolean: return SetBoolean(eAttr, wsValue != L"0", bNotify); case XFA_AttributeType::Integer: return SetInteger(eAttr, FXSYS_round(FXSYS_wcstof(wsValue.unterminated_c_str(), wsValue.GetLength(), nullptr)), bNotify); case XFA_AttributeType::Measure: return SetMeasure(eAttr, CXFA_Measurement(wsValue), bNotify); default: break; } return false; } void CJX_Object::SetMapModuleString(void* pKey, const WideStringView& wsValue) { SetMapModuleBuffer(pKey, (void*)wsValue.unterminated_c_str(), wsValue.GetLength() * sizeof(wchar_t), nullptr); } bool CJX_Object::SetAttribute(const WideStringView& wsAttr, const WideStringView& wsValue, bool bNotify) { XFA_Attribute attr = CXFA_Node::NameToAttribute(wsValue); if (attr != XFA_Attribute::Unknown) return SetAttribute(attr, wsValue, bNotify); void* pKey = GetMapKey_Custom(wsAttr); SetMapModuleString(pKey, wsValue); return true; } WideString CJX_Object::GetAttribute(const WideStringView& attr) { return TryAttribute(attr, true).value_or(WideString()); } WideString CJX_Object::GetAttribute(XFA_Attribute attr) { return TryAttribute(attr, true).value_or(WideString()); } pdfium::Optional CJX_Object::TryAttribute(XFA_Attribute eAttr, bool bUseDefault) { switch (ToNode(GetXFAObject())->GetAttributeType(eAttr)) { case XFA_AttributeType::Enum: { pdfium::Optional value = TryEnum(eAttr, bUseDefault); if (!value) return {}; return {CXFA_Node::AttributeEnumToName(*value)}; } case XFA_AttributeType::CData: return TryCData(eAttr, bUseDefault); case XFA_AttributeType::Boolean: { pdfium::Optional value = TryBoolean(eAttr, bUseDefault); if (!value) return {}; return {*value ? L"1" : L"0"}; } case XFA_AttributeType::Integer: { pdfium::Optional iValue = TryInteger(eAttr, bUseDefault); if (!iValue) return {}; return {WideString::Format(L"%d", *iValue)}; } case XFA_AttributeType::Measure: { pdfium::Optional value = TryMeasure(eAttr, bUseDefault); if (!value) return {}; return {value->ToString()}; } default: break; } return {}; } pdfium::Optional CJX_Object::TryAttribute( const WideStringView& wsAttr, bool bUseDefault) { XFA_Attribute attr = CXFA_Node::NameToAttribute(wsAttr); if (attr != XFA_Attribute::Unknown) return TryAttribute(attr, bUseDefault); void* pKey = GetMapKey_Custom(wsAttr); WideStringView wsValueC; if (!GetMapModuleString(pKey, wsValueC)) return {}; return {WideString(wsValueC)}; } void CJX_Object::RemoveAttribute(const WideStringView& wsAttr) { void* pKey = GetMapKey_Custom(wsAttr); if (pKey) RemoveMapModuleKey(pKey); } pdfium::Optional CJX_Object::TryBoolean(XFA_Attribute eAttr, bool bUseDefault) { void* pValue = nullptr; void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr); if (GetMapModuleValue(pKey, pValue)) return {!!pValue}; if (!bUseDefault) return {}; return ToNode(GetXFAObject())->GetDefaultBoolean(eAttr); } bool CJX_Object::SetBoolean(XFA_Attribute eAttr, bool bValue, bool bNotify) { CFX_XMLElement* elem = SetValue(eAttr, XFA_AttributeType::Boolean, (void*)(uintptr_t)bValue, bNotify); if (elem) elem->SetString(CXFA_Node::AttributeToName(eAttr), bValue ? L"1" : L"0"); return true; } bool CJX_Object::GetBoolean(XFA_Attribute eAttr) { return TryBoolean(eAttr, true).value_or(false); } bool CJX_Object::SetInteger(XFA_Attribute eAttr, int32_t iValue, bool bNotify) { CFX_XMLElement* elem = SetValue(eAttr, XFA_AttributeType::Integer, (void*)(uintptr_t)iValue, bNotify); if (elem) { elem->SetString(CXFA_Node::AttributeToName(eAttr), WideString::Format(L"%d", iValue)); } return true; } int32_t CJX_Object::GetInteger(XFA_Attribute eAttr) { return TryInteger(eAttr, true).value_or(0); } pdfium::Optional CJX_Object::TryInteger(XFA_Attribute eAttr, bool bUseDefault) { void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr); void* pValue = nullptr; if (GetMapModuleValue(pKey, pValue)) return {static_cast(reinterpret_cast(pValue))}; if (!bUseDefault) return {}; return ToNode(GetXFAObject())->GetDefaultInteger(eAttr); } pdfium::Optional CJX_Object::TryEnum(XFA_Attribute eAttr, bool bUseDefault) { void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr); void* pValue = nullptr; if (GetMapModuleValue(pKey, pValue)) { return { static_cast(reinterpret_cast(pValue))}; } if (!bUseDefault) return {}; return ToNode(GetXFAObject())->GetDefaultEnum(eAttr); } bool CJX_Object::SetEnum(XFA_Attribute eAttr, XFA_AttributeEnum eValue, bool bNotify) { CFX_XMLElement* elem = SetValue(eAttr, XFA_AttributeType::Enum, (void*)(uintptr_t)eValue, bNotify); if (elem) { elem->SetString(CXFA_Node::AttributeToName(eAttr), CXFA_Node::AttributeEnumToName(eValue)); } return true; } XFA_AttributeEnum CJX_Object::GetEnum(XFA_Attribute eAttr) { return TryEnum(eAttr, true).value_or(XFA_AttributeEnum::Unknown); } bool CJX_Object::SetMeasure(XFA_Attribute eAttr, CXFA_Measurement mValue, bool bNotify) { void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr); OnChanging(eAttr, bNotify); SetMapModuleBuffer(pKey, &mValue, sizeof(CXFA_Measurement), nullptr); OnChanged(eAttr, bNotify, false); return true; } pdfium::Optional CJX_Object::TryMeasure( XFA_Attribute eAttr, bool bUseDefault) const { void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr); void* pValue; int32_t iBytes; if (GetMapModuleBuffer(pKey, pValue, iBytes, true) && iBytes == sizeof(CXFA_Measurement)) { return {*reinterpret_cast(pValue)}; } if (!bUseDefault) return {}; return ToNode(GetXFAObject())->GetDefaultMeasurement(eAttr); } pdfium::Optional CJX_Object::TryMeasureAsFloat( XFA_Attribute attr) const { pdfium::Optional measure = TryMeasure(attr, false); if (measure) return {measure->ToUnit(XFA_Unit::Pt)}; return {}; } CXFA_Measurement CJX_Object::GetMeasure(XFA_Attribute eAttr) const { return TryMeasure(eAttr, true).value_or(CXFA_Measurement()); } WideString CJX_Object::GetCData(XFA_Attribute eAttr) { return TryCData(eAttr, true).value_or(WideString()); } bool CJX_Object::SetCData(XFA_Attribute eAttr, const WideString& wsValue, bool bNotify, bool bScriptModify) { void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr); OnChanging(eAttr, bNotify); if (eAttr == XFA_Attribute::Value) { WideString* pClone = new WideString(wsValue); SetUserData(pKey, pClone, &deleteWideStringCallBack); } else { SetMapModuleString(pKey, wsValue.AsStringView()); if (eAttr == XFA_Attribute::Name) ToNode(GetXFAObject())->UpdateNameHash(); } OnChanged(eAttr, bNotify, bScriptModify); if (!ToNode(GetXFAObject())->IsNeedSavingXMLNode() || eAttr == XFA_Attribute::QualifiedName || eAttr == XFA_Attribute::BindingNode) { return true; } if (eAttr == XFA_Attribute::Name && (GetXFAObject()->GetElementType() == XFA_Element::DataValue || GetXFAObject()->GetElementType() == XFA_Element::DataGroup)) { return true; } auto* elem = static_cast(ToNode(GetXFAObject())->GetXMLMappingNode()); if (eAttr == XFA_Attribute::Value) { FX_XMLNODETYPE eXMLType = elem->GetType(); switch (eXMLType) { case FX_XMLNODE_Element: if (ToNode(GetXFAObject())->IsAttributeInXML()) { elem->SetString(WideString(GetCData(XFA_Attribute::QualifiedName)), wsValue); } else { bool bDeleteChildren = true; if (ToNode(GetXFAObject())->GetPacketType() == XFA_PacketType::Datasets) { for (CXFA_Node* pChildDataNode = ToNode(GetXFAObject()) ->GetNodeItem(XFA_NODEITEM_FirstChild); pChildDataNode; pChildDataNode = pChildDataNode->GetNodeItem( XFA_NODEITEM_NextSibling)) { if (!pChildDataNode->GetBindItems()->empty()) { bDeleteChildren = false; break; } } } if (bDeleteChildren) elem->DeleteChildren(); elem->SetTextData(wsValue); } break; case FX_XMLNODE_Text: static_cast(ToNode(GetXFAObject())->GetXMLMappingNode()) ->SetText(wsValue); break; default: NOTREACHED(); } return true; } ASSERT(elem->GetType() == FX_XMLNODE_Element); WideString wsAttrName = CXFA_Node::AttributeToName(eAttr); if (eAttr == XFA_Attribute::ContentType) wsAttrName = L"xfa:" + wsAttrName; elem->SetString(wsAttrName, wsValue); return true; } void CJX_Object::SetAttributeValue(const WideString& wsValue, const WideString& wsXMLValue, bool bNotify, bool bScriptModify) { void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), XFA_Attribute::Value); OnChanging(XFA_Attribute::Value, bNotify); WideString* pClone = new WideString(wsValue); SetUserData(pKey, pClone, &deleteWideStringCallBack); OnChanged(XFA_Attribute::Value, bNotify, bScriptModify); if (!ToNode(GetXFAObject())->IsNeedSavingXMLNode()) return; auto* elem = static_cast(ToNode(GetXFAObject())->GetXMLMappingNode()); FX_XMLNODETYPE eXMLType = elem->GetType(); switch (eXMLType) { case FX_XMLNODE_Element: if (ToNode(GetXFAObject())->IsAttributeInXML()) { elem->SetString(WideString(GetCData(XFA_Attribute::QualifiedName)), wsXMLValue); } else { bool bDeleteChildren = true; if (ToNode(GetXFAObject())->GetPacketType() == XFA_PacketType::Datasets) { for (CXFA_Node* pChildDataNode = ToNode(GetXFAObject())->GetNodeItem(XFA_NODEITEM_FirstChild); pChildDataNode; pChildDataNode = pChildDataNode->GetNodeItem( XFA_NODEITEM_NextSibling)) { if (!pChildDataNode->GetBindItems()->empty()) { bDeleteChildren = false; break; } } } if (bDeleteChildren) elem->DeleteChildren(); elem->SetTextData(wsXMLValue); } break; case FX_XMLNODE_Text: static_cast(ToNode(GetXFAObject())->GetXMLMappingNode()) ->SetText(wsXMLValue); break; default: ASSERT(0); } } pdfium::Optional CJX_Object::TryCData(XFA_Attribute eAttr, bool bUseDefault) { void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr); if (eAttr == XFA_Attribute::Value) { void* pData; int32_t iBytes = 0; WideString* pStr = nullptr; if (GetMapModuleBuffer(pKey, pData, iBytes, true) && iBytes == sizeof(void*)) { memcpy(&pData, pData, iBytes); pStr = reinterpret_cast(pData); } if (pStr) return {*pStr}; } else { WideStringView wsValueC; if (GetMapModuleString(pKey, wsValueC)) return {WideString(wsValueC)}; } if (!bUseDefault) return {}; return ToNode(GetXFAObject())->GetDefaultCData(eAttr); } CFX_XMLElement* CJX_Object::SetValue(XFA_Attribute eAttr, XFA_AttributeType eType, void* pValue, bool bNotify) { void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr); OnChanging(eAttr, bNotify); SetMapModuleValue(pKey, pValue); OnChanged(eAttr, bNotify, false); if (!ToNode(GetXFAObject())->IsNeedSavingXMLNode()) return nullptr; auto* elem = static_cast(ToNode(GetXFAObject())->GetXMLMappingNode()); ASSERT(elem->GetType() == FX_XMLNODE_Element); return elem; } bool CJX_Object::SetContent(const WideString& wsContent, const WideString& wsXMLValue, bool bNotify, bool bScriptModify, bool bSyncData) { CXFA_Node* pNode = nullptr; CXFA_Node* pBindNode = nullptr; switch (ToNode(GetXFAObject())->GetObjectType()) { case XFA_ObjectType::ContainerNode: { if (XFA_FieldIsMultiListBox(ToNode(GetXFAObject()))) { CXFA_Value* pValue = GetProperty(0, XFA_Element::Value, true); if (!pValue) break; CXFA_Node* pChildValue = pValue->GetNodeItem(XFA_NODEITEM_FirstChild); ASSERT(pChildValue); pChildValue->JSObject()->SetCData(XFA_Attribute::ContentType, L"text/xml", false, false); pChildValue->JSObject()->SetContent(wsContent, wsContent, bNotify, bScriptModify, false); CXFA_Node* pBind = ToNode(GetXFAObject())->GetBindData(); if (bSyncData && pBind) { std::vector wsSaveTextArray; size_t iSize = 0; if (!wsContent.IsEmpty()) { size_t iStart = 0; size_t iLength = wsContent.GetLength(); auto iEnd = wsContent.Find(L'\n', iStart); iEnd = !iEnd.has_value() ? iLength : iEnd; while (iEnd.value() >= iStart) { wsSaveTextArray.push_back( wsContent.Mid(iStart, iEnd.value() - iStart)); iStart = iEnd.value() + 1; if (iStart >= iLength) break; iEnd = wsContent.Find(L'\n', iStart); if (!iEnd.has_value()) { wsSaveTextArray.push_back( wsContent.Mid(iStart, iLength - iStart)); } } iSize = wsSaveTextArray.size(); } if (iSize == 0) { while (CXFA_Node* pChildNode = pBind->GetNodeItem(XFA_NODEITEM_FirstChild)) { pBind->RemoveChild(pChildNode, true); } } else { std::vector valueNodes = pBind->GetNodeList( XFA_NODEFILTER_Children, XFA_Element::DataValue); size_t iDatas = valueNodes.size(); if (iDatas < iSize) { size_t iAddNodes = iSize - iDatas; CXFA_Node* pValueNodes = nullptr; while (iAddNodes-- > 0) { pValueNodes = pBind->CreateSamePacketNode(XFA_Element::DataValue); pValueNodes->JSObject()->SetCData(XFA_Attribute::Name, L"value", false, false); pValueNodes->CreateXMLMappingNode(); pBind->InsertChild(pValueNodes, nullptr); } pValueNodes = nullptr; } else if (iDatas > iSize) { size_t iDelNodes = iDatas - iSize; while (iDelNodes-- > 0) { pBind->RemoveChild(pBind->GetNodeItem(XFA_NODEITEM_FirstChild), true); } } int32_t i = 0; for (CXFA_Node* pValueNode = pBind->GetNodeItem(XFA_NODEITEM_FirstChild); pValueNode; pValueNode = pValueNode->GetNodeItem( XFA_NODEITEM_NextSibling)) { pValueNode->JSObject()->SetAttributeValue( wsSaveTextArray[i], wsSaveTextArray[i], false, false); i++; } } for (const auto& pArrayNode : *(pBind->GetBindItems())) { if (pArrayNode.Get() != ToNode(GetXFAObject())) { pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify, bScriptModify, false); } } } break; } if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::ExclGroup) { pNode = ToNode(GetXFAObject()); } else { CXFA_Value* pValue = GetProperty(0, XFA_Element::Value, true); if (!pValue) break; CXFA_Node* pChildValue = pValue->GetNodeItem(XFA_NODEITEM_FirstChild); ASSERT(pChildValue); pChildValue->JSObject()->SetContent(wsContent, wsContent, bNotify, bScriptModify, false); } pBindNode = ToNode(GetXFAObject())->GetBindData(); if (pBindNode && bSyncData) { pBindNode->JSObject()->SetContent(wsContent, wsXMLValue, bNotify, bScriptModify, false); for (const auto& pArrayNode : *(pBindNode->GetBindItems())) { if (pArrayNode.Get() != ToNode(GetXFAObject())) { pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify, true, false); } } } pBindNode = nullptr; break; } case XFA_ObjectType::ContentNode: { WideString wsContentType; if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::ExData) { pdfium::Optional ret = TryAttribute(XFA_Attribute::ContentType, false); if (ret) wsContentType = *ret; if (wsContentType == L"text/html") { wsContentType = L""; SetAttribute(XFA_Attribute::ContentType, wsContentType.AsStringView(), false); } } CXFA_Node* pContentRawDataNode = ToNode(GetXFAObject())->GetNodeItem(XFA_NODEITEM_FirstChild); if (!pContentRawDataNode) { pContentRawDataNode = ToNode(GetXFAObject()) ->CreateSamePacketNode((wsContentType == L"text/xml") ? XFA_Element::Sharpxml : XFA_Element::Sharptext); ToNode(GetXFAObject())->InsertChild(pContentRawDataNode, nullptr); } return pContentRawDataNode->JSObject()->SetContent( wsContent, wsXMLValue, bNotify, bScriptModify, bSyncData); } case XFA_ObjectType::NodeC: case XFA_ObjectType::TextNode: pNode = ToNode(GetXFAObject()); break; case XFA_ObjectType::NodeV: pNode = ToNode(GetXFAObject()); if (bSyncData && ToNode(GetXFAObject())->GetPacketType() == XFA_PacketType::Form) { CXFA_Node* pParent = ToNode(GetXFAObject())->GetNodeItem(XFA_NODEITEM_Parent); if (pParent) { pParent = pParent->GetNodeItem(XFA_NODEITEM_Parent); } if (pParent && pParent->GetElementType() == XFA_Element::Value) { pParent = pParent->GetNodeItem(XFA_NODEITEM_Parent); if (pParent && pParent->IsContainerNode()) { pBindNode = pParent->GetBindData(); if (pBindNode) { pBindNode->JSObject()->SetContent(wsContent, wsXMLValue, bNotify, bScriptModify, false); } } } } break; default: if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::DataValue) { pNode = ToNode(GetXFAObject()); pBindNode = ToNode(GetXFAObject()); } break; } if (!pNode) return false; SetAttributeValue(wsContent, wsXMLValue, bNotify, bScriptModify); if (pBindNode && bSyncData) { for (const auto& pArrayNode : *(pBindNode->GetBindItems())) { pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify, bScriptModify, false); } } return true; } WideString CJX_Object::GetContent(bool bScriptModify) { return TryContent(bScriptModify, true).value_or(WideString()); } pdfium::Optional CJX_Object::TryContent(bool bScriptModify, bool bProto) { CXFA_Node* pNode = nullptr; switch (ToNode(GetXFAObject())->GetObjectType()) { case XFA_ObjectType::ContainerNode: if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::ExclGroup) { pNode = ToNode(GetXFAObject()); } else { CXFA_Value* pValue = ToNode(GetXFAObject()) ->GetChild(0, XFA_Element::Value, false); if (!pValue) return {}; CXFA_Node* pChildValue = pValue->GetNodeItem(XFA_NODEITEM_FirstChild); if (pChildValue && XFA_FieldIsMultiListBox(ToNode(GetXFAObject()))) { pChildValue->JSObject()->SetAttribute(XFA_Attribute::ContentType, L"text/xml", false); } if (pChildValue) return pChildValue->JSObject()->TryContent(bScriptModify, bProto); return {}; } break; case XFA_ObjectType::ContentNode: { CXFA_Node* pContentRawDataNode = ToNode(GetXFAObject())->GetNodeItem(XFA_NODEITEM_FirstChild); if (!pContentRawDataNode) { XFA_Element element = XFA_Element::Sharptext; if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::ExData) { pdfium::Optional contentType = TryAttribute(XFA_Attribute::ContentType, false); if (contentType) { if (*contentType == L"text/html") element = XFA_Element::SharpxHTML; else if (*contentType == L"text/xml") element = XFA_Element::Sharpxml; } } pContentRawDataNode = ToNode(GetXFAObject())->CreateSamePacketNode(element); ToNode(GetXFAObject())->InsertChild(pContentRawDataNode, nullptr); } return pContentRawDataNode->JSObject()->TryContent(bScriptModify, true); } case XFA_ObjectType::NodeC: case XFA_ObjectType::NodeV: case XFA_ObjectType::TextNode: pNode = ToNode(GetXFAObject()); default: if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::DataValue) pNode = ToNode(GetXFAObject()); break; } if (pNode) { if (bScriptModify) { CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext(); if (pScriptContext) GetDocument()->GetScriptContext()->AddNodesOfRunScript( ToNode(GetXFAObject())); } return TryCData(XFA_Attribute::Value, false); } return {}; } pdfium::Optional CJX_Object::TryNamespace() { if (ToNode(GetXFAObject())->IsModelNode() || ToNode(GetXFAObject())->GetElementType() == XFA_Element::Packet) { CFX_XMLNode* pXMLNode = ToNode(GetXFAObject())->GetXMLMappingNode(); if (!pXMLNode || pXMLNode->GetType() != FX_XMLNODE_Element) return {}; return {static_cast(pXMLNode)->GetNamespaceURI()}; } if (ToNode(GetXFAObject())->GetPacketType() != XFA_PacketType::Datasets) return ToNode(GetXFAObject())->GetModelNode()->JSObject()->TryNamespace(); CFX_XMLNode* pXMLNode = ToNode(GetXFAObject())->GetXMLMappingNode(); if (!pXMLNode || pXMLNode->GetType() != FX_XMLNODE_Element) return {}; if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::DataValue && GetEnum(XFA_Attribute::Contains) == XFA_AttributeEnum::MetaData) { WideString wsNamespace; bool ret = XFA_FDEExtension_ResolveNamespaceQualifier( static_cast(pXMLNode), GetCData(XFA_Attribute::QualifiedName), &wsNamespace); if (!ret) return {}; return {wsNamespace}; } return {static_cast(pXMLNode)->GetNamespaceURI()}; } CXFA_Node* CJX_Object::GetPropertyInternal(int32_t index, XFA_Element eProperty, bool bCreateProperty) { if (index < 0 || index >= ToNode(GetXFAObject())->PropertyOccuranceCount(eProperty)) { return nullptr; } int32_t iCount = 0; for (CXFA_Node* pNode = ToNode(GetXFAObject())->GetChildNode(); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { if (pNode->GetElementType() == eProperty) { iCount++; if (iCount > index) return pNode; } } if (!bCreateProperty) return nullptr; if (ToNode(GetXFAObject()) ->HasPropertyFlags(eProperty, XFA_PROPERTYFLAG_OneOf)) { for (CXFA_Node* pNode = ToNode(GetXFAObject())->GetChildNode(); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { if (ToNode(GetXFAObject()) ->HasPropertyFlags(pNode->GetElementType(), XFA_PROPERTYFLAG_OneOf)) { return nullptr; } } } CXFA_Node* pNewNode = nullptr; for (; iCount <= index; ++iCount) { pNewNode = GetDocument()->CreateNode( ToNode(GetXFAObject())->GetPacketType(), eProperty); if (!pNewNode) return nullptr; ToNode(GetXFAObject())->InsertChild(pNewNode, nullptr); pNewNode->SetFlag(XFA_NodeFlag_Initialized, true); } return pNewNode; } bool CJX_Object::SetUserData(void* pKey, void* pData, XFA_MAPDATABLOCKCALLBACKINFO* pCallbackInfo) { SetMapModuleBuffer(pKey, &pData, sizeof(void*), pCallbackInfo ? pCallbackInfo : &gs_XFADefaultFreeData); return true; } XFA_MAPMODULEDATA* CJX_Object::CreateMapModuleData() { if (!map_module_data_) map_module_data_ = pdfium::MakeUnique(); return map_module_data_.get(); } XFA_MAPMODULEDATA* CJX_Object::GetMapModuleData() const { return map_module_data_.get(); } void CJX_Object::SetMapModuleValue(void* pKey, void* pValue) { CreateMapModuleData()->m_ValueMap[pKey] = pValue; } bool CJX_Object::GetMapModuleValue(void* pKey, void*& pValue) { for (CXFA_Node* pNode = ToNode(GetXFAObject()); pNode; pNode = pNode->GetTemplateNode()) { XFA_MAPMODULEDATA* pModule = pNode->JSObject()->GetMapModuleData(); if (pModule) { auto it = pModule->m_ValueMap.find(pKey); if (it != pModule->m_ValueMap.end()) { pValue = it->second; return true; } } if (pNode->GetPacketType() == XFA_PacketType::Datasets) break; } return false; } bool CJX_Object::GetMapModuleString(void* pKey, WideStringView& wsValue) { void* pValue; int32_t iBytes; if (!GetMapModuleBuffer(pKey, pValue, iBytes, true)) return false; // Defensive measure: no out-of-bounds pointers even if zero length. int32_t iChars = iBytes / sizeof(wchar_t); wsValue = WideStringView(iChars ? (const wchar_t*)pValue : nullptr, iChars); return true; } void CJX_Object::SetMapModuleBuffer( void* pKey, void* pValue, int32_t iBytes, XFA_MAPDATABLOCKCALLBACKINFO* pCallbackInfo) { XFA_MAPDATABLOCK*& pBuffer = CreateMapModuleData()->m_BufferMap[pKey]; if (!pBuffer) { pBuffer = reinterpret_cast( FX_Alloc(uint8_t, sizeof(XFA_MAPDATABLOCK) + iBytes)); } else if (pBuffer->iBytes != iBytes) { if (pBuffer->pCallbackInfo && pBuffer->pCallbackInfo->pFree) pBuffer->pCallbackInfo->pFree(*(void**)pBuffer->GetData()); pBuffer = reinterpret_cast( FX_Realloc(uint8_t, pBuffer, sizeof(XFA_MAPDATABLOCK) + iBytes)); } else if (pBuffer->pCallbackInfo && pBuffer->pCallbackInfo->pFree) { pBuffer->pCallbackInfo->pFree( *reinterpret_cast(pBuffer->GetData())); } if (!pBuffer) return; pBuffer->pCallbackInfo = pCallbackInfo; pBuffer->iBytes = iBytes; memcpy(pBuffer->GetData(), pValue, iBytes); } bool CJX_Object::GetMapModuleBuffer(void* pKey, void*& pValue, int32_t& iBytes, bool bProtoAlso) const { XFA_MAPDATABLOCK* pBuffer = nullptr; for (const CXFA_Node* pNode = ToNode(GetXFAObject()); pNode; pNode = pNode->GetTemplateNode()) { XFA_MAPMODULEDATA* pModule = pNode->JSObject()->GetMapModuleData(); if (pModule) { auto it = pModule->m_BufferMap.find(pKey); if (it != pModule->m_BufferMap.end()) { pBuffer = it->second; break; } } if (!bProtoAlso || pNode->GetPacketType() == XFA_PacketType::Datasets) break; } if (!pBuffer) return false; pValue = pBuffer->GetData(); iBytes = pBuffer->iBytes; return true; } bool CJX_Object::HasMapModuleKey(void* pKey) { XFA_MAPMODULEDATA* pModule = GetMapModuleData(); return pModule && (pdfium::ContainsKey(pModule->m_ValueMap, pKey) || pdfium::ContainsKey(pModule->m_BufferMap, pKey)); } void CJX_Object::ClearMapModuleBuffer() { XFA_MAPMODULEDATA* pModule = GetMapModuleData(); if (!pModule) return; for (auto& pair : pModule->m_BufferMap) { XFA_MAPDATABLOCK* pBuffer = pair.second; if (pBuffer) { if (pBuffer->pCallbackInfo && pBuffer->pCallbackInfo->pFree) pBuffer->pCallbackInfo->pFree(*(void**)pBuffer->GetData()); FX_Free(pBuffer); } } pModule->m_BufferMap.clear(); pModule->m_ValueMap.clear(); } void CJX_Object::RemoveMapModuleKey(void* pKey) { ASSERT(pKey); XFA_MAPMODULEDATA* pModule = GetMapModuleData(); if (!pModule) return; auto it = pModule->m_BufferMap.find(pKey); if (it != pModule->m_BufferMap.end()) { XFA_MAPDATABLOCK* pBuffer = it->second; if (pBuffer) { if (pBuffer->pCallbackInfo && pBuffer->pCallbackInfo->pFree) pBuffer->pCallbackInfo->pFree(*(void**)pBuffer->GetData()); FX_Free(pBuffer); } pModule->m_BufferMap.erase(it); } pModule->m_ValueMap.erase(pKey); return; } void CJX_Object::MergeAllData(CXFA_Object* pDstModule) { XFA_MAPMODULEDATA* pDstModuleData = ToNode(pDstModule)->JSObject()->CreateMapModuleData(); XFA_MAPMODULEDATA* pSrcModuleData = GetMapModuleData(); if (!pSrcModuleData) return; for (const auto& pair : pSrcModuleData->m_ValueMap) pDstModuleData->m_ValueMap[pair.first] = pair.second; for (const auto& pair : pSrcModuleData->m_BufferMap) { XFA_MAPDATABLOCK* pSrcBuffer = pair.second; XFA_MAPDATABLOCK*& pDstBuffer = pDstModuleData->m_BufferMap[pair.first]; if (pSrcBuffer->pCallbackInfo && pSrcBuffer->pCallbackInfo->pFree && !pSrcBuffer->pCallbackInfo->pCopy) { if (pDstBuffer) { pDstBuffer->pCallbackInfo->pFree(*(void**)pDstBuffer->GetData()); pDstModuleData->m_BufferMap.erase(pair.first); } continue; } if (!pDstBuffer) { pDstBuffer = (XFA_MAPDATABLOCK*)FX_Alloc( uint8_t, sizeof(XFA_MAPDATABLOCK) + pSrcBuffer->iBytes); } else if (pDstBuffer->iBytes != pSrcBuffer->iBytes) { if (pDstBuffer->pCallbackInfo && pDstBuffer->pCallbackInfo->pFree) { pDstBuffer->pCallbackInfo->pFree(*(void**)pDstBuffer->GetData()); } pDstBuffer = (XFA_MAPDATABLOCK*)FX_Realloc( uint8_t, pDstBuffer, sizeof(XFA_MAPDATABLOCK) + pSrcBuffer->iBytes); } else if (pDstBuffer->pCallbackInfo && pDstBuffer->pCallbackInfo->pFree) { pDstBuffer->pCallbackInfo->pFree(*(void**)pDstBuffer->GetData()); } if (!pDstBuffer) continue; pDstBuffer->pCallbackInfo = pSrcBuffer->pCallbackInfo; pDstBuffer->iBytes = pSrcBuffer->iBytes; memcpy(pDstBuffer->GetData(), pSrcBuffer->GetData(), pSrcBuffer->iBytes); if (pDstBuffer->pCallbackInfo && pDstBuffer->pCallbackInfo->pCopy) { pDstBuffer->pCallbackInfo->pCopy(*(void**)pDstBuffer->GetData()); } } } void CJX_Object::MoveBufferMapData(CXFA_Object* pDstModule) { if (!pDstModule) return; bool bNeedMove = true; if (pDstModule->GetElementType() != GetXFAObject()->GetElementType()) bNeedMove = false; if (bNeedMove) ToNode(pDstModule)->JSObject()->SetCalcData(ReleaseCalcData()); if (!pDstModule->IsNodeV()) return; WideString wsValue = ToNode(pDstModule)->JSObject()->GetContent(false); WideString wsFormatValue(wsValue); CXFA_WidgetData* pWidgetData = ToNode(pDstModule)->GetContainerWidgetData(); if (pWidgetData) wsFormatValue = pWidgetData->GetFormatDataValue(wsValue); ToNode(pDstModule) ->JSObject() ->SetContent(wsValue, wsFormatValue, true, true, true); } void CJX_Object::MoveBufferMapData(CXFA_Object* pSrcModule, CXFA_Object* pDstModule) { if (!pSrcModule || !pDstModule) return; CXFA_Node* pSrcChild = ToNode(pSrcModule)->GetNodeItem(XFA_NODEITEM_FirstChild); CXFA_Node* pDstChild = ToNode(pDstModule)->GetNodeItem(XFA_NODEITEM_FirstChild); while (pSrcChild && pDstChild) { MoveBufferMapData(pSrcChild, pDstChild); pSrcChild = pSrcChild->GetNodeItem(XFA_NODEITEM_NextSibling); pDstChild = pDstChild->GetNodeItem(XFA_NODEITEM_NextSibling); } ToNode(pSrcModule)->JSObject()->MoveBufferMapData(pDstModule); } void CJX_Object::OnChanging(XFA_Attribute eAttr, bool bNotify) { if (!bNotify || !ToNode(GetXFAObject())->IsInitialized()) return; CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); if (pNotify) pNotify->OnValueChanging(ToNode(GetXFAObject()), eAttr); } void CJX_Object::OnChanged(XFA_Attribute eAttr, bool bNotify, bool bScriptModify) { if (bNotify && ToNode(GetXFAObject())->IsInitialized()) ToNode(GetXFAObject())->SendAttributeChangeMessage(eAttr, bScriptModify); } void CJX_Object::SetCalcData(std::unique_ptr data) { calc_data_ = std::move(data); } std::unique_ptr CJX_Object::ReleaseCalcData() { return std::move(calc_data_); } void CJX_Object::Script_Attribute_String(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (!bSetting) { pValue->SetString(GetAttribute(eAttribute).UTF8Encode().AsStringView()); return; } WideString wsValue = pValue->ToWideString(); SetAttribute(eAttribute, wsValue.AsStringView(), true); if (eAttribute != XFA_Attribute::Use || GetXFAObject()->GetElementType() != XFA_Element::Desc) { return; } CXFA_Node* pTemplateNode = ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Template)); CXFA_Proto* pProtoRoot = pTemplateNode->GetFirstChildByClass(XFA_Element::Subform) ->GetFirstChildByClass(XFA_Element::Proto); WideString wsID; WideString wsSOM; if (!wsValue.IsEmpty()) { if (wsValue[0] == '#') wsID = WideString(wsValue.c_str() + 1, wsValue.GetLength() - 1); else wsSOM = wsValue; } CXFA_Node* pProtoNode = nullptr; if (!wsSOM.IsEmpty()) { XFA_RESOLVENODE_RS resolveNodeRS; bool iRet = GetDocument()->GetScriptContext()->ResolveObjects( pProtoRoot, wsSOM.AsStringView(), &resolveNodeRS, XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes | XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings, nullptr); if (iRet && resolveNodeRS.objects.front()->IsNode()) pProtoNode = resolveNodeRS.objects.front()->AsNode(); } else if (!wsID.IsEmpty()) { pProtoNode = GetDocument()->GetNodeByID(pProtoRoot, wsID.AsStringView()); } if (!pProtoNode) return; CXFA_Node* pHeadChild = ToNode(GetXFAObject())->GetNodeItem(XFA_NODEITEM_FirstChild); while (pHeadChild) { CXFA_Node* pSibling = pHeadChild->GetNodeItem(XFA_NODEITEM_NextSibling); ToNode(GetXFAObject())->RemoveChild(pHeadChild, true); pHeadChild = pSibling; } std::unique_ptr pProtoForm(pProtoNode->CloneTemplateToForm(true)); pHeadChild = pProtoForm->GetNodeItem(XFA_NODEITEM_FirstChild); while (pHeadChild) { CXFA_Node* pSibling = pHeadChild->GetNodeItem(XFA_NODEITEM_NextSibling); pProtoForm->RemoveChild(pHeadChild, true); ToNode(GetXFAObject())->InsertChild(pHeadChild, nullptr); pHeadChild = pSibling; } GetDocument()->RemovePurgeNode(pProtoForm.get()); } void CJX_Object::Script_Attribute_BOOL(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (bSetting) { SetBoolean(eAttribute, pValue->ToBoolean(), true); return; } pValue->SetString(GetBoolean(eAttribute) ? "1" : "0"); } void CJX_Object::Script_Attribute_Integer(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (bSetting) { SetInteger(eAttribute, pValue->ToInteger(), true); return; } pValue->SetInteger(GetInteger(eAttribute)); } void CJX_Object::Script_Som_FontColor(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (!widget_data_) return; CXFA_FontData fontData = widget_data_->GetFontData(true); CXFA_Node* pNode = fontData.GetNode(); if (!pNode) return; if (bSetting) { int32_t r; int32_t g; int32_t b; std::tie(r, g, b) = StrToRGB(pValue->ToWideString()); FX_ARGB color = ArgbEncode(0xff, r, g, b); fontData.SetColor(color); return; } int32_t a; int32_t r; int32_t g; int32_t b; std::tie(a, r, g, b) = ArgbDecode(fontData.GetColor()); pValue->SetString(ByteString::Format("%d,%d,%d", r, g, b).AsStringView()); } void CJX_Object::Script_Som_FillColor(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (!widget_data_) return; CXFA_Border* border = widget_data_->GetBorder(true); CXFA_Fill* borderfill = border->GetFill(true); if (!borderfill) return; if (bSetting) { int32_t r; int32_t g; int32_t b; std::tie(r, g, b) = StrToRGB(pValue->ToWideString()); FX_ARGB color = ArgbEncode(0xff, r, g, b); borderfill->SetColor(color); return; } FX_ARGB color = borderfill->GetColor(false); int32_t a; int32_t r; int32_t g; int32_t b; std::tie(a, r, g, b) = ArgbDecode(color); pValue->SetString( WideString::Format(L"%d,%d,%d", r, g, b).UTF8Encode().AsStringView()); } void CJX_Object::Script_Som_BorderColor(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (!widget_data_) return; CXFA_Border* border = widget_data_->GetBorder(true); int32_t iSize = border->CountEdges(); if (bSetting) { int32_t r = 0; int32_t g = 0; int32_t b = 0; std::tie(r, g, b) = StrToRGB(pValue->ToWideString()); FX_ARGB rgb = ArgbEncode(100, r, g, b); for (int32_t i = 0; i < iSize; ++i) border->GetEdge(i)->SetColor(rgb); return; } FX_ARGB color = border->GetEdge(0)->GetColor(); int32_t a; int32_t r; int32_t g; int32_t b; std::tie(a, r, g, b) = ArgbDecode(color); pValue->SetString( WideString::Format(L"%d,%d,%d", r, g, b).UTF8Encode().AsStringView()); } void CJX_Object::Script_Som_BorderWidth(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (!widget_data_) return; CXFA_Border* border = widget_data_->GetBorder(true); if (bSetting) { CXFA_Measurement thickness = border->GetEdge(0)->GetMSThickness(); pValue->SetString(thickness.ToString().UTF8Encode().AsStringView()); return; } WideString wsThickness = pValue->ToWideString(); for (int32_t i = 0; i < border->CountEdges(); ++i) { border->GetEdge(i)->SetMSThickness( CXFA_Measurement(wsThickness.AsStringView())); } } void CJX_Object::Script_Som_Message(CFXJSE_Value* pValue, bool bSetting, XFA_SOM_MESSAGETYPE iMessageType) { if (!widget_data_) return; bool bNew = false; CXFA_Validate* validate = widget_data_->GetValidate(false); if (!validate) { validate = widget_data_->GetValidate(true); bNew = true; } if (bSetting) { switch (iMessageType) { case XFA_SOM_ValidationMessage: validate->SetScriptMessageText(pValue->ToWideString()); break; case XFA_SOM_FormatMessage: validate->SetFormatMessageText(pValue->ToWideString()); break; case XFA_SOM_MandatoryMessage: validate->SetNullMessageText(pValue->ToWideString()); break; default: break; } if (!bNew) { CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); if (!pNotify) return; pNotify->AddCalcValidate(ToNode(GetXFAObject())); } return; } WideString wsMessage; switch (iMessageType) { case XFA_SOM_ValidationMessage: wsMessage = validate->GetScriptMessageText(); break; case XFA_SOM_FormatMessage: wsMessage = validate->GetFormatMessageText(); break; case XFA_SOM_MandatoryMessage: wsMessage = validate->GetNullMessageText(); break; default: break; } pValue->SetString(wsMessage.UTF8Encode().AsStringView()); } void CJX_Object::Script_Som_ValidationMessage(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { Script_Som_Message(pValue, bSetting, XFA_SOM_ValidationMessage); } void CJX_Object::Script_Som_MandatoryMessage(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { Script_Som_Message(pValue, bSetting, XFA_SOM_MandatoryMessage); } void CJX_Object::Script_Field_Length(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (bSetting) { ThrowInvalidPropertyException(); return; } if (!widget_data_) { pValue->SetInteger(0); return; } pValue->SetInteger(widget_data_->CountChoiceListItems(true)); } void CJX_Object::Script_Som_DefaultValue(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute /* unused */) { XFA_Element eType = ToNode(GetXFAObject())->GetElementType(); // TODO(dsinclair): This should look through the properties on the node to see // if defaultValue is defined and, if so, call that one. Just have to make // sure that those defaultValue calls don't call back to this one .... if (eType == XFA_Element::Field) { static_cast(this)->defaultValue(pValue, bSetting, XFA_Attribute::Unknown); return; } if (eType == XFA_Element::Draw) { static_cast(this)->defaultValue(pValue, bSetting, XFA_Attribute::Unknown); return; } if (eType == XFA_Element::Boolean) { static_cast(this)->defaultValue(pValue, bSetting, XFA_Attribute::Unknown); return; } if (bSetting) { WideString wsNewValue; if (pValue && !(pValue->IsNull() || pValue->IsUndefined())) wsNewValue = pValue->ToWideString(); WideString wsFormatValue(wsNewValue); CXFA_WidgetData* pContainerWidgetData = nullptr; if (ToNode(GetXFAObject())->GetPacketType() == XFA_PacketType::Datasets) { WideString wsPicture; for (const auto& pFormNode : *(ToNode(GetXFAObject())->GetBindItems())) { if (!pFormNode || pFormNode->HasRemovedChildren()) continue; pContainerWidgetData = pFormNode->GetContainerWidgetData(); if (pContainerWidgetData) { wsPicture = pContainerWidgetData->GetPictureContent( XFA_VALUEPICTURE_DataBind); } if (!wsPicture.IsEmpty()) break; pContainerWidgetData = nullptr; } } else if (ToNode(GetXFAObject())->GetPacketType() == XFA_PacketType::Form) { pContainerWidgetData = ToNode(GetXFAObject())->GetContainerWidgetData(); } if (pContainerWidgetData) wsFormatValue = pContainerWidgetData->GetFormatDataValue(wsNewValue); SetContent(wsNewValue, wsFormatValue, true, true, true); return; } WideString content = GetContent(true); if (content.IsEmpty() && eType != XFA_Element::Text && eType != XFA_Element::SubmitUrl) { pValue->SetNull(); } else if (eType == XFA_Element::Integer) { pValue->SetInteger(FXSYS_wtoi(content.c_str())); } else if (eType == XFA_Element::Float || eType == XFA_Element::Decimal) { CFX_Decimal decimal(content.AsStringView()); pValue->SetFloat((float)(double)decimal); } else { pValue->SetString(content.UTF8Encode().AsStringView()); } } void CJX_Object::Script_Som_DefaultValue_Read(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (bSetting) { ThrowInvalidPropertyException(); return; } WideString content = GetContent(true); if (content.IsEmpty()) { pValue->SetNull(); return; } pValue->SetString(content.UTF8Encode().AsStringView()); } void CJX_Object::Script_Som_DataNode(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (bSetting) { ThrowInvalidPropertyException(); return; } CXFA_Node* pDataNode = ToNode(GetXFAObject())->GetBindData(); if (!pDataNode) { pValue->SetNull(); return; } pValue->Assign( GetDocument()->GetScriptContext()->GetJSValueFromMap(pDataNode)); } void CJX_Object::Script_Som_Mandatory(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (!widget_data_) return; CXFA_Validate* validate = widget_data_->GetValidate(true); if (!validate) return; if (bSetting) { validate->SetNullTest(pValue->ToWideString()); return; } WideString str = CXFA_Node::AttributeEnumToName(validate->GetNullTest()); pValue->SetString(str.UTF8Encode().AsStringView()); } void CJX_Object::Script_Som_InstanceIndex(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (!bSetting) { pValue->SetInteger(Subform_and_SubformSet_InstanceIndex()); return; } int32_t iTo = pValue->ToInteger(); int32_t iFrom = Subform_and_SubformSet_InstanceIndex(); CXFA_Node* pManagerNode = nullptr; for (CXFA_Node* pNode = ToNode(GetXFAObject())->GetNodeItem(XFA_NODEITEM_PrevSibling); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_PrevSibling)) { if (pNode->GetElementType() == XFA_Element::InstanceManager) { pManagerNode = pNode; break; } } if (!pManagerNode) return; auto* mgr = static_cast(pManagerNode->JSObject()); mgr->MoveInstance(iTo, iFrom); CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); if (!pNotify) return; CXFA_Node* pToInstance = pManagerNode->GetItem(iTo); if (pToInstance && pToInstance->GetElementType() == XFA_Element::Subform) { pNotify->RunSubformIndexChange(pToInstance); } CXFA_Node* pFromInstance = pManagerNode->GetItem(iFrom); if (pFromInstance && pFromInstance->GetElementType() == XFA_Element::Subform) { pNotify->RunSubformIndexChange(pFromInstance); } } void CJX_Object::Script_Subform_InstanceManager(CFXJSE_Value* pValue, bool bSetting, XFA_AttributeEnum eAttribute) { if (bSetting) { ThrowInvalidPropertyException(); return; } WideString wsName = GetCData(XFA_Attribute::Name); CXFA_Node* pInstanceMgr = nullptr; for (CXFA_Node* pNode = ToNode(GetXFAObject())->GetNodeItem(XFA_NODEITEM_PrevSibling); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_PrevSibling)) { if (pNode->GetElementType() == XFA_Element::InstanceManager) { WideString wsInstMgrName = pNode->JSObject()->GetCData(XFA_Attribute::Name); if (wsInstMgrName.GetLength() >= 1 && wsInstMgrName[0] == '_' && wsInstMgrName.Right(wsInstMgrName.GetLength() - 1) == wsName) { pInstanceMgr = pNode; } break; } } if (!pInstanceMgr) { pValue->SetNull(); return; } pValue->Assign( GetDocument()->GetScriptContext()->GetJSValueFromMap(pInstanceMgr)); } void CJX_Object::Script_SubmitFormat_Mode(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) {} void CJX_Object::Script_Form_Checksum(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (bSetting) { SetAttribute(XFA_Attribute::Checksum, pValue->ToWideString().AsStringView(), false); return; } pdfium::Optional checksum = TryAttribute(XFA_Attribute::Checksum, false); pValue->SetString(checksum ? checksum->UTF8Encode().AsStringView() : ""); } void CJX_Object::Script_ExclGroup_ErrorText(CFXJSE_Value* pValue, bool bSetting, XFA_Attribute eAttribute) { if (bSetting) ThrowInvalidPropertyException(); }