Click here to Skip to main content
15,886,362 members
Articles / Desktop Programming / MFC

Customizable Window Layouts

Rate me:
Please Sign up or sign in to vote.
5.00/5 (16 votes)
28 Jul 2008CPOL6 min read 40K   1.8K   51  
A class to facilitate user defined dialog and window control layouts.
////////////////////////////////////////////////
// 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions