/*
 * e4xml.h --
 *
 *	Definition of the e4_XML classes.
 *
 *	The e4_XMLParser class wraps around James Clark's expat
 *	parser and stores the parse tree under a given node.
 *
 *	The e4_XMLGenerator class generates XML output from a given
 *	node.
 *
 *	Authors: Jacob Levy and Jean-Claude Wippler.
 *		 jyl@best.com	jcw@equi4.com
 *
 *	Copyright: JYL Software, Inc., (c) 2000-2003.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF
 * JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef	__E4_XML_H__
#define	__E4_XML_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "expat.h"
#include "e4graph.h"

/*
 * Ensure propert exporting of symbols on WIN32:
 */

#ifndef e4_XMLDLL
    #if defined(_WIN32) && !defined(E4_STATIC)
	#ifdef E4_XMLDLL
            #define e4_XMLDLL      __declspec(dllexport)
        #else
            #define e4_XMLDLL      __declspec(dllimport)
        #endif
    #else
        #define e4_XMLDLL          
    #endif
#endif

/*
 * Forward declarations:
 */

class e4_XMLDLL e4_XMLGenerator;
class e4_XMLDLL e4_XMLOutputStream;
class e4_XMLDLL e4_XMLOutputProcessor;

class e4_XMLDLL e4_XMLParser;
class e4_XMLDLL e4_XMLInputProcessor;
class e4_XMLDLL e4_XMLNodeVertexCreator;

/*
 * Implementation of base64 encode/decode exported by e4XML as a courtesy.
 */

typedef unsigned char byte;		/* Byte (8 bit quantity) type. */

/*
 * The base64 encoder and decoder functions:
 */

extern "C" e4_XMLDLL byte *	base64_decode(const char *base64str, int *len);
extern "C" e4_XMLDLL char *	base64_encode(const byte *bytes, int len);

/*
 * The e4_XMLInputProcessor class (this must appear *before* the definition
 * of e4_XMLParser because that class embeds an instance of
 * e4_XMLInputProcessor).
 *
 * This class provides methods for processing XML input entities. This class
 * is intended to be subclassed by clients for client-specific behavior
 * implementations.
 */

class e4_XMLDLL e4_XMLInputProcessor {
protected:

    /*
     * This data is protected (and not private) so that it can be accessed
     * directly by subclasses.
     */

    /*
     * The parser associated with this processor.
     */
	
    e4_XMLParser *parser;

    /*
     * The buffer used to queue up the incoming character data.
     */

    e4_DString ds;

    /*
     * The buffer used to queue up the incoming unclassified data.
     */

    e4_DString uc;

    /*
     * These instance variables will hold the name of a namespace declaration
     * and its URI.
     */

    char *ns;
    char *uri;

public:

    /*
     * Default constructor.
     */

    e4_XMLInputProcessor();

    /*
     * Constructor which takes a parser as argument.
     */

    e4_XMLInputProcessor(e4_XMLParser *p);

    /*
     * Destructor -- declared virtual so can be overridden by subclasses.
     */

    virtual ~e4_XMLInputProcessor();

    /*
     * Is the input blank character space?
     */

    static bool IsBlankCharData(const char *input, int len);

    /*
     * Set and retrieve the parser associated with this input processor:
     */

    inline void SetParser(e4_XMLParser *p) {parser = p;}
    inline e4_XMLParser *GetParser() const {return parser;}

    /*
     * Process the start of an element:
     */

    virtual bool ProcessElementBegin(const char *name,
				     const char **attributes);

    /*
     * Process the end of an element.
     */

    virtual bool ProcessElementEnd(const char *name);

    /*
     * Process character data (the data that appears between the start and
     * end tags of an XML element). The input buffer is not NULL terminated.
     * When there is no more character data, the last call will be with
     * a NULL buffer.
     */

    virtual bool ProcessCharData(const char *data, int len);

    /*
     * Process unclassified data (any data appearing in the input that would
     * otherwise not be handled). The input buffer is not NULL terminated.
     * When there is no more unclassified data, the last call will be with
     * a NULL buffer.
     */

    virtual bool ProcessUnclassifiedData(const char *data, int len);

    /*
     * Process a comment in the XML input.
     */

    virtual bool ProcessComment(const char *comment);

    /*
     * Process an XML declaration.
     */

    virtual bool ProcessXMLDeclaration(const char *version,
				       const char *encoding,
				       int standalone);

    /*
     * Process the start of an XML DTD (Document Type Declaration).
     */

    virtual bool ProcessDTDBegin(const char *doctypename,
				 const char *sysid,
				 const char *pubid,
				 int hasinternalsubset);

    /*
     * Process the end of an XML DTD.
     */

    virtual bool ProcessDTDEnd();

    /*
     * Process processing instructions in the XML stream.
     */

    virtual bool ProcessInstructions(const char *target,
				     const char *data);

    /*
     * Process the start of an XML CDATA section.
     */

    virtual bool ProcessCDATABegin();

    /*
     * Process the end of an XML CDATA section.
     */

    virtual bool ProcessCDATAEnd();

    /*
     * Process the start of a namespace scope.
     */

    virtual bool ProcessStartNamespaceDecl(const char *prefix,
					   const char *theuri);

    /*
     * Process the end of a namespace scope.
     */

    virtual bool ProcessEndNamespaceDecl(const char *prefix);

    /*
     * Process the declaration of an unparsed entity.
     */

    virtual bool ProcessUnparsedEntityDecl(const char *entityName,
					   const char *base,
					   const char *systemID,
					   const char *publicID,
					   const char *notationName);

    /*
     * Process the declaration of a notation.
     */

    virtual bool ProcessNotationDecl(const char *notationName,
				     const char *base,
				     const char *systemID,
				     const char *publicID);

    /*
     * Process a skipped entity.
     */

    virtual bool ProcessSkippedEntity(const char *entityName,
				      int isParameterEntity);
};

/*
 * The e4_XMLNodeVertexCreator class (this must appear *before* the definition
 * of e4_XMLParser because that class embeds an instance of
 * e4_XMLNodeVertexCreator).
 *
 * This class provides methods for inserting new nodes and vertices into a
 * storage; this class is intended to be subclassed by clients for implementing
 * client-specific behaviors such as merging with pre-existing structure.
 */

class e4_XMLDLL e4_XMLNodeVertexCreator {
private:
    /*
     * Hash table to hold nodes seen so far during the parse.
     */

    e4_HashTable *nodesSeen;

protected:

    /*
     * This data is protected rather than private so that it can be
     * accessed directly by subclasses.
     */

    /*
     * The parser associated with this storage effector.
     */

    e4_XMLParser *parser;

public:

    /*
     * Default constructor.
     */

    e4_XMLNodeVertexCreator();

    /*
     * Constructor taking a parser as argument.
     */

    e4_XMLNodeVertexCreator(e4_XMLParser *p);

    /*
     * Destructor -- declared virtual so can be overridden by subclasses.
     */

    virtual ~e4_XMLNodeVertexCreator();

    /*
     * Retrieve and set the parser associated with this storage effector.
     */

    inline e4_XMLParser *GetParser() const {return parser;}
    inline void SetParser(e4_XMLParser *p) {
	parser = p;
	if (nodesSeen == NULL) {
	    nodesSeen = e4_NewHashTable(E4_ONE_WORD_KEY);
	}
    }

    /*
     * This method adds a back-reference to a node that was already parsed.
     * The userdata is associated with the vertex created for the backwards
     * reference.
     */

    virtual bool AddNodeBackRef(e4_Node &n,
				const char *nm,
				const char *nid,
				int userdata);

    /*
     * Add a vertex that will be set to a new node. This is used to open
     * a new XML element and also for special elements like __xml__,
     * __processinginstruction__, etc. The element's user data is added
     * later, if any is specified.
     */

    virtual bool AddNodeRef(e4_Node &n,
			    const char *name,
			    e4_InsertOrder io,
			    int &rank,
			    e4_Node &nn,
			    e4_Vertex &v,
			    int nud,
			    int vud);

    /*
     * This operation adds a new style vertex to the current node.
     */

    virtual bool AddVertex(e4_Node &n,
			   const char *vname,
			   const char *vtype,
			   int userdata);

    /*
     * This operation adds a vertex to the current node.
     */

    virtual bool AddVertex(e4_Node &n, 
			   const char *vname,
			   const char *vtype,
			   const char *vval,
			   int userdata);

    /*
     * Add a vertex of type int to the specified node.
     */

    virtual bool AddVertexRef(e4_Node &n,
			      const char* name,
			      e4_InsertOrder o,
			      int &rank,
			      int i,
			      e4_Vertex &v);

    /*
     * Add a vertex of type double to the specified node
     */

    virtual bool AddVertexRef(e4_Node &n,
			      const char* name,
			      e4_InsertOrder o,
			      int &rank,
			      double d,
			      e4_Vertex &v);

    /*
     * Add a vertex of type string.
     */

    virtual bool AddVertexRef(e4_Node &n,
			      const char* name,
			      e4_InsertOrder o,
			      int &rank,
			      const char* s,
			      e4_Vertex &v);

    /*
     * Add a vertex of type binary.
     */

    virtual bool AddVertexRef(e4_Node &n,
			      const char* name,
			      e4_InsertOrder o,
			      int &rank,
			      const void* bytes,
			      int nbytes,
			      e4_Vertex &v);

    /*
     * Add a vertex with a value of the node specified.
     */

    virtual bool AddVertexRef(e4_Node &n,
			      const char* name,
			      e4_InsertOrder o,
			      int &rank,
			      e4_Node vn,
			      e4_Vertex &v);

    /*
     * Hash a node so backwards references to it can be reconstructed.
     */

    void HashNode(e4_Node nn, int id) const;
};

/*
 * The e4_XMLParser class:
 */

class e4_XMLDLL e4_XMLParser {
private:
    /*
     * These classes are friends of the e4_XMLParser class because
     * they need to be able to call CauseVertexCompletionEvent.
     */

    friend class e4_XMLNodeVertexCreator;
    friend class e4_XMLInputProcessor;

    /*
     * These operations are hooked up to the Expat parser and handle data
     * coming back from the parser:
     */

    static void HandleStartElement(void *userData, 
				   const char *name,
				   const char **attributes);
    static void HandleEndElement(void *userData,
				 const char *name);
    static void HandleComment(void *userData,
			      const char *comment);
    static void HandleDefaultData(void *userData,
				  const char *data,
				  int len);
    static void HandleCharData(void *userData,
			       const char *data,
			       int len);
    static void HandleStartCDATA(void *userData);
    static void HandleEndCDATA(void *userData);
    static void HandleProcessingInstructions(void *userData,
					     const char *target,
					     const char *data);
    static void	HandleXMLDeclaration(void *userData,
				     const char *version,
				     const char *encoding,
				     int standalong);
    static void HandleStartDocType(void *userData,
				   const char *doctypename,
				   const char *sysid,
				   const char *pubid,
				   int hasinternalsubset);
    static void HandleEndDocType(void *userData);
    static void HandleStartNamespaceDecl(void *userData,
					 const char *prefix,
					 const char *uri);
    static void HandleEndNamespaceDecl(void *userData,
				       const char *prefix);
    static void HandleUnparsedEntityDecl(void *userData,
					 const char *entityName,
					 const char *base,
					 const char *systemID,
					 const char *publicID,
					 const char *notationName);
    static void HandleNotationDecl(void *userData,
				   const char *notationName,
				   const char *base,
				   const char *systemID,
				   const char *publicID);
    static void HandleSkippedEntity(void *userData,
				    const char *entityName,
				    int isParameterEntity);

    /*
     * Cause a vertex completion event.
     */

    bool CauseVertexCompletionEvent(const e4_Vertex &v, void *csdata);

    /*
     * Is this parser ready?
     */

    bool ready;

    /*
     * Does this parser have an error flagged?
     */

    bool error;

    /*
     * If so, this is the error message.
     */

    char *errorString;

    /*
     * Has the parse started?
     */

    bool started;

    /*
     * How many open XML elements have we entered?
     */

    int depth;

    /*
     * Are we currently in a vertex-add?
     */

    bool inVertex;

    /*
     * Saved vertex.
     */

    e4_Vertex savedvertex;

    /*
     * This is the node under which the XML elements are to be
     * inserted.
     */

    e4_Node n;

    /*
     * This is the storage in which the XML elements are stored.
     */

    e4_Storage s;

    /*
     * This is the XML parser itself.
     */

    XML_Parser parser;

    /*
     * BASE64 string.
     */

    byte *base64bytes;

    /*
     * The XML input processor we use by default.
     */

    e4_XMLInputProcessor defaultXMLInputProcessor;

    /*
     * The storage effector we use by default to create new vertices and
     * nodes in the storage.
     */

    e4_XMLNodeVertexCreator defaultNodeVertexCreator;

    /*
     * Pointers to the currently in-use input processor and storage effector.
     */

    e4_XMLInputProcessor *inputProcessor;
    e4_XMLNodeVertexCreator *nodeVertexCreator;

public:

    /*
     * This constructor constructs an empty parser:
     */

    e4_XMLParser();

    /*
     * This constructor sets up the parser to store new elements under 'nn'.
     */

    e4_XMLParser(e4_Node nn);

    /*
     * The destructor cleans up the state associated with this parser.
     */

    virtual ~e4_XMLParser();

    /*
     * This operation assigns a node as the current node of the parser.
     * New elements will be stored under this node.
     */

    void SetNode(e4_Node nn);

    /*
     * This operation returns in 'ss' the current storage.
     */

    bool GetStorage(e4_Storage &ss) const;

    /*
     * This operation returns in 'nn' the current node.
     */

    bool GetNode(e4_Node &nn) const;

    /*
     * ClearError clears a stored error state.
     */

    void ClearError();

    /*
     * ErrorString returns the error string for the current error state.
     */

    const char *ErrorString();

    /*
     * Is the parse finished?
     */

    bool Finished();

    /*
     * This operation parses one buffer of XML input and stores the new
     * elements under the stored node. It returns true if all went well,
     * false otherwise. If an error occurred then most likely HasError()
     * will return true and ErrorString() will return a non-NULL string.
     */

    bool Parse(char *buf, size_t len);

    /*
     * Does this parser have an uncleared error state?
     */

    bool HasError();

    /*
     * As a service we export BASE64 decoding functionality. The returned
     * byte buffer must be deleted by the caller when no longer needed.
     */

    byte *Base64_Decode(const char *base64str, int *len);

    /*
     * The operations below must be public, because they're used by
     * e4_XMLInputParser and e4_XMLNodeVertexCreator.
     */

    /*
     * Flag an error on this parser and store an error string.
     */

    void FlagError(const char *msg);

    /*
     * This operation begins the addition of a vertex.
     */

    bool EnterVertex();

    /*
     * Are we currently in a vertex?
     */

    bool InVertex() const;

    /*
     * This operation closes the current vertex.
     */

    void ExitVertex();

    /*
     * This operation constructs a new parser from the stored file pointer
     * and node.
     */

    bool ConstructParser();

    /*
     * Increment/decrement the nesting depth of XML elements entered, get
     * the depth we're currently at.
     */

    inline void IncrDepth() {depth++;}
    inline void DecrDepth() {depth--;}
    inline int GetDepth() const {return depth;}

    /*
     * Get and set an XML processor instance associated with this parser.
     */

    inline e4_XMLInputProcessor *GetXMLProcessor() {return inputProcessor;}
    inline bool SetXMLInputProcessor(e4_XMLInputProcessor *np) {
	if (np == NULL) {
	    inputProcessor = &defaultXMLInputProcessor;
	    return false;
	}
	inputProcessor = np;
	return true;
    }

    /*
     * Get and set a storage effector that will create new nodes and
     * vertices in the storage in response to parsing XML input.
     */

    inline e4_XMLNodeVertexCreator *GetNodeVertexCreator() {
	return nodeVertexCreator;
    }
    inline bool SetNodeVertexCreator(e4_XMLNodeVertexCreator *np) {
	if (np == NULL) {
	    nodeVertexCreator = &defaultNodeVertexCreator;
	    return false;
	}
	nodeVertexCreator = np;
	return true;
    }

    /*
     * These operations deal with the saved vertex for new style
     * vertices as they are being parsed.
     */

    inline void SetSavedVertex(e4_Vertex v) {
	savedvertex = v;
    }
    inline bool HasSavedVertex() {
	return (savedvertex == invalidVertex) ? false : true;
    }
    bool AssignVertex(e4_DString &dsv);

    /*
     * These operations handle the data coming back from the Expat parser:
     */

    bool ProcessDefaultData(const char *data, int len);
    bool ProcessCharData(const char *data, int len);
    bool ProcessElementBegin(const char *name, const char **attributes);
    bool ProcessElementEnd(const char *name);
    bool ProcessComment(const char *comment);
    bool ProcessXMLDeclaration(const char *version,
			       const char *encoding,
			       int standalone);
    bool ProcessDTDBegin(const char *doctypename,
			 const char *sysid,
			 const char *pubid,
			 int hasinternalsubset);
    bool ProcessDTDEnd();
    bool ProcessInstructions(const char *target, const char *data);
    bool ProcessCDATABegin();
    bool ProcessCDATAEnd();    
    bool ProcessStartNamespaceDecl(const char *prefix, const char *uri);
    bool ProcessEndNamespaceDecl(const char *prefix);
    bool ProcessUnparsedEntityDecl(const char *entityName,
				   const char *base,
				   const char *systemID,
				   const char *publicID,
				   const char *notationName);
    bool ProcessNotationDecl(const char *notationName,
			     const char *base,
			     const char *systemID,
			     const char *publicID);
    bool ProcessSkippedEntity(const char *entityName, int isParameterEntity);

    /*
     * Vertex completion event mechanism:
     *
     * The parser fires a special event (if defined) for each vertex as
     * it is completely read from the input. This enables the implementation
     * of XML Streams protocols (e.g. see the XML streams proposed protocol
     * at http://www.jabber.org/protocol/xmlstreams.html).
     */

    bool DeclareVertexCompletionCallback(e4_CallbackFunction fn,
					 void *clientData);
    bool DeleteVertexCompletionCallback(e4_CallbackFunction fn,
					void *clientData);
};

/*
 * The e4_XMLOutputStream class.
 *
 * This class has the responsibility for handling streamed output
 * that gets generated as a result of the e4_XMLGenerator process.
 * This class is intended to be subclassed by clients that desire
 * to stream to output targets other than the default e4_DString
 * target.
 */

class e4_XMLDLL e4_XMLOutputStream
{
protected:

    /*
     * The default output stream target object...
     */

    e4_DString ds;

public:

    /*
     * Default constructor...
     */

    e4_XMLOutputStream();

    /*
     * Destructor, defined virtual for proper subclassing destruction...
     */

    virtual ~e4_XMLOutputStream();

    /*
     * Accept a pointer to character data and appends to the
     * generating buffer of xml output.
     */

    virtual e4_XMLOutputStream& operator<< (const char *s);

    /*
     * Append a character to the generating buffer of xml output.
     */

    virtual e4_XMLOutputStream& operator<< (char c);

    /*
     * Append an unsigned char to the generating buffer of xml output.
     * The default action is to represent the byte as a 2 digit hex string
     * in the output.
     */

    virtual e4_XMLOutputStream& operator<< (unsigned char uc);

    /*
     * Append an integer numeric string to the generating buffer of xml output.
     */

    virtual e4_XMLOutputStream& operator<< (int val);

    /*
     * Append a double numeric string to the generating buffer of xml output.
     */

    virtual e4_XMLOutputStream& operator<< (double dval);

    /*
     * Reset internal state.
     */

    virtual void Reset();

    /*
     * Return a pointer to a buffer containing the accumulated xml output.
     * If the stream cannot be accessed as a char pointer (ie: the stream
     * was redirected to a file by your subclass), this method should
     * return NULL.
     */
	
    virtual char *Get();
};

/*
 * The e4_XMLOutputProcessor class.
 *
 * This class provides methods for generating XML entities in an output buffer
 * from nodes and vertices existing in an e4Graph storage. This class
 * is intended to be subclassed by clients for client-specific behavior
 * implementations.
 */

class e4_XMLDLL e4_XMLOutputProcessor {
protected:

    /*
     * This data is protected (and not private) so that it can be accessed
     * directly by subclasses.
     */

    /*
     * The parser associated with this processor.
     */
	
    e4_XMLGenerator *generator;

    /*
     * The output stream associated with this processor.
     */

    e4_XMLOutputStream *outstream;

public:

    /*
     * Default constructor.
     */

    e4_XMLOutputProcessor();

    /*
     * Constructor which takes a generator as argument.
     */

    e4_XMLOutputProcessor(e4_XMLGenerator* g);

    /*
     * Destructor -- declared virtual so can be overridden by subclasses.
     */

    virtual ~e4_XMLOutputProcessor();

    /*
     * Set and retrieve the parser associated with this output processor:
     */

    inline void SetGenerator(e4_XMLGenerator *g) {generator = g;}
    inline e4_XMLGenerator *GetGenerator() const {return generator;}

    /*
     * Set and retrieve the output stream associated with 
     * this output processor:
     */

    inline void SetOutputStream(e4_XMLOutputStream *o) {outstream = o;}
    inline e4_XMLOutputStream *GetOutputStream() const {return outstream;}

    /*
     * Bracket the begin and end of the output process.
     */

    virtual bool ProcessOutputBegin(const char *se,
				    e4_Node &sn, 
				    bool firstTime);
    virtual bool ProcessOutputEnd(bool firstTime);

    /*
     * Process a node which is a back reference to another node.
     */

    virtual bool ProcessBackRefNode(const e4_Node &n,
				    const char *elementName,
				    int nodeId,
				    int vertexUserData);

    /*
     * Process a normal node.
     *
     * On input, if this node has parents and could be part of a cyclic
     * graph, nodeId will be some value other than -1.
     *
     * If there are attributes associated with this node, dsAttrs will
     * contain {name,value} string pairs where each component of the pair
     * is null-terminated. The final pair will be followed by an extra
     * null (double-null-terminated).
     */

    virtual bool ProcessNodeBegin(const e4_Node &n,
				  const char *elementName,
				  int nodeId,
				  int vertexUserData,
				  e4_DString &dsAttrs,
				  bool hasVertices);

    virtual bool ProcessNodeEnd(const e4_Node &n,
				const char *elementName,
				bool hasVertices);

    /*
     * Process a vertex.
     */

    virtual bool ProcessVertex(const e4_Vertex &v);

    /*
     * Process a comment in the output stream.
     */

    virtual bool ProcessComment(const char *comment);

    /*
     * Process character data in the output stream.
     */

    virtual bool ProcessCharData(const char *data);

    /*
     * Process CDATA in the output stream.
     */

    virtual bool ProcessCDATA(const char *data);

    /*
     * Process a processing instruction in the output stream.
     */

    virtual bool ProcessInstructions(const char *target, const char *data);

    /*
     * Process an XML declaration in the output stream.
     */

    virtual bool ProcessXMLDeclaration(const char *version,
				       const char *encoding,
				       int standalone);

    /*
     * Process the begin bracket for a DTD declaration.
     */

    virtual bool ProcessDTDBegin(const char *doctypename,
				 const char *sysid,
				 const char *pubid,
				 int hasinternalsubset);

    /*
     * Process the end of a DTD declaration.
     */

    virtual bool ProcessDTDEnd();

    /*
     * Produce output for an unparsed entity declaration.
     */

    virtual bool ProcessUnparsedEntity(const char *entityname,
				       const char *base,
				       const char *systemid,
				       const char *publicid,
				       const char *notationname);

    /*
     * Produce output for a skipped entity.
     */

    virtual bool ProcessSkippedEntity(const char *entityname,
				      int isparameterentity);

    /*
     * Produce output for a notation declaration.
     */

    virtual bool ProcessNotationDecl(const char *notationname,
				     const char *base,
				     const char *systemid,
				     const char *publicid);
};

/*
 * The e4_XMLGenerator class:
 */

class e4_XMLDLL e4_XMLGenerator {
private:
    /*
     * Is this generator ready to generate?
     */

    bool ready;

    /*
     * The starting node.
     */

    e4_Node sn;

    /*
     * The XML element into which the starting node will be wrapped.
     */

    char *se;

    /*
     * nodeCounter counts the number of nodes for which we've already generated
     * XML output. Each node is hashed under its unique ID, and the hash value
     * is its assigned nodeCounter. That way we can generate XML for back
     * references to nodes we've already produced XML for before.
     */

    int nodeCounter;

    /*
     * nodesSeen is a hash table for nodes that were already output into the
     * generated XML. The key is the node unique ID, and the value is the
     * assigned nodeCounter value for that node. This value is used in a
     * "__nodebackreference__" element if the same node occurs more than once
     * in the sub-graph from which we are generating the XML output.
     */

    e4_HashTable *nodesSeen;

    /*
     * BASE64 string.
     */

    char *base64str;

    /*
     * exportPureXML is set true for export quality XML with no nodeid tags.
     * Modified to allow the generator to reproduce exactly the XML that
     * could have been used to create the node from which the exported XML
     * is being created.
     */

     bool exportPureXML;

     /*
      * Has there been an error generating XML output?
      */

     bool error;

     /*
      * If so, this has the error message:
      */

     char *errorString;

     /*
      * Is this the first time this generator is used to generate XML?
      */

     bool firstGeneration;

    /*
     * The XML output processor we use by default.
     */

    e4_XMLOutputProcessor defaultXMLOutputProcessor;

    /*
     * Pointer to the currently in-use output processor.
     */

    e4_XMLOutputProcessor *outputProcessor;

    /*
     * The output stream we use by default.
     */
	
    e4_XMLOutputStream defaultXMLOutputStream;

    /*
     * Pointer to the currently in-use output stream.
     */

    e4_XMLOutputStream *outputStream;

public:
    /*
     * Default constructor:
     */

    e4_XMLGenerator();

    /*
     * Constructor that takes a node and element name as input.
     */

    e4_XMLGenerator(e4_Node nn, char *sen);

    /*
     * Constructor as above that takes additional boolean argument
     * describing whether to export pure XML (the exact equivalent
     * XML that was parsd to create the node) or a slightly marked
     * up XML that contains e.g. information about backreferences.
     */

    e4_XMLGenerator(e4_Node nn, char *sen, bool ex);

    /*
     * Destructor:
     */

    virtual ~e4_XMLGenerator();

    /*
     * ClearError clears a stored error state.
     */

    void ClearError();

    /*
     * ErrorString returns the error string for the current error state.
     */

    const char *ErrorString();

    /*
     * Does this generator have an uncleared error state?
     */

    bool HasError();

    /*
     * Flag an error on this generator and store an error string.
     */

    void FlagError(const char *msg);

    /*
     * Set the starting node. Resets the XML output.
     */

    void SetNode(e4_Node nn);

    /*
     * Set the starting element name. Resets the XML output.
     */

    void SetElementName(char *sen);

    /*
     * Set the element name and the starting node. Resets the XML output.
     */

    void SetElementNameAndNode(char *sen, e4_Node nn);

    /*
     * Retrieve the node for which XML output is being generated.
     */

    void GetNode(e4_Node &nn) const;

    /*
     * Retrieve the wrapping XML element tag name.
     */

    char *GetElementName() const;

    /*
     * Produce XML output.
     *
     * NOTE: The default output processor functionality will return a
     * char pointer to the generated output buffer. This buffer may not be
     * complete if there is an error state set.
     *
     * If the default output processor has been substituted by a client
     * output processor the char pointer returned has a context determined
     * by the client's subclass.
     */

    char *Generate();

    /*
     * Produce XML output.
     *
     * NOTE: The default output processor functionality will return a
     * char pointer to the generated output buffer. This buffer may not
     * be complete if there is an error state set.
     *
     * This version of the Generate interface allows for multiple generations
     * into a continuous output stream of disjoint paths in the storage. The
     * first time it is invoked internal state will be reset. Subsequent
     * invocations will not reset the output stream state.
     */

    char *Generate(const char *sen, e4_Node nn);

    /*
     * Get the accumulated XML output.
     *
     * NOTE: The default output processor functionality will return 
     * a char pointer to the generated output buffer. This buffer may
     * not be complete if there is an error state set.
     *
     * If the default output processor has been substituted by a client
     * output processor the char pointer returned has a context determined
     * by the client's subclass.
     */

    char *Get();

    /*
     * As a service we export BASE64 encoding functionality. The returned
     * character string buffer must be deleted by the caller when no longer
     * needed.
     */

    char *Base64_Encode(byte *bytes, int len);

    /*
     * Operations to control the behavior of exporting pure or marked up
     * XML.
     */

     inline void SetExportXML(bool ex) { exportPureXML = ex; }
     inline bool IsExportXML() const { return exportPureXML; }

    /*
     * Get and set an XML output stream instance associated with
     * this generator.
     */

    inline e4_XMLOutputStream *GetXMLOutputStream() {return outputStream;}
    inline bool SetXMLOutputStream(e4_XMLOutputStream *np) {
	if (np == NULL) {
	    outputStream = &defaultXMLOutputStream;
	    outputProcessor->SetOutputStream(outputStream);
	    return false;
	}
	outputStream = np;
	outputProcessor->SetOutputStream(outputStream);
	return true;
    }

    /*
     * Get and set an XML output processor instance associated with
     * this generator.
     */

    inline e4_XMLOutputProcessor *GetXMLProcessor() {return outputProcessor;}
    inline bool SetXMLOutputProcessor(e4_XMLOutputProcessor *np) {
	if (np == NULL) {
	    outputProcessor = &defaultXMLOutputProcessor;
	    outputProcessor->SetOutputStream(outputStream);
	    outputProcessor->SetGenerator(this);
	    return false;
	}
	outputProcessor = np;
	outputProcessor->SetOutputStream(outputStream);
	outputProcessor->SetGenerator(this);
	return true;
    }

private:
    /*
     * Reset the state of this generator to empty.
     */

    void Reset();

    /*
     * Generate XML output for a node.
     */

    bool GenerateNode(char *elname, e4_Node nn, int ud);

    /*
     * Generate XML output for a vertex.
     */

    bool GenerateVertex(e4_Vertex vv);

    /*
     * Generate XML output for attributes of a node.
     */

    bool GenerateAttributes(e4_Node attrs, e4_DString &dsAttrs) const;

    /*
     * Generate output for DOCTYPE element declarations.
     */

    bool GenerateElementDecls(e4_Node doctype) const;
};

#endif	/* __E4_XML_H__ */
