4#include "Stroika/Foundation/StroikaPreComp.h"
8#include <xercesc/validators/schema/identity/XPathException.hpp>
11#include "Stroika/Foundation/DataExchange/BadFormatException.h"
15#include "Stroika/Foundation/Execution/Exceptions.h"
16#include "Stroika/Foundation/Execution/Throw.h"
19#include "Stroika/Foundation/Memory/Common.h"
29using namespace Stroika::Foundation::DataExchange::XML;
30using namespace Stroika::Foundation::DataExchange::XML::DOM;
31using namespace Stroika::Foundation::DataExchange::XML::Schema;
32using namespace Stroika::Foundation::DataExchange::XML::Providers::Xerces;
33using namespace Stroika::Foundation::Debug;
35using namespace Stroika::Foundation::Streams;
37XERCES_CPP_NAMESPACE_USE;
44static_assert (qStroika_HasComponent_xerces,
"Don't compile this file if qStroika_HasComponent_xerces not set");
55 constexpr auto kUseURIEncodingFlag_ = URI::StringPCTEncodedFlag::eDecoded;
60#define START_LIB_EXCEPTION_MAPPER_ try {
61#define END_LIB_EXCEPTION_MAPPER_ \
63 catch (const xercesc::OutOfMemoryException&) \
65 Execution::Throw (bad_alloc{}, "xerces OutOfMemoryException - throwing bad_alloc"); \
69 Execution::ReThrow (); \
72#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
78struct Provider::MyXercesMemMgr_ :
public MemoryManager {
81 : fAllocator{fBaseAllocator}
86#if qStroika_Foundation_Debug_AssertionsChecked
87 auto snapshot = fAllocator.GetSnapshot ();
88 Assert (snapshot.fAllocations.empty ());
95 mutex fLastSnapshot_CritSection;
96 Memory::LeakTrackingGeneralPurposeAllocator::Snapshot fLastSnapshot;
99 void DUMPCurMemStats ()
102 [[maybe_unused]] lock_guard critSec{fLastSnapshot_CritSection};
103 fAllocator.DUMPCurMemStats (fLastSnapshot);
105 fLastSnapshot = fAllocator.GetSnapshot ();
109 virtual MemoryManager* getExceptionMemoryManager ()
override
113 virtual void* allocate (XMLSize_t size)
override
116 return fAllocator.Allocate (size);
120 throw (OutOfMemoryException{});
123 virtual void deallocate (
void* p)
override
126 return fAllocator.Deallocate (p);
133 struct MySchemaResolver_ :
public XMLEntityResolver {
139 : fResolver_{resolver}
142 virtual InputSource* resolveEntity (XMLResourceIdentifier* resourceIdentifier)
override
148 if (fResolver_ !=
nullptr) {
149 if (
auto o = fResolver_.Lookup (
Resource::Name{.fNamespace = xercesString2String (resourceIdentifier->getNameSpace ()),
150 .fPublicID = xercesString2String (resourceIdentifier->getPublicId ()),
151 .fSystemID = xercesString2String (resourceIdentifier->getSystemId ())})) {
152 return mkMemInputSrc_ (o->fData);
159 static InputSource* mkMemInputSrc_ (
const Memory::BLOB& schemaData)
161 if (schemaData.
empty ()) [[unlikely]] {
163 return new MemBufInputSource{
nullptr, 0,
"",
true};
166 XMLByte* useBuf =
new XMLByte[schemaData.
GetSize ()];
167 memcpy (useBuf, schemaData.
begin (), schemaData.
GetSize ());
168 return new MemBufInputSource{useBuf, schemaData.
GetSize (),
"",
true};
175 void SetupCommonParserFeatures_ (SAX2XMLReader& reader)
177 reader.setFeature (XMLUni::fgSAX2CoreNameSpaces,
true);
178 reader.setFeature (XMLUni::fgXercesDynamic,
false);
179 reader.setFeature (XMLUni::fgSAX2CoreNameSpacePrefixes,
false);
181 void SetupCommonParserFeatures_ (SAX2XMLReader& reader,
bool validatingWithSchema)
183 reader.setFeature (XMLUni::fgXercesSchema, validatingWithSchema);
184 reader.setFeature (XMLUni::fgSAX2CoreValidation, validatingWithSchema);
190 reader.setFeature (XMLUni::fgXercesSchemaFullChecking, validatingWithSchema);
191 reader.setFeature (XMLUni::fgXercesUseCachedGrammarInParse, validatingWithSchema);
192 reader.setFeature (XMLUni::fgXercesIdentityConstraintChecking, validatingWithSchema);
196 reader.setFeature (XMLUni::fgXercesCacheGrammarFromParse,
false);
201 struct Map2StroikaExceptionsErrorReporter_ :
public XMLErrorReporter,
public ErrorHandler {
203 virtual void error ([[maybe_unused]]
const unsigned int errCode, [[maybe_unused]]
const XMLCh*
const errDomain,
204 [[maybe_unused]]
const ErrTypes type,
const XMLCh*
const errorText, [[maybe_unused]]
const XMLCh*
const systemId,
205 [[maybe_unused]]
const XMLCh*
const publicId,
const XMLFileLoc lineNum,
const XMLFileLoc colNum)
override
209 virtual void resetErrors ()
override
212 virtual void warning ([[maybe_unused]]
const SAXParseException& exc)
override
216 virtual void error (
const SAXParseException& exc)
override
219 static_cast<unsigned int> (exc.getColumnNumber ()), 0});
221 virtual void fatalError (
const SAXParseException& exc)
override
224 static_cast<unsigned int> (exc.getColumnNumber ()), 0});
230 struct SchemaRep_ : IXercesSchemaRep {
231#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
232 static inline atomic<unsigned int> sLiveCnt{0};
236 , fResolver{resolver}
237 , fSchemaData{schemaData.ReadAll ()}
240 XMLGrammarPoolImpl* grammarPool =
new (XMLPlatformUtils::fgMemoryManager) XMLGrammarPoolImpl{XMLPlatformUtils::fgMemoryManager};
242 Require (not fSchemaData.empty ());
243 MemBufInputSource mis{
reinterpret_cast<const XMLByte*
> (fSchemaData.begin ()), fSchemaData.GetSize (), u
""};
245 MySchemaResolver_ mySchemaResolver{resolver};
250 shared_ptr<SAX2XMLReaderImpl> reader = shared_ptr<SAX2XMLReaderImpl> (
251 new (XMLPlatformUtils::fgMemoryManager) SAX2XMLReaderImpl{XMLPlatformUtils::fgMemoryManager, grammarPool});
252 reader->setXMLEntityResolver (&mySchemaResolver);
254 SetupCommonParserFeatures_ (*reader,
true);
257 reader->setFeature (XMLUni::fgXercesCacheGrammarFromParse,
true);
258 reader->setErrorHandler (&fErrorReporter_);
259 xercesc::Grammar* g = reader->loadGrammar (mis, Grammar::SchemaGrammarType,
true);
261 const XMLCh* ts = g->getTargetNamespace ();
263 fTargetNamespace =
URI{xercesString2String (ts)};
270 fCachedGrammarPool = grammarPool;
271#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
275 SchemaRep_ (
const SchemaRep_&) =
delete;
276 virtual ~SchemaRep_ ()
278 delete fCachedGrammarPool;
279#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
280 Assert (sLiveCnt > 0);
284 optional<URI> fTargetNamespace;
287 xercesc::XMLGrammarPool* fCachedGrammarPool{
nullptr};
288 Map2StroikaExceptionsErrorReporter_ fErrorReporter_;
290 virtual const Providers::ISchemaProvider* GetProvider ()
const override
292 return &XML::Providers::Xerces::kDefaultProvider;
294 virtual optional<URI> GetTargetNamespace ()
const override
296 return fTargetNamespace;
307 virtual xercesc::XMLGrammarPool* GetCachedGrammarPool ()
override
309 return fCachedGrammarPool;
315 class StdIStream_InputSource_ :
public InputSource {
317 class StdIStream_InputStream :
public XERCES_CPP_NAMESPACE_QUALIFIER BinInputStream {
323 ~StdIStream_InputStream () =
default;
326 virtual XMLFilePos curPos ()
const override
330 virtual XMLSize_t readBytes (XMLByte*
const toFill,
const XMLSize_t maxToRead)
override
332 return fSource.ReadBlocking (span{
reinterpret_cast<byte*
> (toFill), maxToRead}).size ();
334 virtual const XMLCh* getContentType ()
const override
349 virtual BinInputStream* makeStream ()
const override
351 return new (getMemoryManager ()) StdIStream_InputStream{fSource};
360 class SAX2PrintHandlers_ :
public DefaultHandler {
366 : fCallback_{callback}
371 virtual void startDocument ()
override
373 if (fCallback_ !=
nullptr) {
377 virtual void endDocument ()
override
379 if (fCallback_ !=
nullptr) {
383 virtual void startElement (
const XMLCh*
const uri,
const XMLCh*
const localName,
const XMLCh*
const ,
const Attributes& attributes)
override
385 Require (uri !=
nullptr);
386 Require (localName !=
nullptr);
387 if (fCallback_ !=
nullptr) {
390 size_t attributesLen = attributes.getLength ();
391 for (XMLSize_t i = 0; i < attributesLen; ++i) {
392 Name attrName{xercesString2String (attributes.getURI (i)), xercesString2String (attributes.getLocalName (i)), Name::eAttribute};
393 useAttrs.
Add (attrName, xercesString2String (attributes.getValue (i)));
395 fCallback_->
StartElement (Name{xercesString2String (uri), xercesString2String (localName)}, useAttrs);
398 virtual void endElement (
const XMLCh*
const uri,
const XMLCh*
const localName, [[maybe_unused]]
const XMLCh*
const qname)
override
400 Require (uri !=
nullptr);
401 Require (localName !=
nullptr);
402 Require (qname !=
nullptr);
403 if (fCallback_ !=
nullptr) {
407 virtual void characters (
const XMLCh*
const chars,
const XMLSize_t length)
override
409 Require (chars !=
nullptr);
410 Require (length != 0);
411 if (fCallback_ !=
nullptr) {
423 class SubNodeIterator_ {
428 virtual ~Rep () =
default;
431 virtual bool IsAtEnd ()
const = 0;
432 virtual void Next () = 0;
434 virtual size_t GetLength ()
const = 0;
436 explicit SubNodeIterator_ (
const shared_ptr<Rep>& from)
442 nonvirtual
bool NotDone ()
const
444 return not fRep->IsAtEnd ();
446 nonvirtual
bool IsAtEnd ()
const
448 return fRep->IsAtEnd ();
450 nonvirtual
void Next ()
456 return fRep->Current ();
458 nonvirtual
size_t GetLength ()
const
460 return fRep->GetLength ();
462 nonvirtual
void operator++ ()
466 nonvirtual
void operator++ (
int)
476 shared_ptr<Rep> fRep;
481 template <
class TYPE>
484 AutoRelease_ (TYPE* p)
488 AutoRelease_ (
const AutoRelease_<TYPE>&) =
delete;
489 AutoRelease_<TYPE>& operator= (
const AutoRelease_<TYPE>&) =
delete;
496 TYPE& operator* ()
const
500 TYPE* operator->()
const
504 operator TYPE* ()
const
537 DOMImplementation& GetDOMIMPL_ ()
539 static constexpr XMLCh kDOMImplFeatureDeclaration_[] = u
"Core";
542 static DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation (kDOMImplFeatureDeclaration_);
549#if qStroika_Foundation_Debug_AssertionsChecked
550 bool ValidNewNodeName_ (
const String& n)
555 if (n.
find (
':') != wstring::npos) {
566 AutoRelease_<DOMLSOutput> theOutputDesc = GetDOMIMPL_ ().createLSOutput ();
567 theOutputDesc->setEncoding (XMLUni::fgUTF8EncodingString);
568 AutoRelease_<DOMLSSerializer> writer = GetDOMIMPL_ ().createLSSerializer ();
569 DOMConfiguration* dc = writer->getDomConfig ();
570 dc->setParameter (XMLUni::fgDOMWRTFormatPrettyPrint, options.fPrettyPrint);
571 dc->setParameter (XMLUni::fgDOMWRTBOM,
true);
572 class myOutputter :
public XMLFormatTarget {
579 virtual void writeChars (
const XMLByte*
const toWrite,
const XMLSize_t count, [[maybe_unused]] XMLFormatter*
const formatter)
override
581 fOut.
Write (span<const byte>{
reinterpret_cast<const byte*
> (toWrite), count});
583 virtual void flush ()
override
588 myOutputter dest{to};
589 theOutputDesc->setByteStream (&dest);
590 writer->write (node2Write, theOutputDesc);
593 DOMNode* RecursivelySetNamespace_ (DOMNode* n,
const XMLCh* namespaceURI)
597 switch (n->getNodeType ()) {
598 case DOMNode::ELEMENT_NODE: {
599 xercesc::DOMDocument* doc = n->getOwnerDocument ();
601 n = doc->renameNode (n, namespaceURI, n->getNodeName ());
603 for (DOMNode* child = n->getFirstChild (); child !=
nullptr; child = child->getNextSibling ()) {
604 child = RecursivelySetNamespace_ (child, namespaceURI);
610 constexpr XMLCh* kXerces2XMLDBDocumentKey_ =
nullptr;
613 String GetTextForDOMNode_ (
const DOMNode* node)
616 if (node->getNodeType () == DOMNode::COMMENT_NODE) {
632 using xercesc::DOMNode;
633 using xercesc::DOMText;
635 for (DOMNode* n = node->getFirstChild (); n !=
nullptr; n = n->getNextSibling ()) {
636 switch (n->getNodeType ()) {
637 case DOMNode::TEXT_NODE:
638 case DOMNode::CDATA_SECTION_NODE: {
639 DOMText* t (
static_cast<DOMText*
> (n));
644 case DOMNode::ELEMENT_NODE: {
655 DbgTrace (
"WARNING: GetTextForDOMNode_::BackupMode used"_f);
656 return node->getTextContent ();
659 Node::Ptr WrapXercesNodeInStroikaNode_ (DOMNode* n);
660 Element::Ptr WrapXercesNodeInStroikaNode_ (DOMElement* n);
664 class SubNodeIteratorOver_SiblingList_Rep_ :
public SubNodeIterator_::Rep,
668 SubNodeIteratorOver_SiblingList_Rep_ (DOMNode* nodeParent)
669 : fParentNode{nodeParent}
670 , fCachedMainListLen{static_cast<size_t> (-1)}
673 START_LIB_EXCEPTION_MAPPER_
675 fCurNode_ = nodeParent->getFirstChild ();
677 END_LIB_EXCEPTION_MAPPER_
679 virtual bool IsAtEnd ()
const override
681 return fCurNode_ ==
nullptr;
683 virtual void Next ()
override
685 Require (not IsAtEnd ());
687 START_LIB_EXCEPTION_MAPPER_
689 fCurNode_ = fCurNode_->getNextSibling ();
691 END_LIB_EXCEPTION_MAPPER_
693 virtual Node::Ptr Current ()
const override
695 return WrapXercesNodeInStroikaNode_ (fCurNode_);
697 virtual size_t GetLength ()
const override
699 if (fCachedMainListLen ==
static_cast<size_t> (-1)) {
701 START_LIB_EXCEPTION_MAPPER_
703 for (DOMNode* i = fParentNode->getFirstChild (); i !=
nullptr; (i = i->getNextSibling ()), ++n)
706 END_LIB_EXCEPTION_MAPPER_
707 fCachedMainListLen = n;
709 return fCachedMainListLen;
713 DOMNode* fParentNode{
nullptr};
714 DOMNode* fCurNode_{
nullptr};
715 mutable size_t fCachedMainListLen{};
721 NodeRep_ (DOMNode* n)
726 virtual const Providers::IDOMProvider* GetProvider ()
const override
728 return &Providers::Xerces::kDefaultProvider;
730 virtual bool Equals (
const IRep* rhs)
const override
734 return fNode_ ==
dynamic_cast<const NodeRep_*
> (rhs)->fNode_;
736 virtual Node::Type GetNodeType ()
const override
739 START_LIB_EXCEPTION_MAPPER_
741 switch (fNode_->getNodeType ()) {
742 case DOMNode::ELEMENT_NODE:
743 return Node::eElementNT;
744 case DOMNode::ATTRIBUTE_NODE:
745 return Node::eAttributeNT;
746 case DOMNode::TEXT_NODE:
747 return Node::eTextNT;
748 case DOMNode::COMMENT_NODE:
749 return Node::eCommentNT;
751 return Node::eOtherNT;
754 END_LIB_EXCEPTION_MAPPER_
759 Require (GetNodeType () == Node::eElementNT or GetNodeType () == Node::eAttributeNT);
760 START_LIB_EXCEPTION_MAPPER_
763 const XMLCh* n = fNode_->getNamespaceURI ();
764 return NameWithNamespace{n ==
nullptr ? optional<URI>{} :
URI{xercesString2String (n)}, fNode_->getNodeName ()};
766 END_LIB_EXCEPTION_MAPPER_
771#if qStroika_Foundation_Debug_AssertionsChecked
772 Require (ValidNewNodeName_ (name.fName));
774 START_LIB_EXCEPTION_MAPPER_
776 xercesc::DOMDocument* doc = fNode_->getOwnerDocument ();
778 fNode_ = doc->renameNode (
779 fNode_, name.fNamespace == nullopt ?
nullptr : name.fNamespace->As<
String> (kUseURIEncodingFlag_).As<u16string> ().c_str (),
780 name.fName.As<u16string> ().c_str ());
783 END_LIB_EXCEPTION_MAPPER_
785 virtual String GetValue ()
const override
788 START_LIB_EXCEPTION_MAPPER_
790 return GetTextForDOMNode_ (fNode_);
792 END_LIB_EXCEPTION_MAPPER_
794 virtual void SetValue (
const String& v)
override
797 START_LIB_EXCEPTION_MAPPER_
799 fNode_->setTextContent (v.empty () ?
nullptr : v.As<u16string> ().c_str ());
801 END_LIB_EXCEPTION_MAPPER_
803 virtual void DeleteNode ()
override
805 START_LIB_EXCEPTION_MAPPER_
807 DOMNode* selNode = fNode_;
809 DOMNode* parentNode = selNode->getParentNode ();
810 if (parentNode ==
nullptr) {
812 if (fNode_ !=
nullptr) {
813 const XMLCh* ln = selNode->getNodeName ();
815 DOMElement* de =
dynamic_cast<DOMElement*
> (fNode_);
816 de->removeAttribute (ln);
820 (void)parentNode->removeChild (selNode);
823 END_LIB_EXCEPTION_MAPPER_
825 virtual Node::Ptr GetParentNode ()
const override
828 START_LIB_EXCEPTION_MAPPER_
830 auto p = fNode_->getParentNode ();
831 return p ==
nullptr ? nullptr : WrapXercesNodeInStroikaNode_ (p);
833 END_LIB_EXCEPTION_MAPPER_
837 START_LIB_EXCEPTION_MAPPER_
839 DoWrite2Stream_ (fNode_, to, options);
841 END_LIB_EXCEPTION_MAPPER_
843 virtual xercesc::DOMNode* GetInternalTRep ()
override
854 struct ElementRep_ : Element::
IRep, Memory::InheritAndUseBlockAllocationIfAppropriate<ElementRep_, NodeRep_> {
856 ElementRep_ (DOMNode* n)
860 Require (n->getNodeType () == DOMNode::ELEMENT_NODE);
862 virtual Node::Type GetNodeType ()
const override
865 Assert (fNode_->getNodeType () == DOMNode::ELEMENT_NODE);
866 return Node::eElementNT;
868 virtual optional<String> GetAttribute (
const NameWithNamespace& attrName)
const override
871 START_LIB_EXCEPTION_MAPPER_
873 if (fNode_->getNodeType () == DOMNode::ELEMENT_NODE) {
874 DOMElement* elt = Debug::UncheckedDynamicCast<DOMElement*> (fNode_);
875 const XMLCh* s = attrName.fNamespace
876 ? elt->getAttributeNS (attrName.fNamespace->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str (),
877 attrName.fName.
As<u16string> ().c_str ())
878 : elt->getAttribute (attrName.fName.
As<u16string> ().c_str ());
886 END_LIB_EXCEPTION_MAPPER_
888 virtual void SetAttribute (
const NameWithNamespace& attrName,
const optional<String>& v)
override
890 Require (GetNodeType () == Node::eElementNT);
892 START_LIB_EXCEPTION_MAPPER_
894 DOMElement* element =
dynamic_cast<DOMElement*
> (fNode_);
916 element->setAttributeNS (attrName.fNamespace ? attrName.fNamespace->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str () : nullptr,
917 attrName.fName.As<u16string> ().c_str (), v->As<u16string> ().c_str ());
920 element->removeAttributeNS (
921 attrName.fNamespace ? attrName.fNamespace->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str () : nullptr,
922 attrName.fName.As<u16string> ().c_str ());
925 END_LIB_EXCEPTION_MAPPER_
929#if qStroika_Foundation_Debug_AssertionsChecked
930 Require (ValidNewNodeName_ (eltName.fName));
932 START_LIB_EXCEPTION_MAPPER_
934 xercesc::DOMDocument* doc = fNode_->getOwnerDocument ();
937 DOMNode* child = doc->createElementNS ((eltName.fNamespace == nullopt)
938 ? fNode_->getNamespaceURI ()
939 : eltName.fNamespace->As<
String> (kUseURIEncodingFlag_).As<u16string> ().c_str (),
940 eltName.fName.As<u16string> ().c_str ());
941 DOMNode* refChildNode =
nullptr;
942 if (afterNode ==
nullptr) {
945 refChildNode = fNode_->getFirstChild ();
948 refChildNode =
dynamic_cast<NodeRep_&
> (*afterNode.
GetRep ()).GetInternalTRep ()->getNextSibling ();
950 DOMNode* childx = fNode_->insertBefore (child, refChildNode);
952 return WrapXercesNodeInStroikaNode_ (childx);
954 END_LIB_EXCEPTION_MAPPER_
958#if qStroika_Foundation_Debug_AssertionsChecked
959 Require (ValidNewNodeName_ (eltName.fName));
961 START_LIB_EXCEPTION_MAPPER_
963 xercesc::DOMDocument* doc = fNode_->getOwnerDocument ();
965 if (eltName.fNamespace) {
966 u16string namespaceURI = eltName.fNamespace->As<
String> (kUseURIEncodingFlag_).As<u16string> ();
967 child = doc->createElementNS (namespaceURI.c_str (), eltName.fName.
As<u16string> ().c_str ());
970 const XMLCh* namespaceURI = fNode_->getNamespaceURI ();
971 child = doc->createElementNS (namespaceURI, eltName.fName.
As<u16string> ().c_str ());
973 DOMNode* childx = fNode_->appendChild (child);
975 return WrapXercesNodeInStroikaNode_ (childx);
977 END_LIB_EXCEPTION_MAPPER_
982 START_LIB_EXCEPTION_MAPPER_
984 return Traversal::CreateGenerator<Node::Ptr> (
985 [sni = SubNodeIterator_{Memory::MakeSharedPtr<SubNodeIteratorOver_SiblingList_Rep_> (fNode_)}] ()
mutable -> optional<Node::Ptr> {
986 if (sni.IsAtEnd ()) {
987 return optional<Node::Ptr>{};
994 END_LIB_EXCEPTION_MAPPER_
996 struct XPathQueryHelper_ {
997 optional<AutoRelease_<DOMXPathNSResolver>> resolver;
998 DOMXPathResult::ResultType rt{};
999 optional<AutoRelease_<DOMXPathExpression>> expr;
1002 xercesc::DOMDocument* doc = n->getOwnerDocument ();
1003 resolver.emplace (doc->createNSResolver (
nullptr));
1004 auto namespaceDefs = e.
GetOptions ().fNamespaces;
1005 if (namespaceDefs.GetDefaultNamespace ()) {
1006 (*resolver)->addNamespaceBinding (
1007 u
"", namespaceDefs.GetDefaultNamespace ()->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str ());
1010 (*resolver)->addNamespaceBinding (ni.fKey.As<u16string> ().c_str (),
1011 ni.fValue.As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str ());
1014 expr.emplace (doc->createExpression (e.
GetExpression ().
As<u16string> ().c_str (), *resolver));
1016 catch (
const xercesc::DOMXPathException&) {
1020 switch (e.
GetOptions ().fResultTypeIndex.value_or (DOMXPathResult::ANY_TYPE)) {
1021 case XPath::ResultTypeIndex_v<Node::Ptr>: {
1024 rt = e.
GetOptions ().fOrdered ? DOMXPathResult::FIRST_ORDERED_NODE_TYPE : DOMXPathResult::ANY_UNORDERED_NODE_TYPE;
1026 else if (o.fSnapshot) {
1027 rt = e.
GetOptions ().fOrdered ? DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE : DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE;
1032 rt = e.
GetOptions ().fOrdered ? DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE : DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE;
1039 static optional<XPath::Result> ToResult_ (
const xercesc::DOMXPathResult* r)
1042 switch (r->getResultType ()) {
1043 case DOMXPathResult::NUMBER_TYPE:
1044 return XPath::Result{r->getNumberValue ()};
1045 case DOMXPathResult::BOOLEAN_TYPE:
1046 return XPath::Result{r->getBooleanValue ()};
1047 case DOMXPathResult::STRING_TYPE:
1048 return XPath::Result{xercesString2String (r->getStringValue ())};
1049 case DOMXPathResult::ANY_UNORDERED_NODE_TYPE:
1050 case DOMXPathResult::FIRST_ORDERED_NODE_TYPE:
1051 case DOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE:
1052 case DOMXPathResult::ORDERED_NODE_ITERATOR_TYPE:
1053 case DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE:
1054 case DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE: {
1055 auto n = r->getNodeValue ();
1056 return n ==
nullptr ? optional<XPath::Result>{} : XPath::Result{
Node::Ptr{WrapXercesNodeInStroikaNode_ (n)}};
1066 if constexpr (
false) {
1068 for (
auto i : Lookup (e)) {
1073 START_LIB_EXCEPTION_MAPPER_
1075 XPathQueryHelper_ xpHelp{fNode_, e,
true};
1076 AutoRelease_<xercesc::DOMXPathResult> r = (*xpHelp.expr)->evaluate (fNode_, xpHelp.rt,
nullptr);
1077 return XPathQueryHelper_::ToResult_ (r);
1079 END_LIB_EXCEPTION_MAPPER_
1084 XPath::Expression::Options e2o = e.
GetOptions ();
1085 e2o.fSnapshot =
false;
1088 shared_ptr<XPathQueryHelper_> xpHelp = make_shared<XPathQueryHelper_> (fNode_, e,
false);
1089 shared_ptr<AutoRelease_<xercesc::DOMXPathResult>> r =
1090 make_shared<AutoRelease_<xercesc::DOMXPathResult>> ((*xpHelp->expr)->evaluate (fNode_, xpHelp->rt,
nullptr));
1092 if (xpHelp->rt == DOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE or xpHelp->rt == DOMXPathResult::ORDERED_NODE_ITERATOR_TYPE) [[unlikely]] {
1093 return Traversal::CreateGenerator<XPath::Result> ([xpHelp, r, firstTime =
true] ()
mutable -> optional<XPath::Result> {
1096 return XPathQueryHelper_::ToResult_ (*r);
1098 if ((*r)->iterateNext () ==
false) {
1101 return XPathQueryHelper_::ToResult_ (*r);
1104 if (xpHelp->rt == DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE or xpHelp->rt == DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE) [[likely]] {
1105 return Traversal::CreateGenerator<XPath::Result> ([xpHelp, r, snapIdx = 0] ()
mutable -> optional<XPath::Result> {
1106 if (not(*r)->snapshotItem (snapIdx)) {
1110 return XPathQueryHelper_::ToResult_ (*r);
1119 START_LIB_EXCEPTION_MAPPER_
1121 for (DOMNode* i = fNode_->getFirstChild (); i !=
nullptr; i = i->getNextSibling ()) {
1122 if (i->getNodeType () == DOMNode::ELEMENT_NODE) {
1123 DOMElement* elt = Debug::UncheckedDynamicCast<DOMElement*> (i);
1124 const XMLCh* s = elt->getAttribute (u
"id");
1126 if (CString::Equals (s,
id.As<u16string> ().c_str ())) {
1127 return WrapXercesNodeInStroikaNode_ (elt);
1133 END_LIB_EXCEPTION_MAPPER_
1136 DISABLE_COMPILER_MSC_WARNING_END (4250)
1140 inline void MakeXMLDoc_ (shared_ptr<xercesc::DOMDocument>& newXMLDoc)
1142 Require (newXMLDoc ==
nullptr);
1143 newXMLDoc = shared_ptr<xercesc::DOMDocument> (GetDOMIMPL_ ().createDocument (0,
nullptr, 0));
1144 newXMLDoc->setXmlStandalone (
true);
1149 class MyMaybeSchemaDOMParser_ {
1151 Map2StroikaExceptionsErrorReporter_ myErrReporter;
1152 shared_ptr<XercesDOMParser> fParser;
1155 MyMaybeSchemaDOMParser_ () =
delete;
1156 MyMaybeSchemaDOMParser_ (
const MyMaybeSchemaDOMParser_&) =
delete;
1157 MyMaybeSchemaDOMParser_ (
const Schema::Ptr& schema)
1160 shared_ptr<IXercesSchemaRep> accessSchema = dynamic_pointer_cast<IXercesSchemaRep> (schema.GetRep ());
1161 if (accessSchema !=
nullptr) {
1162 fParser = Memory::MakeSharedPtr<XercesDOMParser> (
nullptr, XMLPlatformUtils::fgMemoryManager, accessSchema->GetCachedGrammarPool ());
1163 fParser->cacheGrammarFromParse (
false);
1164 fParser->useCachedGrammarInParse (
true);
1165 fParser->setDoSchema (
true);
1166 fParser->setValidationScheme (AbstractDOMParser::Val_Always);
1167 fParser->setValidationSchemaFullChecking (
true);
1168 fParser->setIdentityConstraintChecking (
true);
1171 fParser = Memory::MakeSharedPtr<XercesDOMParser> ();
1173 fParser->setDoNamespaces (
true);
1174 fParser->setErrorHandler (&myErrReporter);
1182 fParser->setLoadExternalDTD (
false);
1186 fParser->setLoadSchema (
false);
1193 Element::Ptr WrapXercesNodeInStroikaNode_ (DOMElement* n);
1196 struct DocRep_ : DataExchange::XML::DOM::Document::IRep {
1197#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1198 static inline atomic<unsigned int> sLiveCnt{0};
1208 [[maybe_unused]]
int ignoreMe = 0;
1209 START_LIB_EXCEPTION_MAPPER_
1211 MakeXMLDoc_ (fXMLDoc);
1212 fXMLDoc->setUserData (kXerces2XMLDBDocumentKey_,
this,
nullptr);
1213 if (in !=
nullptr) {
1214 MyMaybeSchemaDOMParser_ myDOMParser{schema};
1215 myDOMParser.fParser->parse (StdIStream_InputSource_{in, u
"XMLDB"});
1217 fXMLDoc = shared_ptr<xercesc::DOMDocument>{myDOMParser.fParser->adoptDocument ()};
1218 fXMLDoc->setXmlStandalone (
true);
1219 fXMLDoc->setUserData (kXerces2XMLDBDocumentKey_,
this,
nullptr);
1222 END_LIB_EXCEPTION_MAPPER_
1223#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1227 DocRep_ (
const DocRep_& from)
1229 START_LIB_EXCEPTION_MAPPER_
1231 fXMLDoc = shared_ptr<xercesc::DOMDocument> (
dynamic_cast<xercesc::DOMDocument*
> (from.fXMLDoc->cloneNode (
true)));
1232 fXMLDoc->setXmlStandalone (
true);
1233 fXMLDoc->setUserData (kXerces2XMLDBDocumentKey_,
this,
nullptr);
1235 END_LIB_EXCEPTION_MAPPER_
1237#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1243#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1244 Assert (sLiveCnt > 0);
1248 virtual const Providers::IDOMProvider* GetProvider ()
const override
1250 return &Providers::Xerces::kDefaultProvider;
1252 virtual bool GetStandalone ()
const override
1255 return fXMLDoc->getXmlStandalone ();
1257 virtual void SetStandalone (
bool standalone)
override
1260 fXMLDoc->setXmlStandalone (standalone);
1266 START_LIB_EXCEPTION_MAPPER_
1267 return Traversal::CreateGenerator<Node::Ptr> (
1268 [sni = SubNodeIterator_{Memory::MakeSharedPtr<SubNodeIteratorOver_SiblingList_Rep_> (fXMLDoc.get ())}] ()
mutable -> optional<Node::Ptr> {
1269 if (sni.IsAtEnd ()) {
1270 return optional<Node::Ptr>{};
1276 END_LIB_EXCEPTION_MAPPER_
1280 DOMElement* n = newEltName.fNamespace == nullopt
1281 ? fXMLDoc->createElement (newEltName.fName.
As<u16string> ().c_str ())
1282 : fXMLDoc->createElementNS (newEltName.fNamespace->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str (),
1283 newEltName.fName.
As<u16string> ().c_str ());
1285 DOMElement* oldRoot = fXMLDoc->getDocumentElement ();
1286 if (oldRoot ==
nullptr) {
1287 (void)fXMLDoc->insertBefore (n,
nullptr);
1290 (void)fXMLDoc->replaceChild (n, oldRoot);
1309 Assert (fXMLDoc->getDocumentElement () == n);
1311 if (childrenInheritNS and newEltName.fNamespace) {
1321 START_LIB_EXCEPTION_MAPPER_
1323 DoWrite2Stream_ (fXMLDoc.get (), to, options);
1325 END_LIB_EXCEPTION_MAPPER_
1327#if qCompilerAndStdLib_arm_asan_FaultStackUseAfterScope_Buggy
1328 Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS
1331 Validate (
const Schema::Ptr& schema)
const override
1336 START_LIB_EXCEPTION_MAPPER_
1343 DOMNode* docNode = fXMLDoc->getDocumentElement ();
1344 if (docNode ==
nullptr) [[unlikely]] {
1347 optional<URI> docURI = docNode->getNamespaceURI () ==
nullptr ? optional<URI>{} : docNode->getNamespaceURI ();
1350 Format (
"Wrong document namespace (found '{}' and expected '{}')"_f, docURI, schema.
GetTargetNamespace ()), 0, 0, 0});
1355 MemBufFormatTarget destination;
1357 AutoRelease_<DOMLSOutput> theOutputDesc = GetDOMIMPL_ ().createLSOutput ();
1358 theOutputDesc->setEncoding (XMLUni::fgUTF8EncodingString);
1359 AutoRelease_<DOMLSSerializer> writer = GetDOMIMPL_ ().createLSSerializer ();
1360 theOutputDesc->setByteStream (&destination);
1361 theOutputDesc->setEncoding (XMLUni::fgUTF8EncodingString);
1362 Assert (fXMLDoc->getXmlStandalone ());
1363 writer->write (fXMLDoc.get (), theOutputDesc);
1365 MemBufInputSource readReadSrc{destination.getRawBuffer (), destination.getLen (), u
"tmp"};
1366 readReadSrc.setEncoding (XMLUni::fgUTF8EncodingString);
1367 shared_ptr<IXercesSchemaRep> accessSchema = dynamic_pointer_cast<IXercesSchemaRep> (schema.GetRep ());
1370 shared_ptr<SAX2XMLReader> parser = shared_ptr<SAX2XMLReader> (
1371 XMLReaderFactory::createXMLReader (XMLPlatformUtils::fgMemoryManager, accessSchema->GetCachedGrammarPool ()));
1372 SetupCommonParserFeatures_ (*parser,
true);
1373 Map2StroikaExceptionsErrorReporter_ myErrorReporter;
1374 parser->setErrorHandler (&myErrorReporter);
1375 parser->parse (readReadSrc);
1380 if constexpr (qDumpXMLOnValidationError_) {
1381#if !qCompilerAndStdLib_arm_asan_FaultStackUseAfterScope_Buggy
1387 DbgTrace (
"Error validating - so writing out temporary file = '{}'"_f, tmpFileName);
1388 Write (IO::FileSystem::FileOutputStream::New (tmpFileName),
SerializationOptions{.fPrettyPrint =
true, .fIndent = 4});
1390 ValidateFile (tmpFileName, schema);
1394 size_t idx = tmpFileNameStr.
find (
".xml");
1395 String newTmpFile = tmpFileNameStr.
substr (0, idx) +
"_MSG.txt";
1397 msgOut <<
"Reason:" << vf.GetDetails () << endl;
1398 optional<unsigned int> lineNum;
1399 optional<unsigned int> colNumber;
1400 optional<uint64_t> fileOffset;
1401 vf.GetPositionInfo (&lineNum, &colNumber, &fileOffset);
1403 msgOut <<
"Line:" << *lineNum << endl;
1406 msgOut <<
"Col: " << *colNumber << endl;
1409 msgOut <<
"FilePos: " << *fileOffset << endl;
1419 END_LIB_EXCEPTION_MAPPER_
1421 shared_ptr<xercesc::DOMDocument> fXMLDoc;
1427 Node::Ptr WrapXercesNodeInStroikaNode_ (DOMNode* n)
1430 if (n->getNodeType () == DOMNode::ELEMENT_NODE) {
1431 return Node::Ptr{Memory::MakeSharedPtr<ElementRep_> (n)};
1434 return Node::Ptr{Memory::MakeSharedPtr<NodeRep_> (n)};
1437 Element::Ptr WrapXercesNodeInStroikaNode_ (DOMElement* n)
1440 return Element::Ptr{Memory::MakeSharedPtr<ElementRep_> (n)};
1449String Providers::Xerces::xercesString2String (
const XMLCh* s,
const XMLCh* e)
1451 if constexpr (same_as<XMLCh, char16_t>) {
1452 return String{span{s, e}};
1456 if constexpr (
sizeof (XMLCh) ==
sizeof (
char16_t)) {
1457 return String{span{
reinterpret_cast<const char16_t*
> (s),
reinterpret_cast<const char16_t*
> (e)}};
1459 else if constexpr (
sizeof (XMLCh) ==
sizeof (
char32_t)) {
1460 return String{span{
reinterpret_cast<const char32_t*
> (s),
reinterpret_cast<const char32_t*
> (e)}};
1468String Providers::Xerces::xercesString2String (
const XMLCh* t)
1470 if constexpr (same_as<XMLCh, char16_t>) {
1475 if constexpr (
sizeof (XMLCh) ==
sizeof (
char16_t)) {
1476 return String{
reinterpret_cast<const char16_t*
> (t)};
1478 else if constexpr (
sizeof (XMLCh) ==
sizeof (
char32_t)) {
1479 return String{
reinterpret_cast<const char32_t*
> (t)};
1492Providers::Xerces::Provider::Provider ()
1495#if qStroika_Foundation_Debug_AssertionsChecked
1496 static unsigned int sNProvidersCreated_{0};
1497 Assert (++sNProvidersCreated_ == 1);
1499#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1500 fUseXercesMemoryManager_ =
new MyXercesMemMgr_{};
1501 XMLPlatformUtils::Initialize (XMLUni::fgXercescDefaultLocale, 0, 0, fUseXercesMemoryManager_);
1503 XMLPlatformUtils::Initialize (XMLUni::fgXercescDefaultLocale, 0, 0);
1507Providers::Xerces::Provider::~Provider ()
1510 XMLPlatformUtils::Terminate ();
1511#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1512 Require (SchemaRep_::sLiveCnt == 0);
1513 Require (DocRep_::sLiveCnt == 0);
1514 delete fUseXercesMemoryManager_;
1520 return Memory::MakeSharedPtr<SchemaRep_> (schemaData, resolver);
1524 const Schema::Ptr& schemaToValidateAgainstWhileReading)
const
1526 return Memory::MakeSharedPtr<DocRep_> (in, schemaToValidateAgainstWhileReading);
1532 SAX2PrintHandlers_ handler{callback};
1533 shared_ptr<IXercesSchemaRep> accessSchema;
1534 if (schema !=
nullptr) {
1535 accessSchema = dynamic_pointer_cast<IXercesSchemaRep> (schema.GetRep ());
1537 shared_ptr<SAX2XMLReader> parser{XMLReaderFactory::createXMLReader (
1538 XMLPlatformUtils::fgMemoryManager, accessSchema ==
nullptr ?
nullptr : accessSchema->GetCachedGrammarPool ())};
1539 SetupCommonParserFeatures_ (*parser, accessSchema !=
nullptr);
1540 parser->setContentHandler (&handler);
1541 Map2StroikaExceptionsErrorReporter_ mErrorReproter_;
1542 parser->setErrorHandler (&mErrorReproter_);
1543 parser->parse (StdIStream_InputSource_{in});
#define AssertNotImplemented()
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
#define RequireNotNull(p)
#define AssertNotReached()
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
bool Equals(const T *lhs, const T *rhs)
strcmp or wsccmp() as appropriate == 0
#define CompileTimeFlagChecker_SOURCE(NS_PREFIX, NAME, VALUE)
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual String str() const
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual string AsNarrowSDKString() const
nonvirtual String substr(size_t from, size_t count=npos) const
nonvirtual size_t find(Character c, size_t startAt=0) const
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
A generalization of a vector: a container whose elements are keyed by the natural numbers.
virtual void EndDocument()
virtual void StartDocument()
virtual void TextInsideElement(const String &text)
virtual void EndElement(const Name &name)
virtual void StartElement(const Name &name, const Mapping< Name, String > &attributes)
nonvirtual void SetAttribute(const NameWithNamespace &attrName, const optional< String > &v)
nonvirtual shared_ptr< IRep > GetRep() const
return the associated shared_ptr (cannot be nullptr)
Node::Ptr is a smart pointer to a Node::IRep.
nonvirtual String GetExpression() const
nonvirtual Options GetOptions() const
nonvirtual optional< URI > GetTargetNamespace() const
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
nonvirtual filesystem::path GetTmpFile(const String &fileBaseName)
static AppTmpFileManager sThe
nonvirtual bool empty() const
nonvirtual const byte * begin() const
nonvirtual size_t GetSize() const
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
nonvirtual void Write(span< ELEMENT_TYPE2, EXTENT_2 > elts) const
nonvirtual void Flush() const
forces any data contained in this stream to be written.
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
DISABLE_COMPILER_MSC_WARNING_START(4996)
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
void ThrowIfNull(const Private_::ConstVoidStar &p, const HRESULT &hr)
Template specialization for ThrowIfNull (), for thing being thrown HRESULT - really throw HRESULTErro...