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