| // Copyright 2016 The PDFium Authors | |
| // 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 "xfa/fxfa/parser/xfa_basic_data.h" | |
| #include <functional> | |
| #include <iterator> | |
| #include <utility> | |
| #include "core/fxcrt/span.h" | |
| #include "fxjs/xfa/cjx_boolean.h" | |
| #include "fxjs/xfa/cjx_container.h" | |
| #include "fxjs/xfa/cjx_datawindow.h" | |
| #include "fxjs/xfa/cjx_delta.h" | |
| #include "fxjs/xfa/cjx_desc.h" | |
| #include "fxjs/xfa/cjx_draw.h" | |
| #include "fxjs/xfa/cjx_encrypt.h" | |
| #include "fxjs/xfa/cjx_eventpseudomodel.h" | |
| #include "fxjs/xfa/cjx_exclgroup.h" | |
| #include "fxjs/xfa/cjx_extras.h" | |
| #include "fxjs/xfa/cjx_field.h" | |
| #include "fxjs/xfa/cjx_form.h" | |
| #include "fxjs/xfa/cjx_handler.h" | |
| #include "fxjs/xfa/cjx_hostpseudomodel.h" | |
| #include "fxjs/xfa/cjx_instancemanager.h" | |
| #include "fxjs/xfa/cjx_layoutpseudomodel.h" | |
| #include "fxjs/xfa/cjx_logpseudomodel.h" | |
| #include "fxjs/xfa/cjx_manifest.h" | |
| #include "fxjs/xfa/cjx_model.h" | |
| #include "fxjs/xfa/cjx_node.h" | |
| #include "fxjs/xfa/cjx_occur.h" | |
| #include "fxjs/xfa/cjx_packet.h" | |
| #include "fxjs/xfa/cjx_script.h" | |
| #include "fxjs/xfa/cjx_signaturepseudomodel.h" | |
| #include "fxjs/xfa/cjx_source.h" | |
| #include "fxjs/xfa/cjx_subform.h" | |
| #include "fxjs/xfa/cjx_textnode.h" | |
| #include "fxjs/xfa/cjx_tree.h" | |
| #include "fxjs/xfa/cjx_treelist.h" | |
| #include "fxjs/xfa/cjx_wsdlconnection.h" | |
| #include "fxjs/xfa/cjx_xfa.h" | |
| #include "xfa/fxfa/fxfa_basic.h" | |
| namespace { | |
| struct PacketTableRecord { | |
| uint32_t hash; | |
| XFA_PACKETINFO info; | |
| }; | |
| const PacketTableRecord kPacketTable[] = { | |
| #undef PCKT____ | |
| #define PCKT____(a, b, c, d, e, f) \ | |
| {a, {XFA_PacketType::c, XFA_PacketMatch::e, XFA_PacketSupport::f, b, d}}, | |
| #include "xfa/fxfa/parser/packets.inc" | |
| #undef PCKT____ | |
| }; | |
| constexpr pdfium::span<const PacketTableRecord> kPacketSpan{kPacketTable}; | |
| struct ElementRecord { | |
| uint32_t hash; // Hashed as wide string. | |
| XFA_Element element; | |
| XFA_Element parent; | |
| }; | |
| // Contains read-only data that do not require relocation. | |
| // Parts that require relocation are in `kElementNames` below. | |
| constexpr ElementRecord kElementRecords[] = { | |
| #undef ELEM____ | |
| #define ELEM____(a, b, c, d) {a, XFA_Element::c, XFA_Element::d}, | |
| #include "xfa/fxfa/parser/elements.inc" | |
| #undef ELEM____ | |
| }; | |
| constexpr pdfium::span<const ElementRecord> kElementRecordSpan{kElementRecords}; | |
| constexpr const char* kElementNames[] = { | |
| #undef ELEM____ | |
| #define ELEM____(a, b, c, d) b, | |
| #include "xfa/fxfa/parser/elements.inc" | |
| #undef ELEM____ | |
| }; | |
| constexpr const pdfium::span<const char* const> kElementNameSpan{kElementNames}; | |
| static_assert(std::size(kElementRecords) == std::size(kElementNames), | |
| "Size mismatch"); | |
| struct AttributeRecord { | |
| uint32_t hash; // Hashed as wide string. | |
| XFA_Attribute attribute; | |
| XFA_ScriptType script_type; | |
| }; | |
| // Contains read-only data that do not require relocation. | |
| // Parts that require relocation are in `kAttributeNames` below. | |
| constexpr AttributeRecord kAttributeRecords[] = { | |
| #undef ATTR____ | |
| #define ATTR____(a, b, c, d) {a, XFA_Attribute::c, XFA_ScriptType::d}, | |
| #include "xfa/fxfa/parser/attributes.inc" | |
| #undef ATTR____ | |
| }; | |
| constexpr pdfium::span<const AttributeRecord> kAttributeRecordSpan{ | |
| kAttributeRecords}; | |
| constexpr const char* kAttributeNames[] = { | |
| #undef ATTR____ | |
| #define ATTR____(a, b, c, d) b, | |
| #include "xfa/fxfa/parser/attributes.inc" | |
| #undef ATTR____ | |
| }; | |
| constexpr pdfium::span<const char* const> kAttributeNameSpan{kAttributeNames}; | |
| static_assert(std::size(kAttributeRecords) == std::size(kAttributeNames), | |
| "Size mismatch"); | |
| struct AttributeValueRecord { | |
| // Associated entry in `kAttributeValueNames` hashed as WideString. | |
| uint32_t uHash; | |
| XFA_AttributeValue eName; | |
| }; | |
| // Contains read-only data that do not require relocation. | |
| // Parts that require relocation are in `kAttributeValueNames` below. | |
| constexpr AttributeValueRecord kAttributeValueRecords[] = { | |
| #undef VALUE____ | |
| #define VALUE____(a, b, c) {a, XFA_AttributeValue::c}, | |
| #include "xfa/fxfa/parser/attribute_values.inc" | |
| #undef VALUE____ | |
| }; | |
| constexpr const char* kAttributeValueNames[] = { | |
| #undef VALUE____ | |
| #define VALUE____(a, b, c) b, | |
| #include "xfa/fxfa/parser/attribute_values.inc" | |
| #undef VALUE____ | |
| }; | |
| constexpr pdfium::span<const char* const> kAttributeValueNameSpan{ | |
| kAttributeValueNames}; | |
| static_assert(std::size(kAttributeValueRecords) == | |
| std::size(kAttributeValueNames), | |
| "Size mismatch"); | |
| struct ElementAttributeRecord { | |
| XFA_Element element; | |
| XFA_Attribute attribute; | |
| }; | |
| // Contains read-only data that do not require relocation. | |
| // Parts that require relocation are in `kElementAttributeCallbacks` below. | |
| constexpr ElementAttributeRecord kElementAttributeRecords[] = { | |
| #undef ELEM_ATTR____ | |
| #define ELEM_ATTR____(a, b, c) {XFA_Element::a, XFA_Attribute::b}, | |
| #include "xfa/fxfa/parser/element_attributes.inc" | |
| #undef ELEM_ATTR____ | |
| }; | |
| constexpr XFA_ATTRIBUTE_CALLBACK kElementAttributeCallbacks[] = { | |
| #undef ELEM_ATTR____ | |
| #define ELEM_ATTR____(a, b, c) c##_static, | |
| #include "xfa/fxfa/parser/element_attributes.inc" | |
| #undef ELEM_ATTR____ | |
| }; | |
| constexpr pdfium::span<const XFA_ATTRIBUTE_CALLBACK> | |
| kElementAttributeCallbackSpan{kElementAttributeCallbacks}; | |
| static_assert(std::size(kElementAttributeRecords) == | |
| std::size(kElementAttributeCallbacks), | |
| "Size mismatch"); | |
| } // namespace | |
| XFA_PACKETINFO XFA_GetPacketByIndex(XFA_PacketType ePacket) { | |
| return kPacketSpan[static_cast<uint8_t>(ePacket)].info; | |
| } | |
| std::optional<XFA_PACKETINFO> XFA_GetPacketByName(WideStringView wsName) { | |
| uint32_t hash = FX_HashCode_GetW(wsName); | |
| auto* elem = std::ranges::lower_bound(kPacketTable, hash, std::less<>{}, | |
| &PacketTableRecord::hash); | |
| if (elem != std::end(kPacketTable) && wsName.EqualsASCII(elem->info.name)) { | |
| return elem->info; | |
| } | |
| return std::nullopt; | |
| } | |
| ByteStringView XFA_ElementToName(XFA_Element elem) { | |
| return kElementNameSpan[static_cast<size_t>(elem)]; | |
| } | |
| XFA_Element XFA_GetElementByName(WideStringView name) { | |
| uint32_t hash = FX_HashCode_GetW(name); | |
| auto* elem = std::ranges::lower_bound(kElementRecords, hash, std::less<>{}, | |
| &ElementRecord::hash); | |
| if (elem == std::end(kElementRecords)) { | |
| return XFA_Element::Unknown; | |
| } | |
| size_t index = std::distance(std::begin(kElementRecords), elem); | |
| return name.EqualsASCII(kElementNameSpan[index]) ? elem->element | |
| : XFA_Element::Unknown; | |
| } | |
| ByteStringView XFA_AttributeToName(XFA_Attribute attr) { | |
| return kAttributeNameSpan[static_cast<size_t>(attr)]; | |
| } | |
| std::optional<XFA_ATTRIBUTEINFO> XFA_GetAttributeByName(WideStringView name) { | |
| uint32_t hash = FX_HashCode_GetW(name); | |
| auto* elem = std::lower_bound( | |
| kAttributeRecordSpan.begin(), kAttributeRecordSpan.end(), hash, | |
| [](const AttributeRecord& a, uint32_t hash) { return a.hash < hash; }); | |
| if (elem == kAttributeRecordSpan.end()) { | |
| return std::nullopt; | |
| } | |
| size_t index = std::distance(kAttributeRecordSpan.begin(), elem); | |
| if (!name.EqualsASCII(kAttributeNameSpan[index])) { | |
| return std::nullopt; | |
| } | |
| XFA_ATTRIBUTEINFO result; | |
| result.attribute = elem->attribute; | |
| result.eValueType = elem->script_type; | |
| return result; | |
| } | |
| ByteStringView XFA_AttributeValueToName(XFA_AttributeValue item) { | |
| return kAttributeValueNameSpan[static_cast<int32_t>(item)]; | |
| } | |
| std::optional<XFA_AttributeValue> XFA_GetAttributeValueByName( | |
| WideStringView name) { | |
| auto* it = | |
| std::ranges::lower_bound(kAttributeValueRecords, FX_HashCode_GetW(name), | |
| std::less<>{}, &AttributeValueRecord::uHash); | |
| if (it == std::end(kAttributeValueRecords)) { | |
| return std::nullopt; | |
| } | |
| size_t index = std::distance(std::begin(kAttributeValueRecords), it); | |
| if (!name.EqualsASCII(kAttributeValueNameSpan[index])) { | |
| return std::nullopt; | |
| } | |
| return it->eName; | |
| } | |
| std::optional<XFA_SCRIPTATTRIBUTEINFO> XFA_GetScriptAttributeByName( | |
| XFA_Element element, | |
| WideStringView attribute_name) { | |
| std::optional<XFA_ATTRIBUTEINFO> attr = | |
| XFA_GetAttributeByName(attribute_name); | |
| if (!attr.has_value()) { | |
| return std::nullopt; | |
| } | |
| while (element != XFA_Element::Unknown) { | |
| auto compound_key = std::make_pair(element, attr.value().attribute); | |
| auto* it = std::lower_bound( | |
| std::begin(kElementAttributeRecords), | |
| std::end(kElementAttributeRecords), compound_key, | |
| [](const ElementAttributeRecord& arg, | |
| const std::pair<XFA_Element, XFA_Attribute>& key) { | |
| return std::make_pair(arg.element, arg.attribute) < key; | |
| }); | |
| if (it != std::end(kElementAttributeRecords) && | |
| compound_key == std::make_pair(it->element, it->attribute)) { | |
| XFA_SCRIPTATTRIBUTEINFO result; | |
| result.attribute = attr.value().attribute; | |
| result.eValueType = attr.value().eValueType; | |
| size_t index = std::distance(std::begin(kElementAttributeRecords), it); | |
| result.callback = kElementAttributeCallbackSpan[index]; | |
| return result; | |
| } | |
| element = kElementRecordSpan[static_cast<size_t>(element)].parent; | |
| } | |
| return std::nullopt; | |
| } |