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;
41using Memory::MakeSharedPtr;
46static_assert (qStroika_HasComponent_xerces,
"Don't compile this file if qStroika_HasComponent_xerces not set");
57 constexpr auto kUseURIEncodingFlag_ = URI::StringPCTEncodedFlag::eDecoded;
62#define START_LIB_EXCEPTION_MAPPER_ try {
63#define END_LIB_EXCEPTION_MAPPER_ \
65 catch (const xercesc::OutOfMemoryException&) \
67 Execution::Throw (bad_alloc{}, "xerces OutOfMemoryException - throwing bad_alloc"); \
71 Execution::ReThrow (); \
74#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
80struct Provider::MyXercesMemMgr_ :
public MemoryManager {
83 : fAllocator{fBaseAllocator}
88#if qStroika_Foundation_Debug_AssertionsChecked
89 auto snapshot = fAllocator.GetSnapshot ();
90 Assert (snapshot.fAllocations.empty ());
97 mutex fLastSnapshot_CritSection;
98 Memory::LeakTrackingGeneralPurposeAllocator::Snapshot fLastSnapshot;
101 void DUMPCurMemStats ()
104 [[maybe_unused]] lock_guard critSec{fLastSnapshot_CritSection};
105 fAllocator.DUMPCurMemStats (fLastSnapshot);
107 fLastSnapshot = fAllocator.GetSnapshot ();
111 virtual MemoryManager* getExceptionMemoryManager ()
override
115 virtual void* allocate (XMLSize_t size)
override
118 return fAllocator.Allocate (size);
122 throw (OutOfMemoryException{});
125 virtual void deallocate (
void* p)
override
128 return fAllocator.Deallocate (p);
135 struct MySchemaResolver_ :
public XMLEntityResolver {
141 : fResolver_{resolver}
144 virtual InputSource* resolveEntity (XMLResourceIdentifier* resourceIdentifier)
override
150 if (fResolver_ !=
nullptr) {
151 if (
auto o = fResolver_.Lookup (
Resource::Name{.fNamespace = xercesString2String (resourceIdentifier->getNameSpace ()),
152 .fPublicID = xercesString2String (resourceIdentifier->getPublicId ()),
153 .fSystemID = xercesString2String (resourceIdentifier->getSystemId ())})) {
154 return mkMemInputSrc_ (o->fData);
161 static InputSource* mkMemInputSrc_ (
const Memory::BLOB& schemaData)
163 if (schemaData.
empty ()) [[unlikely]] {
165 return new MemBufInputSource{
nullptr, 0,
"",
true};
168 XMLByte* useBuf =
new XMLByte[schemaData.
GetSize ()];
169 memcpy (useBuf, schemaData.
begin (), schemaData.
GetSize ());
170 return new MemBufInputSource{useBuf, schemaData.
GetSize (),
"",
true};
177 void SetupCommonParserFeatures_ (SAX2XMLReader& reader)
179 reader.setFeature (XMLUni::fgSAX2CoreNameSpaces,
true);
180 reader.setFeature (XMLUni::fgXercesDynamic,
false);
181 reader.setFeature (XMLUni::fgSAX2CoreNameSpacePrefixes,
false);
183 void SetupCommonParserFeatures_ (SAX2XMLReader& reader,
bool validatingWithSchema)
185 reader.setFeature (XMLUni::fgXercesSchema, validatingWithSchema);
186 reader.setFeature (XMLUni::fgSAX2CoreValidation, validatingWithSchema);
192 reader.setFeature (XMLUni::fgXercesSchemaFullChecking, validatingWithSchema);
193 reader.setFeature (XMLUni::fgXercesUseCachedGrammarInParse, validatingWithSchema);
194 reader.setFeature (XMLUni::fgXercesIdentityConstraintChecking, validatingWithSchema);
198 reader.setFeature (XMLUni::fgXercesCacheGrammarFromParse,
false);
203 struct Map2StroikaExceptionsErrorReporter_ :
public XMLErrorReporter,
public ErrorHandler {
205 virtual void error ([[maybe_unused]]
const unsigned int errCode, [[maybe_unused]]
const XMLCh*
const errDomain,
206 [[maybe_unused]]
const ErrTypes type,
const XMLCh*
const errorText, [[maybe_unused]]
const XMLCh*
const systemId,
207 [[maybe_unused]]
const XMLCh*
const publicId,
const XMLFileLoc lineNum,
const XMLFileLoc colNum)
override
209 Execution::Throw (
BadFormatException{errorText,
static_cast<unsigned int> (lineNum),
static_cast<unsigned int> (colNum), 0});
211 virtual void resetErrors ()
override
214 virtual void warning ([[maybe_unused]]
const SAXParseException& exc)
override
218 virtual void error (
const SAXParseException& exc)
override
220 Execution::Throw (
BadFormatException{exc.getMessage (),
static_cast<unsigned int> (exc.getLineNumber ()),
221 static_cast<unsigned int> (exc.getColumnNumber ()), 0});
223 virtual void fatalError (
const SAXParseException& exc)
override
225 Execution::Throw (
BadFormatException{exc.getMessage (),
static_cast<unsigned int> (exc.getLineNumber ()),
226 static_cast<unsigned int> (exc.getColumnNumber ()), 0});
232 struct SchemaRep_ : IXercesSchemaRep {
233#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
234 static inline atomic<unsigned int> sLiveCnt{0};
238 , fResolver{resolver}
239 , fSchemaData{schemaData.ReadAll ()}
242 XMLGrammarPoolImpl* grammarPool =
new (XMLPlatformUtils::fgMemoryManager) XMLGrammarPoolImpl{XMLPlatformUtils::fgMemoryManager};
244 Require (not fSchemaData.empty ());
245 MemBufInputSource mis{
reinterpret_cast<const XMLByte*
> (fSchemaData.begin ()), fSchemaData.GetSize (), u
""};
247 MySchemaResolver_ mySchemaResolver{resolver};
252 shared_ptr<SAX2XMLReaderImpl> reader = shared_ptr<SAX2XMLReaderImpl> (
253 new (XMLPlatformUtils::fgMemoryManager) SAX2XMLReaderImpl{XMLPlatformUtils::fgMemoryManager, grammarPool});
254 reader->setXMLEntityResolver (&mySchemaResolver);
256 SetupCommonParserFeatures_ (*reader,
true);
259 reader->setFeature (XMLUni::fgXercesCacheGrammarFromParse,
true);
260 reader->setErrorHandler (&fErrorReporter_);
261 xercesc::Grammar* g = reader->loadGrammar (mis, Grammar::SchemaGrammarType,
true);
263 const XMLCh* ts = g->getTargetNamespace ();
265 fTargetNamespace =
URI{xercesString2String (ts)};
270 Execution::ReThrow ();
272 fCachedGrammarPool = grammarPool;
273#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
277 SchemaRep_ (
const SchemaRep_&) =
delete;
278 virtual ~SchemaRep_ ()
280 delete fCachedGrammarPool;
281#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
282 Assert (sLiveCnt > 0);
286 optional<URI> fTargetNamespace;
289 xercesc::XMLGrammarPool* fCachedGrammarPool{
nullptr};
290 Map2StroikaExceptionsErrorReporter_ fErrorReporter_;
292 virtual const Providers::ISchemaProvider* GetProvider ()
const override
294 return &XML::Providers::Xerces::kDefaultProvider;
296 virtual optional<URI> GetTargetNamespace ()
const override
298 return fTargetNamespace;
309 virtual xercesc::XMLGrammarPool* GetCachedGrammarPool ()
override
311 return fCachedGrammarPool;
317 class StdIStream_InputSource_ :
public InputSource {
319 class StdIStream_InputStream :
public XERCES_CPP_NAMESPACE_QUALIFIER BinInputStream {
325 ~StdIStream_InputStream () =
default;
328 virtual XMLFilePos curPos ()
const override
332 virtual XMLSize_t readBytes (XMLByte*
const toFill,
const XMLSize_t maxToRead)
override
334 return fSource.ReadBlocking (span{
reinterpret_cast<byte*
> (toFill), maxToRead}).size ();
336 virtual const XMLCh* getContentType ()
const override
351 virtual BinInputStream* makeStream ()
const override
353 return new (getMemoryManager ()) StdIStream_InputStream{fSource};
362 class SAX2PrintHandlers_ :
public DefaultHandler {
368 : fCallback_{callback}
373 virtual void startDocument ()
override
375 if (fCallback_ !=
nullptr) {
379 virtual void endDocument ()
override
381 if (fCallback_ !=
nullptr) {
385 virtual void startElement (
const XMLCh*
const uri,
const XMLCh*
const localName,
const XMLCh*
const ,
const Attributes& attributes)
override
387 Require (uri !=
nullptr);
388 Require (localName !=
nullptr);
389 if (fCallback_ !=
nullptr) {
392 size_t attributesLen = attributes.getLength ();
393 for (XMLSize_t i = 0; i < attributesLen; ++i) {
394 Name attrName{xercesString2String (attributes.getURI (i)), xercesString2String (attributes.getLocalName (i)), Name::eAttribute};
395 useAttrs.
Add (attrName, xercesString2String (attributes.getValue (i)));
397 fCallback_->
StartElement (Name{xercesString2String (uri), xercesString2String (localName)}, useAttrs);
400 virtual void endElement (
const XMLCh*
const uri,
const XMLCh*
const localName, [[maybe_unused]]
const XMLCh*
const qname)
override
402 Require (uri !=
nullptr);
403 Require (localName !=
nullptr);
404 Require (qname !=
nullptr);
405 if (fCallback_ !=
nullptr) {
409 virtual void characters (
const XMLCh*
const chars,
const XMLSize_t length)
override
411 Require (chars !=
nullptr);
412 Require (length != 0);
413 if (fCallback_ !=
nullptr) {
425 class SubNodeIterator_ {
430 virtual ~Rep () =
default;
433 virtual bool IsAtEnd ()
const = 0;
434 virtual void Next () = 0;
436 virtual size_t GetLength ()
const = 0;
438 explicit SubNodeIterator_ (
const shared_ptr<Rep>& from)
444 nonvirtual
bool NotDone ()
const
446 return not fRep->IsAtEnd ();
448 nonvirtual
bool IsAtEnd ()
const
450 return fRep->IsAtEnd ();
452 nonvirtual
void Next ()
458 return fRep->Current ();
460 nonvirtual
size_t GetLength ()
const
462 return fRep->GetLength ();
464 nonvirtual
void operator++ ()
468 nonvirtual
void operator++ (
int)
478 shared_ptr<Rep> fRep;
483 template <
class TYPE>
486 AutoRelease_ (TYPE* p)
490 AutoRelease_ (
const AutoRelease_<TYPE>&) =
delete;
491 AutoRelease_<TYPE>& operator= (
const AutoRelease_<TYPE>&) =
delete;
498 TYPE& operator* ()
const
502 TYPE* operator->()
const
506 operator TYPE* ()
const
539 DOMImplementation& GetDOMIMPL_ ()
541 static constexpr XMLCh kDOMImplFeatureDeclaration_[] = u
"Core";
544 static DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation (kDOMImplFeatureDeclaration_);
551#if qStroika_Foundation_Debug_AssertionsChecked
552 bool ValidNewNodeName_ (
const String& n)
557 if (n.
find (
':') != wstring::npos) {
568 AutoRelease_<DOMLSOutput> theOutputDesc = GetDOMIMPL_ ().createLSOutput ();
569 theOutputDesc->setEncoding (XMLUni::fgUTF8EncodingString);
570 AutoRelease_<DOMLSSerializer> writer = GetDOMIMPL_ ().createLSSerializer ();
571 DOMConfiguration* dc = writer->getDomConfig ();
572 dc->setParameter (XMLUni::fgDOMWRTFormatPrettyPrint, options.fPrettyPrint);
573 dc->setParameter (XMLUni::fgDOMWRTBOM,
true);
574 class myOutputter :
public XMLFormatTarget {
581 virtual void writeChars (
const XMLByte*
const toWrite,
const XMLSize_t count, [[maybe_unused]] XMLFormatter*
const formatter)
override
583 fOut.
Write (span<const byte>{
reinterpret_cast<const byte*
> (toWrite), count});
585 virtual void flush ()
override
590 myOutputter dest{to};
591 theOutputDesc->setByteStream (&dest);
592 writer->write (node2Write, theOutputDesc);
595 DOMNode* RecursivelySetNamespace_ (DOMNode* n,
const XMLCh* namespaceURI)
599 switch (n->getNodeType ()) {
600 case DOMNode::ELEMENT_NODE: {
601 xercesc::DOMDocument* doc = n->getOwnerDocument ();
603 n = doc->renameNode (n, namespaceURI, n->getNodeName ());
605 for (DOMNode* child = n->getFirstChild (); child !=
nullptr; child = child->getNextSibling ()) {
606 child = RecursivelySetNamespace_ (child, namespaceURI);
612 constexpr XMLCh* kXerces2XMLDBDocumentKey_ =
nullptr;
615 String GetTextForDOMNode_ (
const DOMNode* node)
618 if (node->getNodeType () == DOMNode::COMMENT_NODE) {
634 using xercesc::DOMNode;
635 using xercesc::DOMText;
637 for (DOMNode* n = node->getFirstChild (); n !=
nullptr; n = n->getNextSibling ()) {
638 switch (n->getNodeType ()) {
639 case DOMNode::TEXT_NODE:
640 case DOMNode::CDATA_SECTION_NODE: {
641 DOMText* t (
static_cast<DOMText*
> (n));
646 case DOMNode::ELEMENT_NODE: {
657 DbgTrace (
"WARNING: GetTextForDOMNode_::BackupMode used"_f);
658 return node->getTextContent ();
661 Node::Ptr WrapXercesNodeInStroikaNode_ (DOMNode* n);
662 Element::Ptr WrapXercesNodeInStroikaNode_ (DOMElement* n);
666 class SubNodeIteratorOver_SiblingList_Rep_ :
public SubNodeIterator_::Rep,
670 SubNodeIteratorOver_SiblingList_Rep_ (DOMNode* nodeParent)
671 : fParentNode{nodeParent}
672 , fCachedMainListLen{static_cast<size_t> (-1)}
675 START_LIB_EXCEPTION_MAPPER_
677 fCurNode_ = nodeParent->getFirstChild ();
679 END_LIB_EXCEPTION_MAPPER_
681 virtual bool IsAtEnd ()
const override
683 return fCurNode_ ==
nullptr;
685 virtual void Next ()
override
687 Require (not IsAtEnd ());
689 START_LIB_EXCEPTION_MAPPER_
691 fCurNode_ = fCurNode_->getNextSibling ();
693 END_LIB_EXCEPTION_MAPPER_
695 virtual Node::Ptr Current ()
const override
697 return WrapXercesNodeInStroikaNode_ (fCurNode_);
699 virtual size_t GetLength ()
const override
701 if (fCachedMainListLen ==
static_cast<size_t> (-1)) {
703 START_LIB_EXCEPTION_MAPPER_
705 for (DOMNode* i = fParentNode->getFirstChild (); i !=
nullptr; (i = i->getNextSibling ()), ++n)
708 END_LIB_EXCEPTION_MAPPER_
709 fCachedMainListLen = n;
711 return fCachedMainListLen;
715 DOMNode* fParentNode{
nullptr};
716 DOMNode* fCurNode_{
nullptr};
717 mutable size_t fCachedMainListLen{};
723 NodeRep_ (DOMNode* n)
728 virtual const Providers::IDOMProvider* GetProvider ()
const override
730 return &Providers::Xerces::kDefaultProvider;
732 virtual bool Equals (
const IRep* rhs)
const override
736 return fNode_ ==
dynamic_cast<const NodeRep_*
> (rhs)->fNode_;
738 virtual Node::Type GetNodeType ()
const override
741 START_LIB_EXCEPTION_MAPPER_
743 switch (fNode_->getNodeType ()) {
744 case DOMNode::ELEMENT_NODE:
745 return Node::eElementNT;
746 case DOMNode::ATTRIBUTE_NODE:
747 return Node::eAttributeNT;
748 case DOMNode::TEXT_NODE:
749 return Node::eTextNT;
750 case DOMNode::COMMENT_NODE:
751 return Node::eCommentNT;
753 return Node::eOtherNT;
756 END_LIB_EXCEPTION_MAPPER_
761 Require (GetNodeType () == Node::eElementNT or GetNodeType () == Node::eAttributeNT);
762 START_LIB_EXCEPTION_MAPPER_
765 const XMLCh* n = fNode_->getNamespaceURI ();
766 return NameWithNamespace{n ==
nullptr ? optional<URI>{} :
URI{xercesString2String (n)}, fNode_->getNodeName ()};
768 END_LIB_EXCEPTION_MAPPER_
773#if qStroika_Foundation_Debug_AssertionsChecked
774 Require (ValidNewNodeName_ (name.fName));
776 START_LIB_EXCEPTION_MAPPER_
778 xercesc::DOMDocument* doc = fNode_->getOwnerDocument ();
780 fNode_ = doc->renameNode (
781 fNode_, name.fNamespace == nullopt ?
nullptr : name.fNamespace->As<
String> (kUseURIEncodingFlag_).As<u16string> ().c_str (),
782 name.fName.As<u16string> ().c_str ());
785 END_LIB_EXCEPTION_MAPPER_
787 virtual String GetValue ()
const override
790 START_LIB_EXCEPTION_MAPPER_
792 return GetTextForDOMNode_ (fNode_);
794 END_LIB_EXCEPTION_MAPPER_
796 virtual void SetValue (
const String& v)
override
799 START_LIB_EXCEPTION_MAPPER_
801 fNode_->setTextContent (v.empty () ?
nullptr : v.As<u16string> ().c_str ());
803 END_LIB_EXCEPTION_MAPPER_
805 virtual void DeleteNode ()
override
807 START_LIB_EXCEPTION_MAPPER_
809 DOMNode* selNode = fNode_;
811 DOMNode* parentNode = selNode->getParentNode ();
812 if (parentNode ==
nullptr) {
814 if (fNode_ !=
nullptr) {
815 const XMLCh* ln = selNode->getNodeName ();
817 DOMElement* de =
dynamic_cast<DOMElement*
> (fNode_);
818 de->removeAttribute (ln);
822 (void)parentNode->removeChild (selNode);
825 END_LIB_EXCEPTION_MAPPER_
827 virtual Node::Ptr GetParentNode ()
const override
830 START_LIB_EXCEPTION_MAPPER_
832 auto p = fNode_->getParentNode ();
833 return p ==
nullptr ? nullptr : WrapXercesNodeInStroikaNode_ (p);
835 END_LIB_EXCEPTION_MAPPER_
839 START_LIB_EXCEPTION_MAPPER_
841 DoWrite2Stream_ (fNode_, to, options);
843 END_LIB_EXCEPTION_MAPPER_
845 virtual xercesc::DOMNode* GetInternalTRep ()
override
856 struct ElementRep_ : Element::
IRep, Memory::InheritAndUseBlockAllocationIfAppropriate<ElementRep_, NodeRep_> {
858 ElementRep_ (DOMNode* n)
862 Require (n->getNodeType () == DOMNode::ELEMENT_NODE);
864 virtual Node::Type GetNodeType ()
const override
867 Assert (fNode_->getNodeType () == DOMNode::ELEMENT_NODE);
868 return Node::eElementNT;
870 virtual optional<String> GetAttribute (
const NameWithNamespace& attrName)
const override
873 START_LIB_EXCEPTION_MAPPER_
875 if (fNode_->getNodeType () == DOMNode::ELEMENT_NODE) {
876 DOMElement* elt = Debug::UncheckedDynamicCast<DOMElement*> (fNode_);
877 const XMLCh* s = attrName.fNamespace
878 ? elt->getAttributeNS (attrName.fNamespace->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str (),
879 attrName.fName.
As<u16string> ().c_str ())
880 : elt->getAttribute (attrName.fName.
As<u16string> ().c_str ());
888 END_LIB_EXCEPTION_MAPPER_
890 virtual void SetAttribute (
const NameWithNamespace& attrName,
const optional<String>& v)
override
892 Require (GetNodeType () == Node::eElementNT);
894 START_LIB_EXCEPTION_MAPPER_
896 DOMElement* element =
dynamic_cast<DOMElement*
> (fNode_);
918 element->setAttributeNS (attrName.fNamespace ? attrName.fNamespace->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str () : nullptr,
919 attrName.fName.As<u16string> ().c_str (), v->As<u16string> ().c_str ());
922 element->removeAttributeNS (
923 attrName.fNamespace ? attrName.fNamespace->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str () : nullptr,
924 attrName.fName.As<u16string> ().c_str ());
927 END_LIB_EXCEPTION_MAPPER_
931#if qStroika_Foundation_Debug_AssertionsChecked
932 Require (ValidNewNodeName_ (eltName.fName));
934 START_LIB_EXCEPTION_MAPPER_
936 xercesc::DOMDocument* doc = fNode_->getOwnerDocument ();
939 DOMNode* child = doc->createElementNS ((eltName.fNamespace == nullopt)
940 ? fNode_->getNamespaceURI ()
941 : eltName.fNamespace->As<
String> (kUseURIEncodingFlag_).As<u16string> ().c_str (),
942 eltName.fName.As<u16string> ().c_str ());
943 DOMNode* refChildNode =
nullptr;
944 if (afterNode ==
nullptr) {
947 refChildNode = fNode_->getFirstChild ();
950 refChildNode =
dynamic_cast<NodeRep_&
> (*afterNode.
GetRep ()).GetInternalTRep ()->getNextSibling ();
952 DOMNode* childx = fNode_->insertBefore (child, refChildNode);
954 return WrapXercesNodeInStroikaNode_ (childx);
956 END_LIB_EXCEPTION_MAPPER_
960#if qStroika_Foundation_Debug_AssertionsChecked
961 Require (ValidNewNodeName_ (eltName.fName));
963 START_LIB_EXCEPTION_MAPPER_
965 xercesc::DOMDocument* doc = fNode_->getOwnerDocument ();
967 if (eltName.fNamespace) {
968 u16string namespaceURI = eltName.fNamespace->As<
String> (kUseURIEncodingFlag_).As<u16string> ();
969 child = doc->createElementNS (namespaceURI.c_str (), eltName.fName.
As<u16string> ().c_str ());
972 const XMLCh* namespaceURI = fNode_->getNamespaceURI ();
973 child = doc->createElementNS (namespaceURI, eltName.fName.
As<u16string> ().c_str ());
975 DOMNode* childx = fNode_->appendChild (child);
977 return WrapXercesNodeInStroikaNode_ (childx);
979 END_LIB_EXCEPTION_MAPPER_
984 START_LIB_EXCEPTION_MAPPER_
986 return Traversal::CreateGenerator<Node::Ptr> (
987 [sni = SubNodeIterator_{MakeSharedPtr<SubNodeIteratorOver_SiblingList_Rep_> (fNode_)}] ()
mutable -> optional<Node::Ptr> {
988 if (sni.IsAtEnd ()) {
989 return optional<Node::Ptr>{};
996 END_LIB_EXCEPTION_MAPPER_
998 struct XPathQueryHelper_ {
999 optional<AutoRelease_<DOMXPathNSResolver>> resolver;
1000 DOMXPathResult::ResultType rt{};
1001 optional<AutoRelease_<DOMXPathExpression>> expr;
1004 xercesc::DOMDocument* doc = n->getOwnerDocument ();
1005 resolver.emplace (doc->createNSResolver (
nullptr));
1006 auto namespaceDefs = e.
GetOptions ().fNamespaces;
1007 if (namespaceDefs.GetDefaultNamespace ()) {
1008 (*resolver)->addNamespaceBinding (
1009 u
"", namespaceDefs.GetDefaultNamespace ()->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str ());
1012 (*resolver)->addNamespaceBinding (ni.fKey.As<u16string> ().c_str (),
1013 ni.fValue.As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str ());
1016 expr.emplace (doc->createExpression (e.
GetExpression ().
As<u16string> ().c_str (), *resolver));
1018 catch (
const xercesc::DOMXPathException&) {
1020 Execution::Throw (XPath::XPathExpressionNotSupported::kThe);
1022 switch (e.
GetOptions ().fResultTypeIndex.value_or (DOMXPathResult::ANY_TYPE)) {
1023 case XPath::ResultTypeIndex_v<Node::Ptr>: {
1026 rt = e.
GetOptions ().fOrdered ? DOMXPathResult::FIRST_ORDERED_NODE_TYPE : DOMXPathResult::ANY_UNORDERED_NODE_TYPE;
1028 else if (o.fSnapshot) {
1029 rt = e.
GetOptions ().fOrdered ? DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE : DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE;
1034 rt = e.
GetOptions ().fOrdered ? DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE : DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE;
1041 static optional<XPath::Result> ToResult_ (
const xercesc::DOMXPathResult* r)
1044 switch (r->getResultType ()) {
1045 case DOMXPathResult::NUMBER_TYPE:
1046 return XPath::Result{r->getNumberValue ()};
1047 case DOMXPathResult::BOOLEAN_TYPE:
1048 return XPath::Result{r->getBooleanValue ()};
1049 case DOMXPathResult::STRING_TYPE:
1050 return XPath::Result{xercesString2String (r->getStringValue ())};
1051 case DOMXPathResult::ANY_UNORDERED_NODE_TYPE:
1052 case DOMXPathResult::FIRST_ORDERED_NODE_TYPE:
1053 case DOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE:
1054 case DOMXPathResult::ORDERED_NODE_ITERATOR_TYPE:
1055 case DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE:
1056 case DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE: {
1057 auto n = r->getNodeValue ();
1058 return n ==
nullptr ? optional<XPath::Result>{} : XPath::Result{
Node::Ptr{WrapXercesNodeInStroikaNode_ (n)}};
1068 if constexpr (
false) {
1070 for (
auto i : Lookup (e)) {
1075 START_LIB_EXCEPTION_MAPPER_
1077 XPathQueryHelper_ xpHelp{fNode_, e,
true};
1078 AutoRelease_<xercesc::DOMXPathResult> r = (*xpHelp.expr)->evaluate (fNode_, xpHelp.rt,
nullptr);
1079 return XPathQueryHelper_::ToResult_ (r);
1081 END_LIB_EXCEPTION_MAPPER_
1086 XPath::Expression::Options e2o = e.
GetOptions ();
1087 e2o.fSnapshot =
false;
1090 shared_ptr<XPathQueryHelper_> xpHelp = MakeSharedPtr<XPathQueryHelper_> (fNode_, e,
false);
1091 shared_ptr<AutoRelease_<xercesc::DOMXPathResult>> r =
1092 MakeSharedPtr<AutoRelease_<xercesc::DOMXPathResult>> ((*xpHelp->expr)->evaluate (fNode_, xpHelp->rt,
nullptr));
1094 if (xpHelp->rt == DOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE or xpHelp->rt == DOMXPathResult::ORDERED_NODE_ITERATOR_TYPE) [[unlikely]] {
1095 return Traversal::CreateGenerator<XPath::Result> ([xpHelp, r, firstTime =
true] ()
mutable -> optional<XPath::Result> {
1098 return XPathQueryHelper_::ToResult_ (*r);
1100 if ((*r)->iterateNext () ==
false) {
1103 return XPathQueryHelper_::ToResult_ (*r);
1106 if (xpHelp->rt == DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE or xpHelp->rt == DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE) [[likely]] {
1107 return Traversal::CreateGenerator<XPath::Result> ([xpHelp, r, snapIdx = 0] ()
mutable -> optional<XPath::Result> {
1108 if (not(*r)->snapshotItem (snapIdx)) {
1112 return XPathQueryHelper_::ToResult_ (*r);
1121 START_LIB_EXCEPTION_MAPPER_
1123 for (DOMNode* i = fNode_->getFirstChild (); i !=
nullptr; i = i->getNextSibling ()) {
1124 if (i->getNodeType () == DOMNode::ELEMENT_NODE) {
1125 DOMElement* elt = Debug::UncheckedDynamicCast<DOMElement*> (i);
1126 const XMLCh* s = elt->getAttribute (u
"id");
1128 if (CString::Equals (s,
id.As<u16string> ().c_str ())) {
1129 return WrapXercesNodeInStroikaNode_ (elt);
1135 END_LIB_EXCEPTION_MAPPER_
1138 DISABLE_COMPILER_MSC_WARNING_END (4250)
1142 inline void MakeXMLDoc_ (shared_ptr<xercesc::DOMDocument>& newXMLDoc)
1144 Require (newXMLDoc ==
nullptr);
1145 newXMLDoc = shared_ptr<xercesc::DOMDocument> (GetDOMIMPL_ ().createDocument (0,
nullptr, 0));
1146 newXMLDoc->setXmlStandalone (
true);
1151 class MyMaybeSchemaDOMParser_ {
1153 Map2StroikaExceptionsErrorReporter_ myErrReporter;
1154 shared_ptr<XercesDOMParser> fParser;
1157 MyMaybeSchemaDOMParser_ () =
delete;
1158 MyMaybeSchemaDOMParser_ (
const MyMaybeSchemaDOMParser_&) =
delete;
1159 MyMaybeSchemaDOMParser_ (
const Schema::Ptr& schema)
1162 shared_ptr<IXercesSchemaRep> accessSchema = dynamic_pointer_cast<IXercesSchemaRep> (schema.GetRep ());
1163 if (accessSchema !=
nullptr) {
1164 fParser = MakeSharedPtr<XercesDOMParser> (
nullptr, XMLPlatformUtils::fgMemoryManager, accessSchema->GetCachedGrammarPool ());
1165 fParser->cacheGrammarFromParse (
false);
1166 fParser->useCachedGrammarInParse (
true);
1167 fParser->setDoSchema (
true);
1168 fParser->setValidationScheme (AbstractDOMParser::Val_Always);
1169 fParser->setValidationSchemaFullChecking (
true);
1170 fParser->setIdentityConstraintChecking (
true);
1173 fParser = MakeSharedPtr<XercesDOMParser> ();
1175 fParser->setDoNamespaces (
true);
1176 fParser->setErrorHandler (&myErrReporter);
1184 fParser->setLoadExternalDTD (
false);
1188 fParser->setLoadSchema (
false);
1195 Element::Ptr WrapXercesNodeInStroikaNode_ (DOMElement* n);
1198 struct DocRep_ : DataExchange::XML::DOM::Document::IRep {
1199#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1200 static inline atomic<unsigned int> sLiveCnt{0};
1210 [[maybe_unused]]
int ignoreMe = 0;
1211 START_LIB_EXCEPTION_MAPPER_
1213 MakeXMLDoc_ (fXMLDoc);
1214 fXMLDoc->setUserData (kXerces2XMLDBDocumentKey_,
this,
nullptr);
1215 if (in !=
nullptr) {
1216 MyMaybeSchemaDOMParser_ myDOMParser{schema};
1217 myDOMParser.fParser->parse (StdIStream_InputSource_{in, u
"XMLDB"});
1219 fXMLDoc = shared_ptr<xercesc::DOMDocument>{myDOMParser.fParser->adoptDocument ()};
1220 fXMLDoc->setXmlStandalone (
true);
1221 fXMLDoc->setUserData (kXerces2XMLDBDocumentKey_,
this,
nullptr);
1224 END_LIB_EXCEPTION_MAPPER_
1225#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1229 DocRep_ (
const DocRep_& from)
1231 START_LIB_EXCEPTION_MAPPER_
1233 fXMLDoc = shared_ptr<xercesc::DOMDocument> (
dynamic_cast<xercesc::DOMDocument*
> (from.fXMLDoc->cloneNode (
true)));
1234 fXMLDoc->setXmlStandalone (
true);
1235 fXMLDoc->setUserData (kXerces2XMLDBDocumentKey_,
this,
nullptr);
1237 END_LIB_EXCEPTION_MAPPER_
1239#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1245#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1246 Assert (sLiveCnt > 0);
1250 virtual const Providers::IDOMProvider* GetProvider ()
const override
1252 return &Providers::Xerces::kDefaultProvider;
1254 virtual bool GetStandalone ()
const override
1257 return fXMLDoc->getXmlStandalone ();
1259 virtual void SetStandalone (
bool standalone)
override
1262 fXMLDoc->setXmlStandalone (standalone);
1268 START_LIB_EXCEPTION_MAPPER_
1269 return Traversal::CreateGenerator<Node::Ptr> (
1270 [sni = SubNodeIterator_{MakeSharedPtr<SubNodeIteratorOver_SiblingList_Rep_> (fXMLDoc.get ())}] ()
mutable -> optional<Node::Ptr> {
1271 if (sni.IsAtEnd ()) {
1272 return optional<Node::Ptr>{};
1278 END_LIB_EXCEPTION_MAPPER_
1282 DOMElement* n = newEltName.fNamespace == nullopt
1283 ? fXMLDoc->createElement (newEltName.fName.
As<u16string> ().c_str ())
1284 : fXMLDoc->createElementNS (newEltName.fNamespace->As<
String> (kUseURIEncodingFlag_).
As<u16string> ().c_str (),
1285 newEltName.fName.
As<u16string> ().c_str ());
1287 DOMElement* oldRoot = fXMLDoc->getDocumentElement ();
1288 if (oldRoot ==
nullptr) {
1289 (void)fXMLDoc->insertBefore (n,
nullptr);
1292 (void)fXMLDoc->replaceChild (n, oldRoot);
1311 Assert (fXMLDoc->getDocumentElement () == n);
1313 if (childrenInheritNS and newEltName.fNamespace) {
1323 START_LIB_EXCEPTION_MAPPER_
1325 DoWrite2Stream_ (fXMLDoc.get (), to, options);
1327 END_LIB_EXCEPTION_MAPPER_
1329#if qCompilerAndStdLib_arm_asan_FaultStackUseAfterScope_Buggy
1330 Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS
1333 Validate (
const Schema::Ptr& schema)
const override
1338 START_LIB_EXCEPTION_MAPPER_
1345 DOMNode* docNode = fXMLDoc->getDocumentElement ();
1346 if (docNode ==
nullptr) [[unlikely]] {
1349 optional<URI> docURI = docNode->getNamespaceURI () ==
nullptr ? optional<URI>{} : docNode->getNamespaceURI ();
1352 Format (
"Wrong document namespace (found '{}' and expected '{}')"_f, docURI, schema.
GetTargetNamespace ()), 0, 0, 0});
1357 MemBufFormatTarget destination;
1359 AutoRelease_<DOMLSOutput> theOutputDesc = GetDOMIMPL_ ().createLSOutput ();
1360 theOutputDesc->setEncoding (XMLUni::fgUTF8EncodingString);
1361 AutoRelease_<DOMLSSerializer> writer = GetDOMIMPL_ ().createLSSerializer ();
1362 theOutputDesc->setByteStream (&destination);
1363 theOutputDesc->setEncoding (XMLUni::fgUTF8EncodingString);
1364 Assert (fXMLDoc->getXmlStandalone ());
1365 writer->write (fXMLDoc.get (), theOutputDesc);
1367 MemBufInputSource readReadSrc{destination.getRawBuffer (), destination.getLen (), u
"tmp"};
1368 readReadSrc.setEncoding (XMLUni::fgUTF8EncodingString);
1369 shared_ptr<IXercesSchemaRep> accessSchema = dynamic_pointer_cast<IXercesSchemaRep> (schema.GetRep ());
1372 shared_ptr<SAX2XMLReader> parser = shared_ptr<SAX2XMLReader> (
1373 XMLReaderFactory::createXMLReader (XMLPlatformUtils::fgMemoryManager, accessSchema->GetCachedGrammarPool ()));
1374 SetupCommonParserFeatures_ (*parser,
true);
1375 Map2StroikaExceptionsErrorReporter_ myErrorReporter;
1376 parser->setErrorHandler (&myErrorReporter);
1377 parser->parse (readReadSrc);
1382 if constexpr (qDumpXMLOnValidationError_) {
1383#if !qCompilerAndStdLib_arm_asan_FaultStackUseAfterScope_Buggy
1389 DbgTrace (
"Error validating - so writing out temporary file = '{}'"_f, tmpFileName);
1390 Write (IO::FileSystem::FileOutputStream::New (tmpFileName),
SerializationOptions{.fPrettyPrint =
true, .fIndent = 4});
1392 ValidateFile (tmpFileName, schema);
1396 size_t idx = tmpFileNameStr.
find (
".xml");
1397 String newTmpFile = tmpFileNameStr.
substr (0, idx) +
"_MSG.txt";
1399 msgOut <<
"Reason:" << vf.GetDetails () << endl;
1400 optional<unsigned int> lineNum;
1401 optional<unsigned int> colNumber;
1402 optional<uint64_t> fileOffset;
1403 vf.GetPositionInfo (&lineNum, &colNumber, &fileOffset);
1405 msgOut <<
"Line:" << *lineNum << endl;
1408 msgOut <<
"Col: " << *colNumber << endl;
1411 msgOut <<
"FilePos: " << *fileOffset << endl;
1418 Execution::ReThrow ();
1421 END_LIB_EXCEPTION_MAPPER_
1423 shared_ptr<xercesc::DOMDocument> fXMLDoc;
1429 Node::Ptr WrapXercesNodeInStroikaNode_ (DOMNode* n)
1432 if (n->getNodeType () == DOMNode::ELEMENT_NODE) {
1433 return Node::Ptr{MakeSharedPtr<ElementRep_> (n)};
1436 return Node::Ptr{MakeSharedPtr<NodeRep_> (n)};
1439 Element::Ptr WrapXercesNodeInStroikaNode_ (DOMElement* n)
1451String Providers::Xerces::xercesString2String (
const XMLCh* s,
const XMLCh* e)
1453 if constexpr (same_as<XMLCh, char16_t>) {
1454 return String{span{s, e}};
1458 if constexpr (
sizeof (XMLCh) ==
sizeof (
char16_t)) {
1459 return String{span{
reinterpret_cast<const char16_t*
> (s),
reinterpret_cast<const char16_t*
> (e)}};
1461 else if constexpr (
sizeof (XMLCh) ==
sizeof (
char32_t)) {
1462 return String{span{
reinterpret_cast<const char32_t*
> (s),
reinterpret_cast<const char32_t*
> (e)}};
1470String Providers::Xerces::xercesString2String (
const XMLCh* t)
1472 if constexpr (same_as<XMLCh, char16_t>) {
1477 if constexpr (
sizeof (XMLCh) ==
sizeof (
char16_t)) {
1478 return String{
reinterpret_cast<const char16_t*
> (t)};
1480 else if constexpr (
sizeof (XMLCh) ==
sizeof (
char32_t)) {
1481 return String{
reinterpret_cast<const char32_t*
> (t)};
1494Providers::Xerces::Provider::Provider ()
1497#if qStroika_Foundation_Debug_AssertionsChecked
1498 static unsigned int sNProvidersCreated_{0};
1499 Assert (++sNProvidersCreated_ == 1);
1501#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1502 fUseXercesMemoryManager_ =
new MyXercesMemMgr_{};
1503 XMLPlatformUtils::Initialize (XMLUni::fgXercescDefaultLocale, 0, 0, fUseXercesMemoryManager_);
1505 XMLPlatformUtils::Initialize (XMLUni::fgXercescDefaultLocale, 0, 0);
1509Providers::Xerces::Provider::~Provider ()
1512 XMLPlatformUtils::Terminate ();
1513#if qStroika_Foundation_DataExchange_XML_DebugMemoryAllocations
1514 Require (SchemaRep_::sLiveCnt == 0);
1515 Require (DocRep_::sLiveCnt == 0);
1516 delete fUseXercesMemoryManager_;
1522 return MakeSharedPtr<SchemaRep_> (schemaData, resolver);
1526 const Schema::Ptr& schemaToValidateAgainstWhileReading)
const
1528 return MakeSharedPtr<DocRep_> (in, schemaToValidateAgainstWhileReading);
1534 SAX2PrintHandlers_ handler{callback};
1535 shared_ptr<IXercesSchemaRep> accessSchema;
1536 if (schema !=
nullptr) {
1537 accessSchema = dynamic_pointer_cast<IXercesSchemaRep> (schema.GetRep ());
1539 shared_ptr<SAX2XMLReader> parser{XMLReaderFactory::createXMLReader (
1540 XMLPlatformUtils::fgMemoryManager, accessSchema ==
nullptr ?
nullptr : accessSchema->GetCachedGrammarPool ())};
1541 SetupCommonParserFeatures_ (*parser, accessSchema !=
nullptr);
1542 parser->setContentHandler (&handler);
1543 Map2StroikaExceptionsErrorReporter_ mErrorReproter_;
1544 parser->setErrorHandler (&mErrorReproter_);
1545 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 ThrowIfNull(const Private_::ConstVoidStar &p, const HRESULT &hr)
Template specialization for ThrowIfNull (), for thing being thrown HRESULT - really throw HRESULTErro...