⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 simplexml.inl

📁 symbian s60上的GPS
💻 INL
📖 第 1 页 / 共 2 页
字号:
/*
* ============================================================================
*  Name 	: CSimpleXml from SimpleXml.cpp
*  Created	: 27/11/2003 by EMCC Software Ltd
*  Description:	Parsing and generation of a simple subset of XML
*  Version	: 1
*  Copyright: EMCC Software Ltd
* ============================================================================
*/

#include "SimpleXml.h"

// Debugging TRACE macro
#include <e32svr.h>
#ifdef _DEBUG
#define TRACE RDebug::Print
#else
#define TRACE if (0) RDebug::Print
#endif

// Literal strings are accessed through templated functions generated by the
// following macro. This allows ASCII or Unicode literals to be generated as
// appropriate, whilst still only defining the string in one place and generating
// one copy of each string in memory (or two copies if both Unicode and Ascii
// parsers are used within the same app)

#define XML_DEFINE_STRING(name, string)													\
	void Str##name(const TDesC8*& aT)	/* ASCII specialization */			\
		{																				\
		_LIT8(str, string);																\
		aT = &str;																		\
		}																				\
	 void Str##name(const TDesC16*& aT)	/* Unicode specialization */		\
		{																				\
		_LIT16(str, string);															\
		aT = &str;																		\
		}																				\
	static const TInt name##_Len = sizeof(string) - 1;

#define XML_USE_STRING(name)															\
	const TXmlDesC *name##_Ptr;															\
	Str##name(name##_Ptr);

XML_DEFINE_STRING(XmlDeclaration, "<?xml version=\"1.0\"?>")
XML_DEFINE_STRING(XmlDeclarationMarker, "<?xml")
XML_DEFINE_STRING(XmlDeclarationEnd, "?>")

XML_DEFINE_STRING(XmlEntityAmp, "&amp;")
XML_DEFINE_STRING(XmlEntityLt, "&lt;")
XML_DEFINE_STRING(XmlEntityGt, "&gt;")
XML_DEFINE_STRING(XmlEntityApos, "&apos;")
XML_DEFINE_STRING(XmlEntityQuot, "&quot;")

const TInt KOutputBufferGranularity = 256;

/*
* ============================================================================
* CSimpleXml class implementation
* ============================================================================
*/

/**
* Two-phase construction
*/

CSimpleXml* CSimpleXml::NewL()
	{
	CSimpleXml* self = NewLC();
	CleanupStack::Pop(self);
    return self;
	}


CSimpleXml* CSimpleXml::NewLC()
	{
	CSimpleXml* self = new (ELeave) CSimpleXml();
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
	}

/**
* First-phase constructor
*/

CSimpleXml::CSimpleXml()
    {
	iMaxNesting = KDefaultMaxXmlElementNesting;
    }

/**
* Second-phase constructor
*/

void CSimpleXml::ConstructL()
	{
	TRACE(_L("CSimpleXml::ConstructL\n"));
    }

/**
* Destructor
*/

CSimpleXml::~CSimpleXml()
	{
	Reset();
	}

/**
* Parse
* Generates an internal representation of the input XML source
*/

void CSimpleXml::ParseL(const TXmlDesC &aXml)
	{
	// Set member variables to reference the input XML
	iAllXml.Set(aXml);
	iCurXml.Set(aXml);

	// Clear out any existing XML internal representation
	delete iRootElement;
	iRootElement = NULL;

	// Process the XML declaration which should appear at the top of the XML
	if (FindNextChunkL() == EChunkXmlDeclaration)
		{
		GetXmlDeclarationL();
		}

	// Now process the root element (and all contents thereof, i.e. everything)

	if (FindNextChunkL() != EChunkXmlElement)
		{
		User::Leave(/*KErrArgument*/KErrNoMemory);
		}
	iRootElement = new (ELeave) CXmlElement();
	iNesting = -1;						// root element will be at nesting level 0
	GetXmlElementL(*iRootElement);
	__ASSERT_DEBUG(iNesting == -1, Panic(EPanicBadNesting));	// shouldn't be possible
	}
/**
* RootElement
* Accessor for the root element
*/


CXmlElement& CSimpleXml::RootElement() const
	{
	if (!iRootElement) Panic(EPanicNoRootElement);
	return *iRootElement;
	}


/**
* Reset
* Clear out the internal XML representation
*/


void CSimpleXml::Reset()
	{
	delete iRootElement;
	iRootElement = NULL;
	delete iTempBuf;
	iTempBuf = NULL;
	iXmlAttributes.ResetAndDestroy();
	}

/**
* CreateRootElementL
* Create a new root element (replaces any existing data)
*/


CXmlElement& CSimpleXml::CreateRootElementL(const TXmlDesC &aName)
	{
	Reset();
	iRootElement = new (ELeave) CXmlElement();
	iRootElement->iName = aName.AllocL();
	return *iRootElement;
	}

/**
* Output our contents as XML text
*/


HXmlBufC *CSimpleXml::OutputLC()
	{
	HXmlBufC *output = OutputL();
	CleanupStack::PushL(output);
	return output;
	}


HXmlBufC *CSimpleXml::OutputL()
	{
	// We will use a segmented array of text characters to buffer the output, so that the array
	// class will manage the complexities of growing the temporary output buffer for us, and in a reasonably
	// efficient fashion
	delete iTempBuf;
	iTempBuf = NULL;
	iTempBuf = new (ELeave) CArrayFixSeg<TXmlText>(KOutputBufferGranularity);

	// Now output the XML to the temporary array buffer
	// Start with the XML declaration
	XML_USE_STRING(XmlDeclaration);
	OutputL(*XmlDeclaration_Ptr);

	// Now output the root element (and all contents thereof, i.e. everything)
	iNesting = -1;						// root element will be at nesting level 0
	OutputL(RootElement());
	__ASSERT_DEBUG(iNesting == -1, Panic(EPanicBadNesting));	// shouldn't be possible

	// Now copy the data over into an HXmlBufC for our caller.
	// Note that the HXmlBufC is not pushed onto the cleanup stack: this is because we aren't
	// calling anything that might leave.
	TInt count = iTempBuf->Count();
	HXmlBufC *outBuf = HXmlBufC::NewL(count);	// N.B. not pushed onto cleanup stack
	TXmlPtr outPtr = outBuf->Des();

	// Copy the array data one segment at a time
	for (TInt nIndex = 0; nIndex < count; nIndex += KOutputBufferGranularity)
		{
		TInt toMove = Min(KOutputBufferGranularity, count - nIndex);
		TXmlText *seg = &iTempBuf->At(nIndex);
		outPtr.Append(seg, toMove);
		}

	delete iTempBuf;
	iTempBuf = NULL;

	return outBuf;
	}

/**
* FindNextChunkL
* Finds the start of the next chunk and determines its type
*/


CSimpleXml::TChunkType CSimpleXml::FindNextChunkL()
	{
	// find next non-white-space character
	TChar c;
	TInt i;
	for (i = 0; (c = iCurXml[i]).IsSpace(); ++i)
		;

	if (c == '<')
		{
		iCurXml.Set(iCurXml.Mid(i));	// step the current pointer
		c = iCurXml[1];					// pick up the character after '<'
		return c == '?' ? EChunkXmlDeclaration
				: c == '/' ? EChunkXmlElementEnd
				: EChunkXmlElement;
		}
	else
		{
		return EChunkText;
		}
	}

/**
* GetXmlDeclarationL
*/


void CSimpleXml::GetXmlDeclarationL()
	{
	// Crude first implementation
	XML_USE_STRING(XmlDeclarationMarker);
	if (iCurXml.Left(XmlDeclarationMarker_Len) != *XmlDeclarationMarker_Ptr)
		{
		User::Leave(/*KErrArgument*/KErrNotSupported);
		}
	iCurXml.Set(iCurXml.Mid(XmlDeclarationMarker_Len));

	// Read any attributes in the XML declaration
	while (GetPossibleAttributeL(iXmlAttributes))
		continue;
	// (above call has stepped past any white space)

	// Check that the XML declaration is terminated by "?>"
	XML_USE_STRING(XmlDeclarationEnd);
	if (iCurXml.Left(XmlDeclarationEnd_Len) != *XmlDeclarationEnd_Ptr)
		{
		User::Leave(/*KErrArgument*/KErrTotalLossOfPrecision);
		}
	iCurXml.Set(iCurXml.Mid(XmlDeclarationEnd_Len));
	}

/**
* GetXmlElementL
*/


void CSimpleXml::GetXmlElementL(CXmlElement &aElement)
	{
	// Protect against stack overflow by limiting the depth to which elements
	// can be nested, since we will be parsing recursively
	if (++iNesting > iMaxNesting)
		{
		User::Leave(KErrArgument);
		}

	iCurXml.Set(iCurXml.Mid(1));	// step past '<'
	GetNameL(aElement.iName);

	while (GetPossibleAttributeL(aElement.iAttributes))
		continue;
	// (above call has stepped past any white space)

	if (iCurXml[0] == '/')
		{
		// (no space allowed here)
		if (iCurXml[1] != '>')
			{
			User::Leave(KErrArgument);
			}
		iCurXml.Set(iCurXml.Mid(2));	// step past "/>"
		--iNesting;						// reduce nesting level
		return;							// empty element processing finished
		}

	if (iCurXml[0] != '>')
		{
		User::Leave(KErrArgument);
		}
	iCurXml.Set(iCurXml.Mid(1));		// step past ">"

	TChunkType type;
	do
		{
		switch (type = FindNextChunkL())
			{
			case EChunkXmlElement:
				{
				CXmlElement& newElement = aElement.AddElementL();
				GetXmlElementL(newElement);
				break;
				}

			case EChunkText:
				{
				CXmlText& newText = aElement.AddTextL();
				GetTextL(newText.iText);
				break;
				}

			case EChunkXmlElementEnd:
				{
				// Step to the character after "</" which should be the start of the name
				iCurXml.Set(iCurXml.Mid(2));
				HXmlBufC *endName;
				GetNameL(endName);
				TBool same = *endName == *aElement.iName;
				delete endName;
				if (!same) User::Leave(KErrArgument);
				if (iCurXml[0] != '>') User::Leave(KErrArgument);
				iCurXml.Set(iCurXml.Mid(1));	// step past terminating '>'
				break;
				}

			default:
				User::Leave(KErrArgument);
			}
		} while (type != EChunkXmlElementEnd);

	--iNesting;				// reduce nesting level
	}

/**
* GetNameL
*/


void CSimpleXml::GetNameL(HXmlBufC*& aName)
	{
	// check the first character is a letter or underscore
	TChar c = iCurXml[0];
	if (!c.IsAlpha() && c != '_')
		{
		User::Leave(/*KErrArgument*/KErrBadHandle);
		}

	// find first non-name character after this (XML names can
	// contain letters, digits, hyphens, full-stops and underlines
	TInt i;
	for (i = 1; ; ++i)
		{
		c = iCurXml[i];
		if (!c.IsAlphaDigit() && c != '-' && c != '.' && c != '_')
			break;						// end of name found
		}

	// set up the name in allocated memory for caller (who takes responsibility
	// for it - but we must not leave once we have allocated the memory...)
	aName = iCurXml.Left(i).AllocL();

	iCurXml.Set(iCurXml.Mid(i));	// step the current pointer past the name
	}


/**
* GetPossibleAttributeL
*/


TBool CSimpleXml::GetPossibleAttributeL(RPointerArray<CXmlAttribute >& aAttributeList)
	{
	// step past any white space
	TInt i;
	TChar c;
	for (i = 0; (c = iCurXml[i]).IsSpace(); ++i)
		;

	if (i == 0) return FALSE;	// no whitespace separator means no attribute found

	iCurXml.Set(iCurXml.Mid(i));	// step the current pointer past the white space

	if (!c.IsAlpha() && c != '_') return FALSE;	// not a valid attribute name start

	// From here on, we know that the data ought to be an attribute and we will Leave
	// if the format is wrong

	// Create a new attribute object and add it to the array of attributes for this element
	CXmlAttribute &attrib = CXmlAttribute::AddAttributeToListL(aAttributeList);

	// Fill in the attribute name keyword
	GetNameL(attrib.iKeyword);

	// Step past any (optional) white space
	for (i = 0; (c = iCurXml[i]).IsSpace(); ++i)
		;

	// Ensure "equals" sign separator is present
	if (c != '=') User::Leave(/*KErrArgument*/KErrUnderflow);

	// Step past any (optional) white space
	TChar quote;
	for (++i; (quote = iCurXml[i]).IsSpace(); ++i)
		;

	// Validate the starting quotation mark for the attribute value
	if (quote != TChar('"') && quote != TChar('\'')) User::Leave(KErrArgument);

	iCurXml.Set(iCurXml.Mid(i + 1));	// step the current pointer to the start of the value

	GetTextL(attrib.iValue, quote);	// get text, with entity resolution, till end quote found

	if (iCurXml[0] != (TXmlText) quote) User::Leave(/*KErrArgument*/KErrAlreadyExists);
	iCurXml.Set(iCurXml.Mid(1));		// step the current pointer past the end quote
	return ETrue;
	}

/**
* GetTextL
*/


void CSimpleXml::GetTextL(HXmlBufC*& aText, TChar aQuote /* = 0 */)
	{
	TInt pass;
	TXmlPtr output(NULL, 0);

	XML_USE_STRING(XmlEntityAmp);
	XML_USE_STRING(XmlEntityLt);
	XML_USE_STRING(XmlEntityGt);
	XML_USE_STRING(XmlEntityApos);
	XML_USE_STRING(XmlEntityQuot);

	// Use two passes through the data - first pass calculates the length only; second
	// pass outputs the converted data. This saves having to re-allocate buffers as the data
	// grows.
	for (pass = 1; pass <= 2; ++pass)
		{
		TInt i = 0;
		TChar c;
		// Not strictly kosher XML behaviour, but we will strip out all leading and trailing white

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -