// XMLParser.h: interface for the WMXMLParser class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003 Robert Cunnings. All rights reserved.
//
// You may copy, modify, distribute or publish this code free of charge.
//
// NO WARRANTY: This software is provided AS IS, without warranty of any kind.
//
//////////////////////////////////////////////////////////////////////
//
// XMLParser class - a no frills XML parser that generates SAX like events
// while parsing. Event handlers must inherit from class WMXMLEventHandler
// (defined in XMLParser.h). Input is accepted in UTF8 or UTF16 encoding.
// The parser converts UTF8 to UNICODE for the purpose of parsing the document.
// UTF16 input must have the proper BOM at the start. Namespaces are supported.
//  
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_XMLPARSER_H__2FE7B4F1_2B9A_11D4_9E67_00105AABC815__INCLUDED_)
#define AFX_XMLPARSER_H__2FE7B4F1_2B9A_11D4_9E67_00105AABC815__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <tchar.h>
#include <vector>
#include <string>
#include <list>
#include <map>
#include <stack>
using namespace std;

class WMXMLElement;
class WMXMLEventHandler;

typedef map<wstring, wstring> NSPrefixMap;

/////////////////////////////////////////////////////////////////
// XML Name Class
/////////////////////////////////////////////////////////////////

class WMXMLName
{
public:
	WMXMLName(const wstring& wstrQualifiedName);
	~WMXMLName();
	const wstring& GetURI();
	const wstring& GetLocalName();
	const wstring& GetQualifiedName();

	void SetURI(const wstring& wstrURI);
	void SetLocalName(const wstring& wstrLocalName);
	void SetQualifiedName(const wstring& wstrQualifiedName);

	virtual bool Matches(WMXMLName& XMLName);

private:
    wstring			m_wstrURI;
    wstring			m_wstrLocalName;
    wstring			m_wstrQualifiedName;
};

/////////////////////////////////////////////////////////////////
// Attribute classes
/////////////////////////////////////////////////////////////////

class WMXMLAttribute : public WMXMLName
{
public:
	WMXMLAttribute(const wstring& wstrQualifiedName, const wstring& wstrValue);
	WMXMLAttribute(WMXMLAttribute& Attr);
	~WMXMLAttribute();
	const wstring& GetElementName();
	const wstring& GetElementNS();
	void SetElementName(const wstring& wstrName);
	void SetElementNS(const wstring& wstrNS);
	const wstring& GetValue();

	bool Matches(WMXMLAttribute& XMLAttr);

private:
	wstring		m_wstrElementName;
	wstring		m_wstrElementNS;
	wstring		m_wstrValue;
};

class WMXMLAttributeMap : public map<wstring, WMXMLAttribute *>
{
public:
	WMXMLAttributeMap();
	~WMXMLAttributeMap();
	void AddAttribute(const wstring& wstrQualifiedName, const wstring& wstrValue);
};

/////////////////////////////////////////////////////////////////
// WMXMLMarkup class and derivatives
/////////////////////////////////////////////////////////////////
class WMXMLMarkup  
{
public:
	WMXMLMarkup();
	WMXMLMarkup(const wstring& wstrName);
	virtual ~WMXMLMarkup();

	const wstring& GetContent();
	void SetContent(const wstring& wstrValue);
	void AppendContent(const wstring& wstrChars);
	void AppendContent(wchar_t c);

private:
    wstring		m_wstrContent;
};

typedef list<WMXMLElement *> ChildElementsList;

class WMXMLElement : public WMXMLName, public WMXMLMarkup
{
public:
	WMXMLElement(WMXMLElement& Elem);
	WMXMLElement(const wstring& wstrQualifiedName);
    WMXMLElement(   const wstring& wstrQualifiedName,
                    const wstring& wstrNamespaceURI,
                    const wstring& wstrLocalName);
	virtual ~WMXMLElement();

	bool SetAttribute(const wstring& wstrName, const wstring& wstrValue);
	bool SetNSPrefix(const wstring& wstrPrefix, const wstring& wstrNS);
	bool SetAttribute(  const wstring& wstrQualifiedName,
						const wstring& wstrNS,
						const wstring& wstrValue);
	bool GetAttribute(  const wstring& wstrNS,
						const wstring& wstrLocalName,
						wstring& wstrValue);
	WMXMLAttributeMap& GetAttributeMap();
	void AddChildElement(WMXMLElement *pChild);
	WMXMLElement *GetChildElement(const wstring& wstrNS, const wstring& wstrLocalName);
	WMXMLElement *GetNestedElement(const wstring& wstrNS, const wstring& wstrLocalName);
	ChildElementsList& GetChildElements();
	NSPrefixMap& GetNSPrefixMap();
	wstring& GetDefaultNS();
    void SetDefaultNS(const wstring& wstrNS);
	bool ResolveNSPrefixes(WMXMLElement *pParent);
	bool ProcNamespaceDecl(WMXMLAttribute *pAttribute);
	void Serialize(WMXMLElement *pParent, wstring& wstrBuffer);
	BSTR Serialize(WMXMLElement *pParent);
    void Serialize( WMXMLElement *pParent,
                    wstring& wstrBuffer,
                    int nLevel,
                    int nIndent = 4);
	BSTR Serialize( WMXMLElement *pParent,
                    int nLevel,
                    int nIndent = 4);
	void EscElementContent(wstring& wstrContent);
	void EscAttributeValue(wstring& wstrAttValue);

private:
	WMXMLAttributeMap	m_mapAttributes;
	ChildElementsList	m_listChildren;
	// namespace support
	NSPrefixMap			m_mapNSPrefixes;
	wstring				m_wstrDefNameSpace;
};

/////////////////////////////////////////////////////////////////
// WMXMLParser class
/////////////////////////////////////////////////////////////////
class WMXMLParser  
{
public:
	WMXMLParser();
	virtual ~WMXMLParser();

	// call one of these to parse document...can throw exception
	void ParseXML(const char *pszBuffer, unsigned long ulSize, WMXMLEventHandler *pEventHandler);
	void ParseXML_UTF16_BE(const wstring& wstrBuffer, WMXMLEventHandler *pEventHandler);
	void ParseXML_UTF16_LE(const wstring& wstrBuffer, WMXMLEventHandler *pEventHandler);
	void ParseXML_WideString(const wstring& wstrBuffer, WMXMLEventHandler *pEventHandler);
	void ParseXML_WideString(const BSTR bstrBuffer, WMXMLEventHandler *pEventHandler);
	void ParseXML_UTF8(const string& strBuffer, WMXMLEventHandler *pEventHandler);
	// call SetDocRoot() to attach a WMXMLElement tree for serialization
	void SetDocRoot(WMXMLElement *pRoot);
	WMXMLElement *GetDocRoot();
	// call this if you want to own tree
	WMXMLElement *DetachDocRoot();
	// call these to serialize...depending on the output encoding desired
	int SerializeXML_UTF8(string& strUTF8);
	int SerializeXML_UTF8(char **pszUTF8);
	bool SerializeXML_UTF16_BE(wstring& wstrUTF16);
	bool SerializeXML_UTF16_LE(wstring& wstrUTF16);

private:
	// implementation
	typedef struct tagLocation
	{
		const wchar_t	*pwszLocation;
		int				nLineNbr;
	} LOCATION;

	void Error(); // throws exception
	void SaveLocation(LOCATION& Loc);
	void RestoreLocation(LOCATION& Loc);

	wchar_t NextCh();
	void PrevCh();
	bool ParseWhiteSpace();

	bool ParseCh(wchar_t c);
	bool ParseString(const wchar_t *pwszString);
	bool ParseStringInsensitive(const wchar_t *pwszString);
	bool ParseDecNumber(int& nNbr);
	bool ParseHexNumber(int& nNbr);
	bool ParseComment(wstring& wstrContent);
	bool ParseDocTypeDecl(wstring& wstrName, wstring& wstrContent);
	bool ParsePI(wstring& wstrName, wstring& wstrContent);

	bool ParseName(wstring& wstrName);
	bool Dereference(const wstring& wstrRef, wchar_t& r);
	bool ParseReference(wchar_t& r);
	bool ParseAttributeValue(wstring& wstrValue);
	bool ParseAttribute(WMXMLElement *pElement);
	bool ParseCDATA(WMXMLElement *pElement);
	bool ParseMarkup(WMXMLElement *pElement);
	bool ParseEndTag(WMXMLElement *pElement);
	bool ParseContent(WMXMLElement *pElement);
	WMXMLElement *ParseElementStart(WMXMLElement *pParent);
	WMXMLElement *ParseElement(WMXMLElement *pParent);
	void ParseMisc();
	bool ParseProlog();
	void ParseXMLDocument();

	// parse events
	void FireStartDocEvent();
	void FireEndDocEvent();
	void FireStartElementEvent(WMXMLElement *pElement);
	void FireEndElementEvent(WMXMLElement *pElement);
	void FireCharactersEvent(WMXMLElement *pElement);
	void FireFatalErrorEvent();
	void FirePIEvent(const wstring& wstrTarget, const wstring& wstrContents);
	void FireStartNSMappingEvents(WMXMLElement *pElement, WMXMLElement *pParent);
	void FireEndNSMappingEvents(WMXMLElement *pElement, WMXMLElement *pParent);

	// pointers into XML source buffer
	const wchar_t		*m_pwszStart;
	const wchar_t		*m_pwszStop;
	const wchar_t		*m_pwszCurrent;
	// current line nbr
	int					m_nLineNbr;

	// to mark location
	LOCATION			m_Location;

	// Reference entity map
	map<wstring, wchar_t> m_mapReferences;

	// event handler object pointer
	WMXMLEventHandler	*m_pEventHandler;

	// document root element
	WMXMLElement		*m_pDocRoot;

	// build parse tree?
	bool				m_bBuildTree;
};

/////////////////////////////////////////////////////////////////
// WMXMLEventHandler class
//
// SAX like event handler interface.
// Inherit from this abstract class to implement a parser event handler.
//
/////////////////////////////////////////////////////////////////
class WMXMLEventHandler  
{
public:
	WMXMLEventHandler() {}
	virtual ~WMXMLEventHandler() {}

    virtual void StartDocument() {}
    virtual void EndDocument() {}

    virtual WMXMLEventHandler *StartElement(const wstring& wstrURI,
											const wstring& wstrLocalName,
											const wstring& wstrQualifiedName,
											WMXMLAttributeMap& mapAttributes,
											WMXMLElement *pElement) = 0;

	virtual bool EndElement(const wstring& wstrURI,
							const wstring& wstrLocalName,
							const wstring& wstrQualifiedName,
							WMXMLElement *pElement) { return true; }

    virtual void Characters(const wstring& wstrChars) {}

	virtual void FatalError(int nLineNbr) {}

	virtual void ProcessingInstruction(const wstring& wstrTarget, const wstring& wstrContent) {}

	virtual void StartNSPrefixMapping(const wstring& wstrPrefix, const wstring& wstrURI) {}
	virtual void EndNSPrefixMapping(const wstring& wstrPrefix) {}
};

#include "XMLParser.inl"

#endif // !defined(AFX_XMLPARSER_H__2FE7B4F1_2B9A_11D4_9E67_00105AABC815__INCLUDED_)
