/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiSource Program Utilities * * Copyright (C) 2003 Francis James Franklin * Copyright (C) 2003 AbiSource, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef UTIL_TREE_H #define UTIL_TREE_H #include "ut_xml.h" #include "ut_IntStrMap.h" class UT_Element; class UT_ElementHash; class UT_Tree; class ABI_EXPORT UT_Node { public: class ABI_EXPORT Writer { public: virtual ~Writer () { } /* if this returns false the current node (elements call the next method) isn't written */ virtual bool treeNodeWrite (const UT_Node * node) = 0; /* in the case of elements, all descendant nodes are affected also if you return * false and set descend to false */ virtual bool treeNodeWrite (const UT_Element * element, bool & descend) = 0; virtual void treeAscending (const UT_Element * element) = 0; // notify that element is about to write the end-tag /* if this returns false the write process is stopped */ virtual bool treeNodeWrite (const UT_UTF8String & text) = 0; }; enum NodeType { nt_element, nt_text, nt_cdata, nt_pi, nt_comment, nt_default, nt_other }; protected: UT_Node (NodeType nt); public: virtual ~UT_Node () { } private: const NodeType m_type; UT_Element * m_parent; public: inline NodeType type () const { return m_type; } inline const UT_Element * parent () const { return m_parent; }; inline void parent (UT_Element * parent) { m_parent = parent; }; virtual bool write (UT_UTF8String & cache, Writer & writer) const = 0; }; class ABI_EXPORT UT_Text_Node : public UT_Node { private: UT_UTF8String m_text; public: inline const UT_UTF8String & text () const { return m_text; } inline UT_UTF8String & edit () { return m_text; } protected: UT_Text_Node (NodeType nt, const char * text); public: UT_Text_Node (const char * text = 0); virtual ~UT_Text_Node (); virtual bool write (UT_UTF8String & cache, Writer & writer) const; }; class ABI_EXPORT UT_CDATA_Node : public UT_Text_Node { public: UT_CDATA_Node (const char * text = 0); bool write (UT_UTF8String & cache, Writer & writer) const; }; class ABI_EXPORT UT_PI_Node : public UT_Text_Node { private: UT_UTF8String m_target; public: inline const UT_UTF8String & target () const { return m_target; } UT_PI_Node (const char * pi_target, const char * text = 0); bool write (UT_UTF8String & cache, Writer & writer) const; }; class ABI_EXPORT UT_Comment_Node : public UT_Text_Node { public: UT_Comment_Node (const char * text = 0); bool write (UT_UTF8String & cache, Writer & writer) const; }; class ABI_EXPORT UT_Default_Node : public UT_Text_Node { public: UT_Default_Node (const char * text = 0); }; class ABI_EXPORT UT_Element : public UT_Node, public UT_GenericBase { public: static const char * GBID; virtual const char * GenericBaseID () const; private: UT_Tree * m_tree; UT_UTF8String m_ElementTag; UT_UTF8String m_ElementID; UT_uint32 m_sibling_number; UT_Node ** m_node; UT_uint32 m_node_count; UT_uint32 m_node_max; UT_uint32 m_children; UT_UTF8Hash * m_Attrs; protected: UT_UTF8Hash * m_Props; private: UT_uint32 m_ref_count; public: inline const UT_Tree * tree () const { return m_tree; } inline const UT_UTF8String & ElementTag () const { return m_ElementTag; } inline const UT_UTF8String & ElementID () const { return m_ElementID; } inline UT_uint32 sibling_number () const { return m_sibling_number; } inline const UT_Node * operator[] (UT_uint32 i) const { return (i < m_node_count) ? m_node[i] : 0; }; inline UT_uint32 nodes () const { return m_node_count; } inline UT_uint32 children () const { return m_children; } // element-children only inline const UT_UTF8String * Attr (const char * attr) const { return m_Attrs ? (*m_Attrs)[attr] : 0; } inline const UT_UTF8String * Attr (const UT_UTF8String & attr) const { return m_Attrs ? (*m_Attrs)[attr] : 0; } inline const UT_UTF8String * Prop (const char * prop) const { return m_Props ? (*m_Props)[prop] : 0; } inline const UT_UTF8String * Prop (const UT_UTF8String & prop) const { return m_Props ? (*m_Props)[prop] : 0; } inline const UT_UTF8Hash * Attrs () const { return m_Attrs; } inline const UT_UTF8Hash * Props () const { return m_Props; } inline UT_uint32 refs () const { return m_ref_count; } public: UT_Element (const char * element_tag, const char * element_id); virtual ~UT_Element (); protected: /* change the element's ID; * fails if the new element_id is already registered with the element's tree (if any) */ bool ElementID (const UT_UTF8String & element_id); public: /* adding/changing attributes */ virtual bool insAttr (const char ** atts); virtual bool insAttr (const char * name, const char * value); virtual void delAttr (const char * name); const UT_Element * child (UT_uint32 sn) const; /* responsibility for node passes to element with appendNode() and insertNode(), * and passes back with detachNode(). */ inline bool appendNode (UT_Node * node) { return insertNode (node, m_node_count); } bool insertNode (UT_Node * node, UT_uint32 index, bool delete_if_fail = true); bool deleteNode (UT_uint32 index); UT_Node * detachNode (UT_uint32 index); protected: /* this is called by insertNode() to check whether the supplied node is permitted * at the suggested index; UT_Element default implementation returns true always */ virtual bool acceptNode (const UT_Node * node, UT_uint32 index) const; public: /* for moving nodes about within a tree; on failure the node stays where it started */ bool shiftNode (UT_uint32 src_index, UT_Element * dest, UT_uint32 dest_index); bool descendsFrom (const UT_Element * element) const; virtual bool write (UT_UTF8String & cache, Writer & writer) const; static bool map (UT_Tree * Tree, UT_Element * element); private: inline bool map (UT_Element * element) { return UT_Element::map (m_tree, element); } bool setUniqueID (UT_Tree * m_tree, UT_UTF8Hash & map_Abi, UT_UTF8Hash & map_Named); protected: virtual void remap_IDREFs (UT_UTF8Hash & map_Abi, UT_UTF8Hash & map_Named); // empty implementation private: /* don't call register() unless you're sure it will succeed; use map() first * returns false if part (or all) of element & children failed to register */ bool enregister (UT_Tree * Tree); void deregister (); public: /* used by UT_Tree for deregistering root elements */ static void deregister (UT_Element * element); inline void relabel (UT_uint32 sn) { m_sibling_number = sn; } void relabelChildren (); bool grow (); }; class ABI_EXPORT UT_ElementHash : public UT_GenericUTF8Hash { public: UT_ElementHash (UT_uint32 increment); ~UT_ElementHash (); inline void clear () { UT_GenericUTF8Hash::clear (false); // don't delete elements } /* for easy sequential access of map members: */ bool pair (UT_uint32 index, const UT_UTF8String *& element_id, const UT_Element *& element) const; /* The ElementHash stores pointers only, does not delete them ever */ inline bool ins (const UT_UTF8String & element_id, const UT_Element * element) { return element ? UT_GenericUTF8Hash::ins (element_id, const_cast(element)) : false; } /* returns false if no element with ID; does not delete element, if any */ bool del (const UT_UTF8String & element_id); inline const UT_Element * operator[] (const UT_UTF8String & key) { return static_cast(UT_GenericUTF8Hash::lookup (key)); } }; class ABI_EXPORT UT_ID_Generator { public: static bool isInternal (const UT_UTF8String & element_id); // true if element_id matches "Abi_??????" UT_ID_Generator (); /* cycles through 56.8 billion unique 10-character IDs, * each starting with the 4-character sequence "Abi_" */ const char * next (); private: int i1,i2,i3,i4,i5,i6; char buffer[11]; }; class ABI_EXPORT UT_ElementFactory { public: virtual UT_Element * createElement (const char * element_tag, const char * element_id) const; virtual ~UT_ElementFactory () { } }; class ABI_EXPORT UT_Tree : public UT_XML::ExpertListener { private: UT_XML * m_parser; // used when building tree const UT_ElementFactory * m_factory; UT_Element * m_current; bool m_cdata; bool m_valid; /* IDs fall into 2 categories: (1) internal "Abi_??????"; (2) user-defined */ UT_ElementHash m_ElementID_Abi; UT_ElementHash m_ElementID_Named; UT_Element * m_root; UT_Node ** m_node; UT_uint32 m_node_count; UT_uint32 m_node_max; UT_ID_Generator m_Generator; public: inline const UT_Element * root () const { return m_root; } inline const UT_Node * operator[] (UT_uint32 i) const { return (i < m_node_count) ? m_node[i] : 0; }; inline UT_uint32 nodes () const { return m_node_count; } /* return an internal ID (i.e., of type "Abi_??????") unique in this tree: */ inline const char * uniqueEID () { return m_Generator.next (); } const UT_Element * lookupEID (const UT_UTF8String & element_id); public: UT_Tree (); ~UT_Tree (); /* responsibility for node passes to element with appendNode() and insertNode(), * and passes back with detachNode(). */ inline bool appendNode (UT_Node * node) { return insertNode (node, m_node_count); } bool insertNode (UT_Node * node, UT_uint32 index, bool delete_if_fail = true); bool deleteNode (UT_uint32 index); UT_Node * detachNode (UT_uint32 index); private: bool grow (); public: bool write (UT_Node::Writer & writer) const; /* Element Registration * * register()/deregister() perform some checks, but it's up to the caller really to ensure * that IDs are properly assigned to elements - use lookupEID() to ensure IDs are unique */ /* fails if an element with the same ID has already been registered, or if the element * belongs to a tree; if registration succeeds then the element should set its tree to this */ bool enregister (const UT_Element * element); /* fails if element has registered parent or is root element; if deregistration succeeds then the * element should set its tree to 0 */ bool deregister (const UT_Element * element); /* attempts to deregister element, but this may fail silently; registers element with new ID * if reregistration succeeds, the element should change its ID to new_EID */ bool reregister (const UT_Element * element, const UT_UTF8String & new_EID); /* building the tree from file/memory using the XML parser */ inline bool parse (const char * filename, const UT_ElementFactory * factory = 0) { return parse (filename, 0, factory, false); } inline bool parse (const char * buffer, UT_uint32 length, const UT_ElementFactory * factory = 0) { return parse (buffer, length, factory, true); } private: bool parse (const char * buffer, UT_uint32 length, const UT_ElementFactory * factory, bool bIsBuffer); public: /* implementation of UT_XML::ExpertListener */ void StartElement (const XML_Char * name, const XML_Char ** atts); void EndElement (const XML_Char * name); void CharData (const XML_Char * buffer, int length); void ProcessingInstruction (const XML_Char * target, const XML_Char * data); void Comment (const XML_Char * data); void StartCdataSection (); void EndCdataSection (); void Default (const XML_Char * buffer, int length); }; #endif /* ! UTIL_TREE_H */