|
////////////////////////////////////////////////
// xmlfile.cpp
//
// 2008 Roland Trainor
//
#include "stdafx.h"
#include "xmlfile.h"
#include <io.h>
#include <fstream>
#include <sstream>
#define XMLFILEPARSER_MAXBUFFER_SIZE 65536
////////////////////////////////////////////////
// CXMLParser
//
// This class is intended to provide a simple
// mechanism for loading and parsing-out information
// from an XML-based file.
//
// Construction/destruction...
CXMLParser::CXMLParser() :
m_lNumCharactersProcessed(0),
m_lNumCharactersInFile(0)
{
}
CXMLParser::~CXMLParser()
{
}
// Persistance...
void CXMLParser::ParseFile(LPCSTR lpszFilename)
{
// Open the file...
FILE* fp = fopen(lpszFilename, "rb");
if (fp)
{
// Get the number of characters in the file...
m_lNumCharactersInFile = _filelength(_fileno(fp));
// Close the file...
fclose(fp);
// Open the file into a binary file stream...
std::ifstream fileStream;
fileStream.open(lpszFilename, std::ios::binary);
// Parse and process the file's data...
ParseStream(&fileStream);
}
else
{
CString strMsg;
strMsg.Format("Unable to open file %s in CXMLParser::ParseFile", lpszFilename);
throw Exception(strMsg);
}
}
void CXMLParser::ParseString(LPCSTR lpszText)
{
// Get the number of characters in the string...
m_lNumCharactersInFile = strlen(lpszText);
// Parse and process the string's data...
std::istringstream stringStream(lpszText);
ParseStream(&stringStream);
}
void CXMLParser::ParseStream(std::istream* pStream)
{
DWORD dwStart = ::GetTickCount();
m_lNumCharactersProcessed = 0;
try
{
// Parse the XML-based data...
bool bElementTag = false;
char strElementData[XMLFILEPARSER_MAXBUFFER_SIZE];
int nElementDataPos = 0;
char strElementTag[XMLFILEPARSER_MAXBUFFER_SIZE];
int nElementTagPos = 0;
void* pUserData = NULL;
char c;
pStream->get(c);
m_lNumCharactersProcessed++;
while (!pStream->eof())
{
if (bElementTag && ((c == '>') || (c == ' ')))
{
strElementTag[nElementTagPos] = NULL;
char* strElementTagEndPos = strchr(strElementTag, '/');
int nEndTag = strElementTagEndPos - strElementTag;
int nComment = strstr(strElementTag, "!--") - strElementTag;
if (nEndTag >= 0)
{
if (nElementDataPos > 0)
{
strElementData[nElementDataPos] = NULL;
try { pUserData = OnElementData(strElementData, pUserData); }
catch (...) { throw Exception("Unhandled exception encountered in call to OnElementData"); }
nElementDataPos = 0;
}
if (nEndTag == 0)
{
strElementTagEndPos = strElementTag + 1;
}
else
{
*strElementTagEndPos = NULL;
strElementTagEndPos = strElementTag;
}
try { pUserData = OnElementEnd(strElementTagEndPos, pUserData); }
catch (...) { throw Exception("Unhandled exception encountered in call to OnElementEnd"); }
if (pStream->peek() == '\n')
ParseOverWhiteSpace(pStream);
}
else if (nComment >= 0)
{
pUserData = ParseComment(pStream, pUserData);
ParseOverWhiteSpace(pStream);
}
else if (strElementData[0] == '?')
{
char* strElementTagPos = strElementTag + 1;
pUserData = ParseProcessingInstruction(pStream, strElementTagPos, pUserData);
ParseOverWhiteSpace(pStream);
}
else
{
if (nElementDataPos > 0)
{
strElementData[nElementDataPos] = NULL;
try { pUserData = OnElementData(strElementData, pUserData); }
catch (...) { throw Exception("Unhandled exception encountered in call to OnElementData"); }
nElementDataPos = 0;
}
try { pUserData = OnElementBegin(strElementTag, pUserData); }
catch (...) { throw Exception("Unhandled exception encountered in call to OnElementBegin"); }
if (c == ' ')
pUserData = ParseProperties(pStream, pUserData);
ParseOverWhiteSpace(pStream);
}
bElementTag = false;
nElementTagPos = 0;
}
else if (bElementTag)
{
strElementTag[nElementTagPos++] = c;
if (nElementTagPos >= XMLFILEPARSER_MAXBUFFER_SIZE)
throw Exception("Buffer overflow ecountered while parsing an element tag in CXMLParser::ParseStream");
}
else if (c == '<')
{
bElementTag = true;
}
else
{
strElementData[nElementDataPos++] = c;
if (nElementDataPos >= XMLFILEPARSER_MAXBUFFER_SIZE)
throw Exception("Buffer overflow ecountered while parsing an element data in CXMLParser::ParseStream");
}
pStream->get(c);
m_lNumCharactersProcessed++;
}
strElementData[nElementDataPos] = NULL;
try { pUserData = OnElementData(strElementData, pUserData); }
catch (...) { throw Exception("Unhandled exception encountered in call to OnElementData"); }
nElementDataPos = 0;
}
catch (Exception& exception)
{
TRACE("CXMLParser::ParseStream -> Exception:%s\n", exception.GetErrorMessage());
throw exception;
}
catch (...)
{
TRACE("CXMLParser::ParseStream -> Unhandled Exception\n");
throw Exception("Unhandled Exception ecountered in CXMLParser::ParseStream");
}
//TRACE("CXMLParser::ParseStream ParseTime:%ldms\n", GetTickCount() - dwStart);
}
void* CXMLParser::ParseComment(std::istream* pStream, void* pUserData)
{
// Parse the comment...
char strComment[XMLFILEPARSER_MAXBUFFER_SIZE];
int nCommentPos = 0;
char c;
pStream->get(c);
m_lNumCharactersProcessed++;
while (!pStream->eof())
{
if (c == '>')
{
if ((strComment[nCommentPos - 1] == '-') &&
(strComment[nCommentPos - 1] == '-'))
{
nCommentPos -= 2;
strComment[nCommentPos] = NULL;
try { pUserData = OnComment(strComment, pUserData); }
catch (...) { throw Exception("Unhandled exception encountered in call to OnComment"); }
return pUserData;
}
else
{
strComment[nCommentPos++] = c;
if (nCommentPos >= XMLFILEPARSER_MAXBUFFER_SIZE)
throw Exception("Buffer overflow ecountered while parsing a comment in CXMLParser::ParseComment");
}
}
else
{
strComment[nCommentPos++] = c;
if (nCommentPos >= XMLFILEPARSER_MAXBUFFER_SIZE)
throw Exception("Buffer overflow ecountered while parsing a comment in CXMLParser::ParseComment");
}
pStream->get(c);
m_lNumCharactersProcessed++;
}
throw Exception("Unexpected EndOfFile encountered while parsing a comment in CXMLParser::ParseComment");
return pUserData;
}
void* CXMLParser::ParseProperties(std::istream* pStream, void* pUserData)
{
// Parse the properties/attributes...
char strName[XMLFILEPARSER_MAXBUFFER_SIZE];
int nNamePos = 0;
char strValue[XMLFILEPARSER_MAXBUFFER_SIZE];
int nValuePos = 0;
bool bName = true;
bool bValue = false;
bool bInQuote = false;
char c;
pStream->get(c);
m_lNumCharactersProcessed++;
while (!pStream->eof())
{
if (c == '=')
{
bName = false;
bValue = true;
}
else if (c == '"')
{
bInQuote = !bInQuote;
if (!bInQuote)
{
strName[nNamePos] = NULL;
strValue[nValuePos] = NULL;
try { pUserData = OnProperty(strName, strValue, pUserData); }
catch (...) { throw Exception("Unhandled exception encountered in call to OnProperty"); }
bName = false;
bValue = false;
nNamePos = 0;
nValuePos = 0;
}
}
else if (bName)
{
strName[nNamePos++] = c;
if (nNamePos >= XMLFILEPARSER_MAXBUFFER_SIZE)
throw Exception("Buffer overflow ecountered while parsing a property name in CXMLParser::ParseProperties");
}
else if (bValue)
{
strValue[nValuePos++] = c;
if (nValuePos >= XMLFILEPARSER_MAXBUFFER_SIZE)
throw Exception("Buffer overflow ecountered while parsing a property value in CXMLParser::ParseProperties");
}
else if (c == '>')
{
return pUserData;
}
else if (c != ' ')
{
strName[nNamePos++] = c;
if (nNamePos >= XMLFILEPARSER_MAXBUFFER_SIZE)
throw Exception("Buffer overflow ecountered while parsing a property name in CXMLParser::ParseProperties");
bName = true;
}
pStream->get(c);
m_lNumCharactersProcessed++;
}
throw Exception("Unexpected EndOfFile encountered while parsing properties in CXMLParser::ParseProperties");
return pUserData;
}
void* CXMLParser::ParseProcessingInstruction(std::istream* pStream, LPCSTR lpszTarget, void* pUserData)
{
try { pUserData = OnProcessingInstructionBegin(lpszTarget, pUserData); }
catch (...) { throw Exception("Unhandled exception encountered in call to OnProcessingInstructionBegin"); }
// Parse the instruction's properties/attributes...
char c;
pStream->get(c);
m_lNumCharactersProcessed++;
while (!pStream->eof())
{
if (c == '>')
{
try { pUserData = OnProcessingInstructionEnd(lpszTarget, pUserData); }
catch (...) { throw Exception("Unhandled exception encountered in call to OnProcessingInstructionEnd"); }
return pUserData;
}
else
{
pUserData = ParseProperties(pStream, pUserData);
}
pStream->get(c);
m_lNumCharactersProcessed++;
}
throw Exception("Unexpected EndOfFile encountered while parsing a comment in CXMLParser::ParseProcessingInstruction");
return pUserData;
}
void CXMLParser::ParseOverWhiteSpace(std::istream* pStream)
{
char c;
pStream->get(c);
m_lNumCharactersProcessed++;
while (!pStream->eof())
{
if ((c != 0x09) && (c != 0x0A) && (c != 0x0D) && (c != 0x020))
{
pStream->seekg(-1, std::ios::cur);
m_lNumCharactersProcessed--;
return;
}
pStream->get(c);
m_lNumCharactersProcessed++;
}
if (m_lNumCharactersProcessed < m_lNumCharactersInFile)
throw Exception("Unexpected EndOfFile encountered while parsing a comment in CXMLParser::ParseOverWhiteSpace");
}
// Processing...
void* CXMLParser::OnProcessingInstructionBegin(LPCSTR lpszTarget, void* pUserData)
{
return pUserData;
}
void* CXMLParser::OnProcessingInstructionEnd(LPCSTR lpszTarget, void* pUserData)
{
return pUserData;
}
void* CXMLParser::OnElementBegin(LPCSTR lpszElementTag, void* pUserData)
{
return pUserData;
}
void* CXMLParser::OnElementData(LPCSTR lpszElementData, void* pUserData)
{
return pUserData;
}
void* CXMLParser::OnElementEnd(LPCSTR lpszElementTag, void* pUserData)
{
return pUserData;
}
void* CXMLParser::OnProperty(LPCSTR lpszPropertyName, LPCSTR lpszPropertyValue, void* pUserData)
{
return pUserData;
}
void* CXMLParser::OnComment(LPCSTR lpszComment, void* pUserData)
{
return pUserData;
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.