// GroveNode.cxx #include "stdafx.h" #include "groveoa.h" #include "config.h" #include "GroveNode.h" #include "Boolean.h" #include "Node.h" #include "LocNode.h" #include "PointerTable.h" #include "NamedResource.h" #include "Ptr.h" #include "Owner.h" #include "ExtendEntityManager.h" #include "StorageManager.h" #include #include #include #include #ifdef SP_NO_STD_NAMESPACE #define std /* as nothing */ #endif #define TRY try { #define CATCH } catch (std::bad_alloc) { return E_OUTOFMEMORY; } // A NULL BSTR is supposed to be equivalent to an empty BSTR // but not everybody gets this right (perl build 306, for example) inline BSTR makeEmptyBSTR() { return ::SysAllocStringLen(0, 0); } using GROVE_NAMESPACE::NodePtr; using GROVE_NAMESPACE::NodeListPtr; using GROVE_NAMESPACE::NamedNodeListPtr; using GROVE_NAMESPACE::GroveString; using GROVE_NAMESPACE::GroveStringList; using GROVE_NAMESPACE::GroveStringListPtr; using GROVE_NAMESPACE::ConstGroveStringListIter; using GROVE_NAMESPACE::GroveChar; using GROVE_NAMESPACE::accessOK; using GROVE_NAMESPACE::accessNull; using GROVE_NAMESPACE::accessNotInClass; using GROVE_NAMESPACE::SdataMapper; class NodeTable; typedef SP_NAMESPACE::Ptr NodeTablePtr; class ATL_NO_VTABLE CStringList : public CComObjectRoot, public IDispatchImpl { public: CStringList() { } BEGIN_COM_MAP(CStringList) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(StringList) END_COM_MAP() STDMETHOD(get_Count)(long *); STDMETHOD(get_Item)(long, BSTR *retval); STDMETHOD(First)(BSTR *retval); STDMETHOD(Rest)(StringList **); static HRESULT make(const GroveStringListPtr &, StringList **); private: GroveStringListPtr sl_; }; class CNodeBase { public: virtual ~CNodeBase(); void init(const NodePtr &nd, const NodeTablePtr &); static HRESULT make(const NodePtr &, const NodeTablePtr &, Node **); static BSTR makeBSTR(const GroveString &); static const GROVE_NAMESPACE::Node &key(const CNodeBase &obj) { return *obj.nd_; } static unsigned long hash(const GROVE_NAMESPACE::Node &nd) { return nd.hash(); } virtual Node *asNode() = 0; HRESULT internalGetStoragePos(StoragePos **); protected: CNodeBase() { } NodePtr nd_; NodeTablePtr table_; }; class NodeTable : public SP_NAMESPACE::Resource, public SP_NAMESPACE::PointerTable { public: NodeTable(SP_NAMESPACE::Owner &thd) { thd.swap(thread_); } private: SP_NAMESPACE::Owner thread_; }; class ATL_NO_VTABLE CNodeList : public CComObjectRoot, public IDispatchImpl { public: CNodeList() { } BEGIN_COM_MAP(CNodeList) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(NodeList) END_COM_MAP() STDMETHOD(get_Count)(long *); STDMETHOD(get_Item)(long, Node **); STDMETHOD(get__NewEnum)(IUnknown **); STDMETHOD(First)(Node **); STDMETHOD(Rest)(NodeList **); static HRESULT make(const NodeListPtr &, const NodeTablePtr &, NodeList **); private: NodeListPtr nl_; NodeTablePtr table_; }; class ATL_NO_VTABLE CChunkNodeList : public CComObjectRoot, public IDispatchImpl { public: CChunkNodeList() { } BEGIN_COM_MAP(CChunkNodeList) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(NodeList) END_COM_MAP() STDMETHOD(get_Count)(long *); STDMETHOD(get_Item)(long, Node **); STDMETHOD(get__NewEnum)(IUnknown **); STDMETHOD(First)(Node **); STDMETHOD(Rest)(NodeList **); static HRESULT make(const NodeListPtr &, const NodeTablePtr &, NodeList **); private: NodeListPtr nl_; NodeTablePtr table_; }; class ATL_NO_VTABLE CNamedNodeList : public CComObjectRoot, public IDispatchImpl { public: CNamedNodeList() { } BEGIN_COM_MAP(CNamedNodeList) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(NamedNodeList) END_COM_MAP() STDMETHOD(get_Count)(long *); STDMETHOD(get_Item)(BSTR, Node **); STDMETHOD(get__NewEnum)(IUnknown **); STDMETHOD(get_NodeList)(NodeList **); STDMETHOD(Normalize)(BSTR, BSTR *); STDMETHOD(NodeName)(Node *, BSTR *); static HRESULT make(const NamedNodeListPtr &, const NodeTablePtr &, NamedNodeList **); private: NamedNodeListPtr nnl_; NodeTablePtr table_; }; class ATL_NO_VTABLE CStoragePos : public CComObjectRoot, public IDispatchImpl { public: CStoragePos() { } BEGIN_COM_MAP(CStoragePos) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(StoragePos) END_COM_MAP() STDMETHOD(get_StorageManagerName)(BSTR *retval) { const char *s = loc_.storageObjectSpec->storageManager->type(); BSTR tem = ::SysAllocStringLen(0, strlen(s)); *retval = tem; if (!tem) return E_OUTOFMEMORY; while (*s) *tem++ = *s++; return NOERROR; } STDMETHOD(get_StorageObjectId)(BSTR *retval) { const SP_NAMESPACE::StringC &id = loc_.actualStorageId; CComBSTR tem(id.size(), id.data()); *retval = tem.Detach(); return *retval ? NOERROR : E_OUTOFMEMORY; } STDMETHOD(get_LineNumber)(long *retval) { *retval = loc_.lineNumber; if (*retval < 0) *retval = 0; return NOERROR; } STDMETHOD(get_ColumnNumber)(long *retval) { *retval = loc_.columnNumber; if (*retval < 0) *retval = 0; return NOERROR; } STDMETHOD(get_ByteIndex)(long *retval) { *retval = loc_.byteIndex + 1; return NOERROR; } STDMETHOD(get_CharacterIndex)(long *retval) { *retval = loc_.storageObjectOffset + 1; return NOERROR; } static HRESULT make(const SP_NAMESPACE::ExternalInfo *, SP_NAMESPACE::Offset, const NodePtr &, StoragePos **); private: SP_NAMESPACE::StorageObjectLocation loc_; NodePtr nd_; }; #define NODE_PROP2(xfunc, ifunc) \ STDMETHOD(xfunc)(Node **retval) { \ TRY \ *retval = 0; \ NodePtr nd; \ if (nd_->ifunc(nd) == accessOK) \ return make(nd, table_, retval); \ return NOERROR; \ CATCH \ } #define NODE_PROP(Name) NODE_PROP2(get_##Name, get##Name) #define DERIVED_NODE_PROP2(xfunc, ifunc, cls) \ STDMETHOD(xfunc)(cls##Node **retval) { \ TRY \ *retval = 0; \ NodePtr nd; \ if (nd_->ifunc(nd) == accessOK) { \ Node *base; \ HRESULT hres = make(nd, table_, &base); \ *retval = (cls##Node *)base; \ return hres; \ } \ return NOERROR; \ CATCH \ } #define DERIVED_NODE_PROP(Name, cls) DERIVED_NODE_PROP2(get_##Name, get##Name, cls) #define NODE_LIST_PROP2(xfunc, ifunc) \ STDMETHOD(xfunc)(NodeList **retval) { \ TRY \ *retval = 0; \ NodeListPtr nl; \ if (nd_->ifunc(nl) == accessOK) \ return CNodeList::make(nl, table_, retval); \ return NOERROR; \ CATCH \ } #define NODE_LIST_PROP(Name) NODE_LIST_PROP2(get_##Name, get##Name) #define STRING_LIST_PROP2(xfunc, ifunc) \ STDMETHOD(xfunc)(StringList **retval) { \ TRY \ *retval = 0; \ GroveStringListPtr sl; \ if (nd_->ifunc(sl) == accessOK) \ return CStringList::make(sl, retval); \ return NOERROR; \ CATCH \ } #define STRING_LIST_PROP(Name) STRING_LIST_PROP2(get_##Name, get##Name) #define CHUNK_NODE_LIST_PROP2(xfunc, ifunc) \ STDMETHOD(xfunc)(NodeList **retval) { \ TRY \ *retval = 0; \ NodeListPtr nl; \ if (nd_->ifunc(nl) == accessOK) \ return CChunkNodeList::make(nl, table_, retval); \ return NOERROR; \ CATCH \ } #define NAMED_NODE_LIST_PROP2(xfunc, ifunc) \ STDMETHOD(xfunc)(NamedNodeList **retval) { \ TRY \ *retval = 0; \ NamedNodeListPtr nnl; \ if (nd_->ifunc(nnl) == accessOK) \ return CNamedNodeList::make(nnl, table_, retval); \ return NOERROR; \ CATCH \ } #define NAMED_NODE_LIST_PROP(Name) \ NAMED_NODE_LIST_PROP2(get_##Name, get##Name) #define BOOL_PROP2(xfunc, ifunc) \ STDMETHOD(xfunc)(VARIANT_BOOL *retval) { \ TRY \ bool b; \ if (nd_->ifunc(b) == accessOK) \ *retval = b ? -1 : 0; \ else \ *retval = 0; \ return NOERROR; \ CATCH \ } #define BOOL_PROP(Name) BOOL_PROP2(get_##Name, get##Name) #define INTEGER_PROP2(xfunc, ifunc) \ STDMETHOD(xfunc)(long *retval) { \ TRY \ long l; \ if (nd_->ifunc(l) == accessOK) \ *retval = l; \ else \ *retval = 0; \ return NOERROR; \ CATCH \ } #define INTEGER_PROP(Name) INTEGER_PROP2(get_##Name, get##Name) #define STRING_PROP2(xfunc, ifunc) \ STDMETHOD(xfunc)(BSTR *retval) { \ TRY \ *retval = 0; \ GroveString str; \ if (nd_->ifunc(str) == accessOK) \ *retval = makeBSTR(str); \ else \ *retval = makeEmptyBSTR(); \ return NOERROR; \ CATCH \ } #define STRING_PROP(Name) STRING_PROP2(get_##Name, get##Name) #define ENUM_PROP2(enumClass, xfunc, ifunc) \ STDMETHOD(xfunc)(enumClass *retval) { \ GROVE_NAMESPACE::Node::##enumClass##::Enum type; \ if (nd_->ifunc(type) == accessOK) \ *retval = enumClass##(type); \ return NOERROR; \ } #define ENUM_PROP(Name) ENUM_PROP2(Name, get_##Name, get##Name) #define NULL_STRING_PROP(Name) \ STRING_PROP(Name) \ STDMETHOD(get_##Name##Null)(VARIANT_BOOL *retval) { \ TRY \ *retval = 0; \ GroveString str; \ if (nd_->get##Name(str) == accessNull) \ *retval = -1; \ return NOERROR; \ CATCH \ } template class INodeImpl : public IDispatchImpl, public CNodeBase { public: NODE_PROP(Parent) NODE_PROP(Origin) NODE_PROP(GroveRoot) NODE_PROP(TreeRoot) NODE_LIST_PROP2(get_Children, children) CHUNK_NODE_LIST_PROP2(get_ChunkChildren, children) NODE_PROP2(FirstChild, firstChild) NODE_PROP2(NextSibling, nextSibling) NODE_PROP2(NextChunkSibling, nextChunkSibling) STDMETHOD(get_Class)(NodeClass *retval) { TRY *retval = nodeClass; return NOERROR; CATCH } STDMETHOD(get_SiblingIndex)(long *retval) { TRY unsigned long n; if (nd_->siblingsIndex(n) == accessOK) *retval = n + 1; else *retval = 0; return NOERROR; CATCH } Node *asNode() { return this; } STDMETHOD(get_StoragePos)(StoragePos **retval) { return internalGetStoragePos(retval); } }; class ATL_NO_VTABLE CElementNode : public CComObjectRoot, public INodeImpl { public: CElementNode() { } BEGIN_COM_MAP(CElementNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(ElementNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Gi) NAMED_NODE_LIST_PROP(Attributes) STRING_PROP(Id) NODE_LIST_PROP(Content) CHUNK_NODE_LIST_PROP2(get_ChunkContent, getContent) BOOL_PROP(Included) BOOL_PROP(MustOmitEndTag) DERIVED_NODE_PROP(ElementType, ElementType) }; class ATL_NO_VTABLE CAttributeAssignmentNode : public CComObjectRoot, public INodeImpl { public: CAttributeAssignmentNode() { } BEGIN_COM_MAP(CAttributeAssignmentNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(AttributeAssignmentNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Name) BOOL_PROP(Implied) NODE_LIST_PROP(Value) CHUNK_NODE_LIST_PROP2(get_ChunkValue, getValue) STDMETHOD(get_TokenSep)(long *retval) { TRY GroveChar ch; if (nd_->getTokenSep(ch) == accessOK) *retval = ch; else *retval = -1; return NOERROR; CATCH } STDMETHOD(get_StringValue)(BSTR *retval) { TRY *retval = 0; bool implied; if (nd_->getImplied(implied) == accessOK && implied) { *retval = makeEmptyBSTR(); return NOERROR; } GroveString tokens; if (nd_->tokens(tokens) == accessOK) { *retval = makeBSTR(tokens); return NOERROR; } NodePtr first; if (nd_->firstChild(first) == accessOK) { size_t len = 0; NodePtr tem(first); do { GroveString chunk; if (tem->charChunk(SdataMapper(), chunk) == accessOK) len += chunk.size(); } while (tem.assignNextChunkSibling() == accessOK); GroveChar *p = ::SysAllocStringLen(0, len); if (!p) return E_OUTOFMEMORY; *retval = p; tem = first; do { GroveString chunk; if (tem->charChunk(SdataMapper(), chunk) == accessOK) { memcpy(p, chunk.data(), chunk.size()*sizeof(*p)); p += chunk.size(); } } while (tem.assignNextChunkSibling() == accessOK); } return NOERROR; CATCH } DERIVED_NODE_PROP(AttributeDef, AttributeDef) }; class ATL_NO_VTABLE CAttributeValueTokenNode : public CComObjectRoot, public INodeImpl { public: CAttributeValueTokenNode() { } BEGIN_COM_MAP(CAttributeValueTokenNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(AttributeValueTokenNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Token) DERIVED_NODE_PROP(Referent, Element) DERIVED_NODE_PROP(Entity, Entity) DERIVED_NODE_PROP(Notation, Notation) }; class ATL_NO_VTABLE CSgmlDocumentNode : public CComObjectRoot, public INodeImpl { public: CSgmlDocumentNode() { } BEGIN_COM_MAP(CSgmlDocumentNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(SgmlDocumentNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() DERIVED_NODE_PROP(DocumentElement, Element) DERIVED_NODE_PROP(SgmlConstants, SgmlConstants) NULL_STRING_PROP(ApplicationInfo) NODE_LIST_PROP(Prolog) NODE_LIST_PROP(Epilog) NAMED_NODE_LIST_PROP(Elements) NAMED_NODE_LIST_PROP(Entities) NAMED_NODE_LIST_PROP(DefaultedEntities) NAMED_NODE_LIST_PROP(DoctypesAndLinktypes) DERIVED_NODE_PROP(GoverningDoctype, DocumentType) NODE_LIST_PROP(Messages) }; class ATL_NO_VTABLE CDataCharNode : public CComObjectRoot, public INodeImpl { public: CDataCharNode() { } BEGIN_COM_MAP(CDataCharNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(DataCharNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STDMETHOD(get_Char)(long *); STDMETHOD(get_NonSgml)(long *); STDMETHOD(get_CharChunk)(BSTR *); }; class ATL_NO_VTABLE CSgmlConstantsNode : public CComObjectRoot, public INodeImpl { public: CSgmlConstantsNode() { } BEGIN_COM_MAP(CSgmlConstantsNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(SgmlConstantsNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() }; class ATL_NO_VTABLE CPiNode : public CComObjectRoot, public INodeImpl { public: CPiNode() { } BEGIN_COM_MAP(CPiNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(PiNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(SystemData) DERIVED_NODE_PROP(Entity, Entity) STRING_PROP(EntityName) }; class ATL_NO_VTABLE CSdataNode : public CComObjectRoot, public INodeImpl { public: CSdataNode() { } BEGIN_COM_MAP(CSdataNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(SdataNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(SystemData) DERIVED_NODE_PROP(Entity, Entity) STRING_PROP(EntityName) }; class ATL_NO_VTABLE CDocumentTypeNode : public CComObjectRoot, public INodeImpl { public: CDocumentTypeNode() { } BEGIN_COM_MAP(CDocumentTypeNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(DocumentTypeNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Name) BOOL_PROP(Governing) NAMED_NODE_LIST_PROP(GeneralEntities) NAMED_NODE_LIST_PROP(Notations) NAMED_NODE_LIST_PROP(ElementTypes) NAMED_NODE_LIST_PROP(ParameterEntities) DERIVED_NODE_PROP(DefaultEntity, DefaultEntity) }; class ATL_NO_VTABLE CEntityNode : public CComObjectRoot, public INodeImpl { public: CEntityNode() { } BEGIN_COM_MAP(CEntityNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(EntityNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Name) NULL_STRING_PROP(Text) DERIVED_NODE_PROP(Notation, Notation) STRING_PROP(NotationName) BOOL_PROP(Defaulted) NAMED_NODE_LIST_PROP(Attributes) DERIVED_NODE_PROP(ExternalId, ExternalId) ENUM_PROP(EntityType) }; class ATL_NO_VTABLE CDefaultEntityNode : public CComObjectRoot, public INodeImpl { public: CDefaultEntityNode() { } BEGIN_COM_MAP(CDefaultEntityNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(DefaultEntityNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Name) NULL_STRING_PROP(Text) DERIVED_NODE_PROP(Notation, Notation) STRING_PROP(NotationName) NAMED_NODE_LIST_PROP(Attributes) DERIVED_NODE_PROP(ExternalId, ExternalId) ENUM_PROP(EntityType) }; class ATL_NO_VTABLE CNotationNode : public CComObjectRoot, public INodeImpl { public: CNotationNode() { } BEGIN_COM_MAP(CNotationNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(NotationNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Name) DERIVED_NODE_PROP(ExternalId, ExternalId) NAMED_NODE_LIST_PROP(AttributeDefs) }; class ATL_NO_VTABLE CExternalIdNode : public CComObjectRoot, public INodeImpl { public: CExternalIdNode() { } BEGIN_COM_MAP(CExternalIdNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(ExternalIdNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() NULL_STRING_PROP(PublicId) NULL_STRING_PROP(SystemId) STRING_PROP(GeneratedSystemId) }; class ATL_NO_VTABLE CExternalDataNode : public CComObjectRoot, public INodeImpl { public: CExternalDataNode() { } BEGIN_COM_MAP(CExternalDataNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(ExternalDataNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() DERIVED_NODE_PROP(Entity, Entity) STRING_PROP(EntityName) }; class ATL_NO_VTABLE CSubdocNode : public CComObjectRoot, public INodeImpl { public: CSubdocNode() { } BEGIN_COM_MAP(CSubdocNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(SubdocNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() DERIVED_NODE_PROP(Entity, Entity) STRING_PROP(EntityName) }; class ATL_NO_VTABLE CElementTypeNode : public CComObjectRoot, public INodeImpl { public: CElementTypeNode() { } BEGIN_COM_MAP(CElementTypeNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(ElementTypeNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Gi) NAMED_NODE_LIST_PROP(AttributeDefs) ENUM_PROP(ContentType) STRING_LIST_PROP(Exclusions) STRING_LIST_PROP(Inclusions) DERIVED_NODE_PROP(ModelGroup, ModelGroup) BOOL_PROP(OmitEndTag) BOOL_PROP(OmitStartTag) }; class ATL_NO_VTABLE CAttributeDefNode : public CComObjectRoot, public INodeImpl { public: CAttributeDefNode() { } BEGIN_COM_MAP(CElementTypeNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(ElementTypeNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Name) ENUM_PROP(DeclValueType) ENUM_PROP(DefaultValueType) STRING_LIST_PROP(Tokens) INTEGER_PROP(CurrentAttributeIndex) NODE_LIST_PROP(CurrentGroup) NODE_LIST_PROP(DefaultValue) }; class ATL_NO_VTABLE CModelGroupNode : public CComObjectRoot, public INodeImpl { public: CModelGroupNode() { } BEGIN_COM_MAP(CModelGroupNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(ModelGroupNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() ENUM_PROP(Connector) ENUM_PROP(OccurIndicator) NODE_LIST_PROP(ContentTokens) }; class ATL_NO_VTABLE CElementTokenNode : public CComObjectRoot, public INodeImpl { public: CElementTokenNode() { } BEGIN_COM_MAP(CElementTokenNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(ElementTokenNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Gi) ENUM_PROP(OccurIndicator) }; class ATL_NO_VTABLE CPcdataTokenNode : public CComObjectRoot, public INodeImpl { public: CPcdataTokenNode() { } BEGIN_COM_MAP(CPcdataTokenNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(PcdataTokenNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() }; class ATL_NO_VTABLE CMessageNode : public CComObjectRoot, public INodeImpl { public: CMessageNode() { } BEGIN_COM_MAP(CMessageNode) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(MessageNode) COM_INTERFACE_ENTRY(Node) END_COM_MAP() STRING_PROP(Text) STDMETHOD(get_Severity)(Severity *retval) { TRY GROVE_NAMESPACE::Node::Severity type; if (nd_->getSeverity(type) == accessOK) *retval = Severity(type); return NOERROR; CATCH } }; class ATL_NO_VTABLE CEnumNodeList : public CComObjectRoot, public IEnumVARIANT { public: CEnumNodeList() { } BEGIN_COM_MAP(CEnumNodeList) COM_INTERFACE_ENTRY(IEnumVARIANT) END_COM_MAP() // IEnumVARIANT STDMETHOD(Next)(ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched); STDMETHOD(Skip)(ULONG celt); STDMETHOD(Reset)(); STDMETHOD(Clone)(IEnumVARIANT **ppEnum); static HRESULT make(const NodeListPtr &, const NodeTablePtr &table, IUnknown **); private: NodeListPtr nl_; NodeListPtr cur_; NodeTablePtr table_; }; class ATL_NO_VTABLE CEnumChunkNodeList : public CComObjectRoot, public IEnumVARIANT { public: CEnumChunkNodeList() { } BEGIN_COM_MAP(CEnumChunkNodeList) COM_INTERFACE_ENTRY(IEnumVARIANT) END_COM_MAP() // IEnumVARIANT STDMETHOD(Next)(ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched); STDMETHOD(Skip)(ULONG celt); STDMETHOD(Reset)(); STDMETHOD(Clone)(IEnumVARIANT **ppEnum); static HRESULT make(const NodeListPtr &, const NodeTablePtr &table, IUnknown **); private: NodeListPtr nl_; NodeListPtr cur_; NodeTablePtr table_; }; struct BuildVisitor : public GROVE_NAMESPACE::NodeVisitor { public: BuildVisitor(const NodePtr &n, const NodeTablePtr &t) : nd(n), table(t), retval(0), hRes(NOERROR) { } #define BUILD(mem, Cls) \ void mem(GROVE_NAMESPACE::Node &) { \ CComObject *p; \ hRes = CComObject::CreateInstance(&p); \ if (!FAILED(hRes)) { \ p->init(nd, table); \ retval = p; \ (retval)->AddRef(); \ } \ } BUILD(element, CElementNode) BUILD(attributeAssignment, CAttributeAssignmentNode) BUILD(attributeValueToken, CAttributeValueTokenNode) BUILD(sgmlDocument, CSgmlDocumentNode) BUILD(dataChar, CDataCharNode) BUILD(sgmlConstants, CSgmlConstantsNode) BUILD(pi, CPiNode) BUILD(sdata, CSdataNode) BUILD(documentType, CDocumentTypeNode) BUILD(entity, CEntityNode) BUILD(notation, CNotationNode) BUILD(externalId, CExternalIdNode) BUILD(externalData, CExternalDataNode) BUILD(subdocument, CSubdocNode) BUILD(message, CMessageNode) BUILD(elementType, CElementTypeNode) BUILD(modelGroup, CModelGroupNode) BUILD(elementToken, CElementTokenNode) BUILD(pcdataToken, CPcdataTokenNode) BUILD(defaultEntity, CDefaultEntityNode) BUILD(attributeDef, CAttributeDefNode) #undef BUILD NodePtr nd; HRESULT hRes; Node *retval; NodeTablePtr table; }; HRESULT CNodeBase::make(const NodePtr &nd, const NodeTablePtr &table, Node **retval) { CNodeBase *nb = table->lookup(*nd); if (nb) { *retval = nb->asNode(); (*retval)->AddRef(); return NOERROR; } else { BuildVisitor visitor(nd, table); nd->accept(visitor); *retval = visitor.retval; return visitor.hRes; } } CNodeBase::~CNodeBase() { CNodeBase *tem = table_->remove(*nd_); if (tem != this) abort(); } void CNodeBase::init(const NodePtr &nd, const NodeTablePtr &table) { table_ = table; nd_ = nd; table_->insert(this); } BSTR CNodeBase::makeBSTR(const GroveString &str) { CComBSTR bstr(str.size(), str.data()); return bstr.Detach(); } HRESULT CNodeBase::internalGetStoragePos(StoragePos **retval) { TRY const SP_NAMESPACE::LocNode *lp = SP_NAMESPACE::LocNode::convert(nd_); if (lp) { SP_NAMESPACE::Location loc; if (lp->getLocation(loc) == accessOK) { const SP_NAMESPACE::Origin *origin = loc.origin().pointer(); SP_NAMESPACE::Index index = loc.index(); while (origin) { const SP_NAMESPACE::ExternalInfo *info = origin->externalInfo(); if (info) return CStoragePos::make(info, origin->startOffset(index), nd_, retval); const SP_NAMESPACE::Location &loc = origin->parent(); index = loc.index(); origin = loc.origin().pointer(); } } } *retval = 0; return NOERROR; CATCH } STDMETHODIMP CDataCharNode::get_CharChunk(BSTR *retval) { TRY *retval = 0; GroveString str; if (nd_->charChunk(SdataMapper(), str) == accessOK) *retval = makeBSTR(str); else *retval = makeEmptyBSTR(); return NOERROR; CATCH } STDMETHODIMP CDataCharNode::get_Char(long *retval) { TRY GroveChar ch; if (nd_->getChar(SdataMapper(), ch) == accessOK) *retval = ch; else *retval = -1; return NOERROR; CATCH } STDMETHODIMP CDataCharNode::get_NonSgml(long *retval) { TRY unsigned long n; if (nd_->getNonSgml(n) == accessOK) *retval = n; else *retval = -1; return NOERROR; CATCH } // ---------- HRESULT CStringList::make(const GroveStringListPtr &sl, StringList **retval) { CComObject *p; HRESULT hRes = CComObject::CreateInstance(&p); if (FAILED(hRes)) return hRes; CStringList *np = p; np->sl_ = sl; *retval = p; (*retval)->AddRef(); return NOERROR; } STDMETHODIMP CStringList::First(BSTR *retval) { TRY *retval = 0; GroveString str; if (sl_->first(str) == accessOK) { *retval = CNodeBase::makeBSTR(str); } return NOERROR; CATCH } STDMETHODIMP CStringList::Rest(StringList **retval) { TRY *retval = 0; GroveStringListPtr sl; if (sl_->rest(sl) == accessOK) return CStringList::make(sl, retval); return NOERROR; CATCH } STDMETHODIMP CStringList::get_Count(long *retval) { TRY long n = 0; for (ConstGroveStringListIter iter(sl_->iter()); !iter.done(); iter.next()) n++; *retval = n; return NOERROR; CATCH } STDMETHODIMP CStringList::get_Item(long i, BSTR *retval) { TRY *retval = 0; if (i <= 0) return E_INVALIDARG; ConstGroveStringListIter iter(*sl_); for (long n = 1; n < i && !iter.done(); n++) iter.next(); if (iter.done()) return E_INVALIDARG; GroveString str; str = iter.cur(); *retval = CNodeBase::makeBSTR(str); return NOERROR; CATCH } // ----------- HRESULT CNodeList::make(const NodeListPtr &nl, const NodeTablePtr &table, NodeList **retval) { CComObject *p; HRESULT hRes = CComObject::CreateInstance(&p); if (FAILED(hRes)) return hRes; CNodeList *np = p; np->nl_ = nl; np->table_ = table; *retval = p; (*retval)->AddRef(); return NOERROR; } STDMETHODIMP CNodeList::First(Node **retval) { TRY *retval = 0; NodePtr nd; if (nl_->first(nd) == accessOK) return CNodeBase::make(nd, table_, retval); return NOERROR; CATCH } STDMETHODIMP CNodeList::Rest(NodeList **retval) { TRY *retval = 0; NodeListPtr nl; if (nl_->rest(nl) == accessOK) return CNodeList::make(nl, table_, retval); return NOERROR; CATCH } STDMETHODIMP CNodeList::get_Count(long *retval) { TRY long n = 0; NodeListPtr nl; if (nl_->rest(nl) == accessOK) { n++; while (nl.assignRest() == accessOK) n++; } *retval = n; return NOERROR; CATCH } STDMETHODIMP CNodeList::get_Item(long i, Node **retval) { TRY *retval = 0; NodePtr nd; if (i <= 0) return E_INVALIDARG; if (nl_->ref(i - 1, nd) != accessOK) return E_INVALIDARG; return CNodeBase::make(nd, table_, retval); CATCH } STDMETHODIMP CNodeList::get__NewEnum(IUnknown **retval) { TRY return CEnumNodeList::make(nl_, table_, retval); CATCH } HRESULT CChunkNodeList::make(const NodeListPtr &nl, const NodeTablePtr &table, NodeList **retval) { CComObject *p; HRESULT hRes = CComObject::CreateInstance(&p); if (FAILED(hRes)) return hRes; CChunkNodeList *np = p; np->nl_ = nl; np->table_ = table; *retval = p; (*retval)->AddRef(); return NOERROR; } STDMETHODIMP CChunkNodeList::First(Node **retval) { TRY *retval = 0; NodePtr nd; if (nl_->first(nd) == accessOK) return CNodeBase::make(nd, table_, retval); return NOERROR; CATCH } STDMETHODIMP CChunkNodeList::Rest(NodeList **retval) { TRY *retval = 0; NodeListPtr nl; if (nl_->chunkRest(nl) == accessOK) return CNodeList::make(nl, table_, retval); return NOERROR; CATCH } STDMETHODIMP CChunkNodeList::get__NewEnum(IUnknown **retval) { TRY return CEnumChunkNodeList::make(nl_, table_, retval); CATCH } STDMETHODIMP CChunkNodeList::get_Count(long *retval) { TRY long n = 0; NodeListPtr nl; if (nl_->chunkRest(nl) == accessOK) { n++; while (nl.assignChunkRest() == accessOK) n++; } *retval = n; return NOERROR; CATCH } STDMETHODIMP CChunkNodeList::get_Item(long i, Node **retval) { TRY *retval = 0; if (i <= 0) return E_INVALIDARG; if (i == 1) return First(retval); NodeListPtr nl(nl_); do { if (nl.assignChunkRest() != accessOK) return E_INVALIDARG; } while (--i > 1); NodePtr nd; if (nl->first(nd) != accessOK) return E_INVALIDARG; return CNodeBase::make(nd, table_, retval); CATCH } STDMETHODIMP CNamedNodeList::get_Count(long *retval) { TRY NodeListPtr nl(nnl_->nodeListNoOrder()); long n = 0; while (nl.assignRest() == accessOK) n++; *retval = n; return NOERROR; CATCH } STDMETHODIMP CNamedNodeList::get_Item(BSTR name, Node **retval) { TRY *retval = 0; if (!name) return E_INVALIDARG; GroveString tem(name, ::SysStringLen(name)); NodePtr nd; if (nnl_->namedNode(tem, nd) != accessOK) return E_INVALIDARG; return CNodeBase::make(nd, table_, retval); CATCH } STDMETHODIMP CNamedNodeList::get_NodeList(NodeList **retval) { TRY return CNodeList::make(nnl_->nodeList(), table_, retval); CATCH } STDMETHODIMP CNamedNodeList::get__NewEnum(IUnknown **retval) { TRY return CEnumNodeList::make(nnl_->nodeListNoOrder(), table_, retval); CATCH } STDMETHODIMP CNamedNodeList::Normalize(BSTR name, BSTR *retval) { TRY *retval = 0; if (name) { size_t len = ::SysStringLen(name); BSTR tem = ::SysAllocStringLen(name, len); size_t newLen = nnl_->normalize(tem, len); if (newLen != len && !::SysReAllocStringLen(&tem, tem, newLen)) { ::SysFreeString(tem); return E_OUTOFMEMORY; } *retval = tem; } else *retval = makeEmptyBSTR(); return NOERROR; CATCH } STDMETHODIMP CNamedNodeList::NodeName(Node *nd, BSTR *retval) { TRY *retval = 0; switch (nnl_->type()) { #define CASE(T, I, P) \ case GROVE_NAMESPACE::NamedNodeList::T: \ { \ I *tem; \ if (SUCCEEDED(nd->QueryInterface(IID_##I, (void **)&tem))) { \ HRESULT hRes = tem->get_##P(retval); \ tem->Release(); \ return hRes; \ } \ return NOERROR; \ } CASE(elements,ElementNode,Id) CASE(entities,EntityNode,Name) CASE(notations,NotationNode,Name) CASE(attributes,AttributeAssignmentNode,Name) CASE(doctypesAndLinktypes,DocumentTypeNode,Name) CASE(elementTypes,ElementTypeNode,Gi) CASE(attributeDefs,AttributeDefNode,Name) } return NOERROR; CATCH } HRESULT CNamedNodeList::make(const NamedNodeListPtr &nnl, const NodeTablePtr &table, NamedNodeList **retval) { CComObject *p; HRESULT hRes = CComObject::CreateInstance(&p); if (FAILED(hRes)) return hRes; CNamedNodeList *np = p; np->nnl_ = nnl; np->table_ = table; *retval = p; (*retval)->AddRef(); return NOERROR; } HRESULT CEnumNodeList::make(const NodeListPtr &nl, const NodeTablePtr &table, IUnknown **retval) { CComObject *p; HRESULT hRes = CComObject::CreateInstance(&p); if (FAILED(hRes)) return hRes; CEnumNodeList *np = p; np->nl_ = nl; np->cur_ = nl; np->table_ = table; return p->QueryInterface(IID_IUnknown, (void **)retval); } STDMETHODIMP CEnumNodeList::Next(ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) { TRY ULONG n = 0; for (; celt > 0; celt--, rgVar++, n++) { NodePtr nd; if (cur_->first(nd) != accessOK) break; if (cur_.assignRest() != accessOK) goto error; Node *ip; if (FAILED(CNodeBase::make(nd, table_, &ip))) goto error; rgVar->vt = VT_DISPATCH; rgVar->pdispVal = ip; } if (pCeltFetched) *pCeltFetched = n; return celt ? S_FALSE : NOERROR; error: while (n > 0) { --n ; --rgVar; VariantClear(rgVar); } if (pCeltFetched) *pCeltFetched = 0; return S_FALSE; CATCH } STDMETHODIMP CEnumNodeList::Skip(ULONG celt) { TRY for (; celt > 0; celt--) { if (cur_.assignRest() != accessOK) return S_FALSE; } return NOERROR; CATCH } STDMETHODIMP CEnumNodeList::Reset() { TRY cur_ = nl_; return NOERROR; CATCH } STDMETHODIMP CEnumNodeList::Clone(IEnumVARIANT **ppEnum) { TRY CComObject *p; HRESULT hRes = CComObject::CreateInstance(&p); if (FAILED(hRes)) return hRes; CEnumNodeList *np = p; np->nl_ = nl_; np->cur_ = cur_; np->table_ = table_; *ppEnum = p; (*ppEnum)->AddRef(); return NOERROR; CATCH } HRESULT CEnumChunkNodeList::make(const NodeListPtr &nl, const NodeTablePtr &table, IUnknown **retval) { CComObject *p; HRESULT hRes = CComObject::CreateInstance(&p); if (FAILED(hRes)) return hRes; CEnumChunkNodeList *np = p; np->nl_ = nl; np->cur_ = nl; np->table_ = table; return p->QueryInterface(IID_IUnknown, (void **)retval); } STDMETHODIMP CEnumChunkNodeList::Next(ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) { TRY ULONG n = 0; for (; celt > 0; celt--, rgVar++, n++) { NodePtr nd; if (cur_->first(nd) != accessOK) break; if (cur_.assignChunkRest() != accessOK) goto error; Node *ip; if (FAILED(CNodeBase::make(nd, table_, &ip))) goto error; rgVar->vt = VT_DISPATCH; rgVar->pdispVal = ip; } if (pCeltFetched) *pCeltFetched = n; return celt ? S_FALSE : NOERROR; error: while (n > 0) { --n ; --rgVar; VariantClear(rgVar); } if (pCeltFetched) *pCeltFetched = 0; return S_FALSE; CATCH } STDMETHODIMP CEnumChunkNodeList::Skip(ULONG celt) { TRY for (; celt > 0; celt--) { if (cur_.assignChunkRest() != accessOK) return S_FALSE; } return NOERROR; CATCH } STDMETHODIMP CEnumChunkNodeList::Reset() { TRY cur_ = nl_; return NOERROR; CATCH } STDMETHODIMP CEnumChunkNodeList::Clone(IEnumVARIANT **ppEnum) { TRY CComObject *p; HRESULT hRes = CComObject::CreateInstance(&p); if (FAILED(hRes)) return hRes; CEnumChunkNodeList *np = p; np->nl_ = nl_; np->cur_ = cur_; np->table_ = table_; *ppEnum = p; (*ppEnum)->AddRef(); return NOERROR; CATCH } HRESULT CStoragePos::make(const SP_NAMESPACE::ExternalInfo *info, SP_NAMESPACE::Offset offset, const NodePtr &nd, StoragePos **retval) { *retval = 0; CComObject *p; HRESULT hRes = CComObject::CreateInstance(&p); if (FAILED(hRes)) return hRes; CStoragePos *tem = p; if (!SP_NAMESPACE::ExtendEntityManager::externalize(info, offset, tem->loc_)) { delete p; return NOERROR; } tem->nd_ = nd; *retval = p; (*retval)->AddRef(); return NOERROR; } HRESULT makeRootNode(const GROVE_NAMESPACE::NodePtr &root, SP_NAMESPACE::Owner &parser, SgmlDocumentNode **retval) { TRY NodeTablePtr table(new NodeTable(parser)); Node *tem; HRESULT hRes = CNodeBase::make(root, table, &tem); *retval = (SgmlDocumentNode *)tem; return hRes; CATCH }