Subversion Repositories tpanel

Rev

Rev 323 | Blame | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2022 by Andreas Theofilu <andreas@theosys.at>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

#include <fstream>
#include <iomanip>

#include <string.h>

#include "texpat++.h"
#include "terror.h"

using namespace Expat;
using std::string;
using std::vector;
using std::ifstream;

int TExpat::mDepth = 0;
string TExpat::mContent;
string TExpat::mLastName;
vector<_ATTRIBUTE_t> TExpat::mAttributes;

TExpat::TExpat()
{
    DECL_TRACER("TExpat::TExpat()");
}

TExpat::TExpat(const std::string &file)
    : mFile(file)
{
    DECL_TRACER("TExpat::TExpat(const std::string &file)");

    mLastIter = mElements.end();
}

TExpat::~TExpat()
{
    DECL_TRACER("TExpat::~TExpat()");
}

void TExpat::setEncoding(TENCODING_t enc)
{
    DECL_TRACER("TExpat::setEncoding(TENCODING_t enc)");

    mSetEncoding = enc;

    switch(enc)
    {
        case ENC_ISO_8859_1:    mEncoding = "ISO-8859-1"; break;
        case ENC_US_ASCII:      mEncoding = "US-ASCII"; break;
        case ENC_UTF16:         mEncoding = "UTF-16"; break;
        case ENC_CP1250:        mEncoding = "CP1250"; break;

        default:
            mEncoding = "UTF-8";
            mSetEncoding = ENC_UTF8;
    }
}

bool TExpat::parse(bool debug)
{
    DECL_TRACER("TExpat::parse()");

    if (!isValidFile(mFile))
    {
        MSG_ERROR("Invalid file: " << mFile);
        TError::setError();
        return false;
    }

    string buf;
    size_t size = 0;

    // First we read the whole XML file into a buffer
    try
    {
        ifstream stream(mFile, std::ios::in);

        if (!stream || !stream.is_open())
            return false;

        stream.seekg(0, stream.end);    // Find the end of the file
        size = stream.tellg();          // Get the position and save it
        stream.seekg(0, stream.beg);    // rewind to the beginning of the file

        buf.resize(size, '\0');         // Initialize the buffer with zeros
        char *begin = &*buf.begin();    // Assign the plain data buffer
        stream.read(begin, size);       // Read the whole file
        stream.close();                 // Close the file
    }
    catch (std::exception& e)
    {
        MSG_ERROR("File error: " << e.what());
        TError::setError();
        return false;
    }

    // Now we parse the file and write the relevant contents into our internal
    // variables.
    // First we initialialize the parser.
    int done = 1;   // 1 = Buffer is complete
    XML_Parser parser = XML_ParserCreate(NULL);
    XML_SetElementHandler(parser, &TExpat::startElement, &TExpat::endElement);
    XML_SetCharacterDataHandler(parser, &TExpat::CharacterDataHandler);
    XML_SetEncoding(parser, mEncoding.c_str());
    XML_SetUserData(parser, &mElements);

    if (mSetEncoding == ENC_CP1250)
        XML_SetUnknownEncodingHandler(parser, &TExpat::cp1250_encoding_handler, NULL);

    MSG_TRACE("Parsing XML file " << mFile);

    if (XML_Parse(parser, buf.data(), size, done) == XML_STATUS_ERROR)
    {
        MSG_ERROR(XML_ErrorString(XML_GetErrorCode(parser)) << " at line " << XML_GetCurrentLineNumber(parser));
        XML_ParserFree(parser);
        TError::setError();
        return false;
    }

    XML_ParserFree(parser);

    if (TStreamError::checkFilter(HLOG_DEBUG) && debug && mElements.size() > 0)
    {
        // Print out the whole XML file formatted
        vector<_ELEMENT_t>::iterator iter;
        size_t cnt = 0;

        for (iter = mElements.begin(); iter != mElements.end(); ++iter)
        {
            string sIndent;

            for (int i = 0; i < iter->depth; i++)
                sIndent += "   ";

            string attrs;

            if ((iter->eType == _ET_START || iter->eType == _ET_ATOMIC) && iter->attrs.size() > 0)
            {
                vector<ATTRIBUTE_t>::iterator atiter;

                for (atiter = iter->attrs.begin(); atiter != iter->attrs.end(); ++atiter)
                {
                    if (!attrs.empty())
                        attrs += " ";

                    attrs += atiter->name + " = \"" + atiter->content + "\"";
                }
            }

            if (iter->eType == _ET_START)
            {
                if (iter->attrs.size() > 0)
                {
                    MSG_DEBUG(std::setw(3) << std::setfill(' ') << "[" << cnt << "] (" << std::setw(0) << iter->depth << ") " << sIndent << "<" << iter->name << " " << attrs << ">");
                }
                else
                {
                    MSG_DEBUG(std::setw(3) << std::setfill(' ') << "[" << cnt << "] (" << std::setw(0) << iter->depth << ") " << sIndent << "<" << iter->name << ">");
                }
            }
            else if (iter->eType == _ET_ATOMIC)
            {
                if (iter->attrs.size() > 0)
                {
                    MSG_DEBUG(std::setw(3) << std::setfill(' ') << "[" << cnt << "] (" << std::setw(0) << iter->depth << ") " << sIndent << "<" << iter->name << " " << attrs << ">" << iter->content << "</" << iter->name << ">");
                }
                else
                {
                    MSG_DEBUG(std::setw(3) << std::setfill(' ') << "[" << cnt << "] (" << std::setw(0) << iter->depth << ") " << sIndent << "<" << iter->name << ">" << iter->content << "</" << iter->name << ">");
                }
            }
            else
            {
                MSG_DEBUG(std::setw(3) << std::setfill(' ') << "[" << cnt << "] (" << std::setw(0) << iter->depth << ") " << sIndent << "</" << iter->name << ">");
            }

            cnt++;
        }
    }

    return true;
}

string TExpat::getElement(const string &name, int depth, bool *valid)
{
    DECL_TRACER("TExpat::getElement(const string &name, int depth)");

    vector<_ELEMENT_t>::iterator iter, startElement;
    bool start = false;

    if (!mElements.empty() && mLastIter != mElements.end())
        startElement = mLastIter;
    else if (!mElements.empty())
        startElement = mElements.begin();
    else
    {
        MSG_DEBUG("Have no elements in queue!");

        if (valid)
            *valid = false;

        return string();
    }

    for (iter = startElement; iter != mElements.end(); ++iter)
    {
        if (!start && iter->depth == depth && iter->eType != _ET_END)
            start = true;

        if (start && iter->eType != _ET_END && iter->name.compare(name)  == 0 && iter->depth == depth)
        {
            if (valid)
                *valid = true;

            return iter->content;
        }
        else if (start && (iter->eType == _ET_END || iter->depth != depth))
            break;
    }

    if (valid)
        *valid = false;

    return string();
}

int TExpat::getElementInt(const string &name, int depth, bool *valid)
{
    DECL_TRACER("TExpat::getElementInt(const string &name, int depth, bool *valid)");

    bool val;
    string erg = getElement(name, depth, &val);

    if (valid)
        *valid = val;

    if (!val)
        return 0;

    return atoi(erg.c_str());
}

long TExpat::getElementLong(const string &name, int depth, bool *valid)
{
    DECL_TRACER("TExpat::getElementLong(const string &name, int depth, bool *valid)");

    bool val;
    string erg = getElement(name, depth, &val);

    if (valid)
        *valid = val;

    if (!val)
        return 0;

    return atol(erg.c_str());
}

float TExpat::getElementFloat(const string &name, int depth, bool *valid)
{
    DECL_TRACER("TExpat::getElementFloat(const string &name, int depth, bool *valid)");

    bool val;
    string erg = getElement(name, depth, &val);

    if (valid)
        *valid = val;

    if (!val)
        return 0;

    return (float)atof(erg.c_str());
}

double TExpat::getElementDouble(const string &name, int depth, bool *valid)
{
    DECL_TRACER("TExpat::getElementDouble(const string &name, int depth, bool *valid)");

    bool val = false;
    string erg = getElement(name, depth, &val);

    if (valid)
        *valid = val;

    if (!val)
        return 0;

    return atof(erg.c_str());
}

size_t TExpat::getElementIndex(const string& name, int depth)
{
    DECL_TRACER("TExpat::getElementIndex(const string& name, int depth)");

    vector<_ELEMENT_t>::iterator iter;
    size_t idx = 0;

    if (mElements.size() == 0)
    {
        mLastIter = mElements.end();
        return npos;
    }

    for (iter = mElements.begin(); iter != mElements.end(); ++iter)
    {
        if (iter->eType != _ET_END && iter->name.compare(name) == 0 && iter->depth == depth)
        {
            mLastIter = iter;
            return idx;
        }

        idx++;
    }

    mLastIter = mElements.end();
    return npos;
}

size_t TExpat::getElementIndex(const string& name, int* depth)
{
    DECL_TRACER("TExpat::getElementIndex(const string& name, int* depth)");

    if (mElements.size() == 0)
    {
        mLastIter = mElements.end();
        return npos;
    }

    vector<_ELEMENT_t>::iterator iter;
    size_t idx = 0;

    for (iter = mElements.begin(); iter != mElements.end(); ++iter)
    {
        if (iter->eType != _ET_END && iter->name.compare(name) == 0)
        {
            if (depth)
                *depth = iter->depth;

            mLastIter = iter;
            return idx;
        }

        idx++;
    }

    if (depth)
        *depth = -1;

    mLastIter = mElements.end();
    return npos;
}

size_t TExpat::getElementFromIndex(size_t index, string* name, string* content, vector<ATTRIBUTE_t> *attrs)
{
    DECL_TRACER("TExpat::getElementFromIndex(size_t index, string* name, string* content, vector<ATTRIBUTE_t> *attrs)");

    if (index == npos || index >= mElements.size() || mElements.at(index).eType == _ET_END)
        return npos;

    if (name)
        name->assign(mElements.at(index).name);

    if (content)
        content->assign(mElements.at(index).content);

    if (attrs)
        *attrs = mElements.at(index).attrs;

    return index;
}

size_t TExpat::getNextElementFromIndex(size_t index, string* name, string* content, vector<ATTRIBUTE_t>* attrs)
{
    DECL_TRACER("TExpat::getNextElementFromIndex(size_t index, int depth, string* name, string* content, vector<ATTRIBUTE_t>* attrs)");

    if (index == npos)
        return npos;

    size_t idx = index + 1;

    if (idx >= mElements.size() || mElements.at(idx).eType == _ET_END)
        return npos;

    if (name)
        name->assign(mElements.at(idx).name);

    if (content)
        content->assign(mElements.at(idx).content);

    if (attrs)
        *attrs = mElements.at(idx).attrs;

    return idx;
}

string TExpat::getFirstElement(const string &name, int *depth)
{
    DECL_TRACER("TExpat::getFirstElement(const string &name, int *depth)");

    vector<_ELEMENT_t>::iterator iter;

    for (iter = mElements.begin(); iter != mElements.end(); ++iter)
    {
        if (iter->eType != _ET_END && iter->name.compare(name) == 0)
        {
            if (depth)
                *depth = iter->depth;

            mLastIter = iter;
            return iter->content;
        }
    }

    if (depth)
        *depth = -1;

    mLastIter = mElements.end();
    return string();
}

string TExpat::getNextElement(const string &name, int depth, bool *valid)
{
    DECL_TRACER("TExpat::getNextElement(const string &name, int depth)");

    if (valid)
        *valid = false;

    if (mLastIter == mElements.end())
        return string();

    mLastIter++;

    while (mLastIter != mElements.end())
    {
        if (mLastIter == mElements.end() || mLastIter->eType == _ET_END)
            return string();

        if (mLastIter->name.compare(name) == 0 && mLastIter->depth == depth)
        {
            if (valid)
                *valid = true;

            return mLastIter->content;
        }

        mLastIter++;
    }

    return string();
}

size_t TExpat::getNextElementIndex(const string& name, int depth)
{
    DECL_TRACER("TExpat::getNextElementIndex(const string& name, int depth)");

    if (mLastIter == mElements.end())
        return npos;

    mLastIter++;

    while (mLastIter != mElements.end())
    {
        if (mLastIter->eType == _ET_END && mLastIter->depth < depth)
            break;

        if (mLastIter->name.compare(name)  == 0 && mLastIter->depth == depth && mLastIter->eType != _ET_END)
        {
            size_t idx = 0;
            vector<_ELEMENT_t>::iterator iter;

            for (iter = mElements.begin(); iter != mElements.end(); ++iter)
            {
                if (iter == mLastIter)
                    return idx;

                idx++;
            }
        }

        mLastIter++;
    }

    return npos;
}

string TExpat::getAttribute(const string& name, vector<ATTRIBUTE_t>& attrs)
{
    DECL_TRACER("TExpat::getAttribute(const string& name, vector<ATTRIBUTE_t>& attrs)");

    vector<ATTRIBUTE_t>::iterator iter;

    if (attrs.size() == 0)
        return string();

    for (iter = attrs.begin(); iter != attrs.end(); ++iter)
    {
        if (iter->name.compare(name) == 0)
            return iter->content;
    }

    return string();
}

int TExpat::getAttributeInt(const string& name, vector<ATTRIBUTE_t>& attrs)
{
    DECL_TRACER("TExpat::getAttributeInt(const string& name, vector<ATTRIBUTE_t>& attrs)");

    return atoi(getAttribute(name, attrs).c_str());
}

long Expat::TExpat::getAttributeLong(const std::string& name, std::vector<ATTRIBUTE_t>& attrs)
{
    DECL_TRACER("TExpat::getAttributeLong(const string& name, vector<ATTRIBUTE_t>& attrs)");

    return atol(getAttribute(name, attrs).c_str());
}

float Expat::TExpat::getAttributeFloat(const std::string& name, std::vector<ATTRIBUTE_t>& attrs)
{
    DECL_TRACER("TExpat::getAttributeFloat(const string& name, vector<ATTRIBUTE_t>& attrs)");

    return (float)atof(getAttribute(name, attrs).c_str());
}

double Expat::TExpat::getAttributeDouble(const std::string& name, std::vector<ATTRIBUTE_t>& attrs)
{
    DECL_TRACER("TExpat::getAttributeDouble(const string& name, vector<ATTRIBUTE_t>& attrs)");

    return atof(getAttribute(name, attrs).c_str());
}

int TExpat::convertElementToInt(const string& content)
{
    DECL_TRACER("TExpat::convertElementToInt(const string& content)");

    if (content.empty())
    {
        TError::setErrorMsg("Empty content!");
        return 0;
    }

    return atoi(content.c_str());
}

long TExpat::convertElementToLong(const string& content)
{
    DECL_TRACER("TExpat::convertElementToLong(const string& content)");

    if (content.empty())
    {
        TError::setErrorMsg("Empty content!");
        return 0;
    }

    return atol(content.c_str());
}

float TExpat::convertElementToFloat(const string& content)
{
    DECL_TRACER("TExpat::convertElementToFloat(const string& content)");

    if (content.empty())
    {
        TError::setErrorMsg("Empty content!");
        return 0;
    }

    return (float)atof(content.c_str());
}

double TExpat::convertElementToDouble(const string& content)
{
    DECL_TRACER("TExpat::convertElementToDouble(const string& content)");

    if (content.empty())
    {
        TError::setErrorMsg("Empty content!");
        return 0;
    }

    return atof(content.c_str());
}

bool TExpat::setIndex(size_t index)
{
    DECL_TRACER("TExpat::setIndex(size_t index)");

    if (index >= mElements.size())
    {
        TError::setErrorMsg("Invalid index " + std::to_string(index) + "!");
        mLastIter = mElements.end();
        return false;
    }

    vector<_ELEMENT_t>::iterator iter;
    size_t idx = 0;

    for (iter = mElements.begin(); iter != mElements.end(); ++iter)
    {
        if (idx == index)
        {
            mLastIter = iter;
            return true;
        }

        idx++;
    }

    mLastIter = mElements.end();
    return false;   // Should not happen and is just for satisfy the compiler.
}

vector<ATTRIBUTE_t> TExpat::getAttributes()
{
    DECL_TRACER("TExpat::getAttributes()");

    if (mLastIter == mElements.end())
        return vector<ATTRIBUTE_t>();

    return mLastIter->attrs;
}

vector<ATTRIBUTE_t> TExpat::getAttributes(size_t index)
{
    DECL_TRACER("TExpat::getAttributes(size_t index)");

    if (index >= mElements.size())
        return vector<ATTRIBUTE_t>();

    return mElements.at(index).attrs;
}

string TExpat::getElementName(bool *valid)
{
    DECL_TRACER("TExpat::getElementName()");

    if (mLastIter != mElements.end())
    {
        if (valid)
            *valid = true;

        return mLastIter->name;
    }

    if (valid)
        *valid = false;

    return string();
}

string TExpat::getElementContent(bool *valid)
{
    DECL_TRACER("TExpat::getElementContent()");

    if (mLastIter != mElements.end())
    {
        if (valid)
            *valid = true;

        return mLastIter->content;
    }

    if (valid)
        *valid = false;

    return string();
}

int TExpat::getElementContentInt(bool *valid)
{
    DECL_TRACER("TExpat::getElementContentInt(bool *valid)");

    if (mLastIter != mElements.end())
    {
        if (valid)
            *valid = true;

        return atoi(mLastIter->content.c_str());
    }

    if (valid)
        *valid = false;

    return 0;
}

long TExpat::getElementContentLong(bool *valid)
{
    DECL_TRACER("TExpat::getElementContentLong(bool *valid)");

    if (mLastIter != mElements.end())
    {
        if (valid)
            *valid = true;

        return atol(mLastIter->content.c_str());
    }

    if (valid)
        *valid = false;

    return 0;
}

float TExpat::getElementContentFloat(bool *valid)
{
    DECL_TRACER("TExpat::getElementContentFloat(bool *valid)");

    if (mLastIter != mElements.end())
    {
        if (valid)
            *valid = true;

        return (float)atof(mLastIter->content.c_str());
    }

    if (valid)
        *valid = false;

    return 0.0;
}

double TExpat::getElementContentDouble(bool *valid)
{
    DECL_TRACER("TExpat::getElementContentDouble(bool *valid)");

    if (mLastIter != mElements.end())
    {
        if (valid)
            *valid = true;

        return atof(mLastIter->content.c_str());
    }

    if (valid)
        *valid = false;

    return 0.0;
}

/******************************************************************************
 *                        Static methods starting here
 ******************************************************************************/

void TExpat::createCP1250Encoding(XML_Encoding* enc)
{
    if (!enc)
        return;

    for (int i = 0; i < 0x0100; i++)
    {
        if (i < 0x007f)
            enc->map[i] = i;
        else
        {
            switch(i)
            {
                case 0x080: enc->map[i] = 0x20AC; break;
                case 0x082: enc->map[i] = 0x201A; break;
                case 0x083: enc->map[i] = 0x0192; break;
                case 0x084: enc->map[i] = 0x201E; break;
                case 0x085: enc->map[i] = 0x2026; break;
                case 0x086: enc->map[i] = 0x2020; break;
                case 0x087: enc->map[i] = 0x2021; break;
                case 0x088: enc->map[i] = 0x02C6; break;
                case 0x089: enc->map[i] = 0x2030; break;
                case 0x08A: enc->map[i] = 0x0160; break;
                case 0x08B: enc->map[i] = 0x2039; break;
                case 0x08C: enc->map[i] = 0x0152; break;
                case 0x08D: enc->map[i] = 0x00A4; break;
                case 0x08E: enc->map[i] = 0x017D; break;
                case 0x08F: enc->map[i] = 0x00B9; break;
                case 0x091: enc->map[i] = 0x2018; break;
                case 0x092: enc->map[i] = 0x2019; break;
                case 0x093: enc->map[i] = 0x201C; break;
                case 0x094: enc->map[i] = 0x201D; break;
                case 0x095: enc->map[i] = 0x2022; break;
                case 0x096: enc->map[i] = 0x2013; break;
                case 0x097: enc->map[i] = 0x2014; break;
                case 0x098: enc->map[i] = 0x02DC; break;
                case 0x099: enc->map[i] = 0x2122; break;
                case 0x09A: enc->map[i] = 0x0161; break;
                case 0x09B: enc->map[i] = 0x203A; break;
                case 0x09C: enc->map[i] = 0x0153; break;
                case 0x09D: enc->map[i] = 0x00A5; break;
                case 0x09E: enc->map[i] = 0x017E; break;
                case 0x09F: enc->map[i] = 0x0178; break;
                case 0x0A0: enc->map[i] = 0x02A0; break;
                case 0x0A1: enc->map[i] = 0x02C7; break;
                case 0x0A2: enc->map[i] = 0x02D8; break;
                case 0x0A3: enc->map[i] = 0x0141; break;
                case 0x0A4: enc->map[i] = 0x00A4; break;
                case 0x0A5: enc->map[i] = 0x0104; break;
                case 0x0A6: enc->map[i] = 0x00A6; break;
                case 0x0A7: enc->map[i] = 0x00A7; break;
                case 0x0A8: enc->map[i] = 0x00A8; break;
                case 0x0A9: enc->map[i] = 0x00A9; break;
                case 0x0AA: enc->map[i] = 0x015E; break;
                case 0x0AB: enc->map[i] = 0x00AB; break;
                case 0x0AC: enc->map[i] = 0x00AC; break;
                case 0x0AD: enc->map[i] = 0x00AD; break;
                case 0x0AE: enc->map[i] = 0x00AE; break;
                case 0x0AF: enc->map[i] = 0x017B; break;
                case 0x0B0: enc->map[i] = 0x00B0; break;
                case 0x0B1: enc->map[i] = 0x00B1; break;
                case 0x0B2: enc->map[i] = 0x02DB; break;
                case 0x0B3: enc->map[i] = 0x0142; break;
                case 0x0B4: enc->map[i] = 0x00B4; break;
                case 0x0B5: enc->map[i] = 0x00B5; break;
                case 0x0B6: enc->map[i] = 0x00B6; break;
                case 0x0B7: enc->map[i] = 0x00B7; break;
                case 0x0B8: enc->map[i] = 0x00B8; break;
                case 0x0B9: enc->map[i] = 0x0105; break;
                case 0x0BA: enc->map[i] = 0x015F; break;
                case 0x0BB: enc->map[i] = 0x00BB; break;
                case 0x0BC: enc->map[i] = 0x013D; break;
                case 0x0BD: enc->map[i] = 0x02DD; break;
                case 0x0BE: enc->map[i] = 0x013E; break;
                case 0x0BF: enc->map[i] = 0x017C; break;
                case 0x0C0: enc->map[i] = 0x0154; break;
                case 0x0C1: enc->map[i] = 0x00C1; break;
                case 0x0C2: enc->map[i] = 0x00C2; break;
                case 0x0C3: enc->map[i] = 0x0102; break;
                case 0x0C4: enc->map[i] = 0x00C4; break;
                case 0x0C5: enc->map[i] = 0x0139; break;
                case 0x0C6: enc->map[i] = 0x0106; break;
                case 0x0C7: enc->map[i] = 0x00C7; break;
                case 0x0C8: enc->map[i] = 0x010C; break;
                case 0x0C9: enc->map[i] = 0x00C9; break;
                case 0x0CA: enc->map[i] = 0x0118; break;
                case 0x0CB: enc->map[i] = 0x00CB; break;
                case 0x0CC: enc->map[i] = 0x00CC; break;    //0x011A
                case 0x0CD: enc->map[i] = 0x00CD; break;
                case 0x0CE: enc->map[i] = 0x00CE; break;
                case 0x0CF: enc->map[i] = 0x00CF; break;
                case 0x0D0: enc->map[i] = 0x0110; break;
                case 0x0D1: enc->map[i] = 0x0143; break;
                case 0x0D2: enc->map[i] = 0x0147; break;
                case 0x0D3: enc->map[i] = 0x00D3; break;
                case 0x0D4: enc->map[i] = 0x00D4; break;
                case 0x0D5: enc->map[i] = 0x0150; break;
                case 0x0D6: enc->map[i] = 0x00D6; break;
                case 0x0D7: enc->map[i] = 0x00D7; break;
                case 0x0D8: enc->map[i] = 0x0158; break;
                case 0x0D9: enc->map[i] = 0x016E; break;
                case 0x0DA: enc->map[i] = 0x00DA; break;
                case 0x0DB: enc->map[i] = 0x0170; break;
                case 0x0DC: enc->map[i] = 0x00DC; break;
                case 0x0DD: enc->map[i] = 0x00DD; break;
                case 0x0DE: enc->map[i] = 0x0162; break;
                case 0x0DF: enc->map[i] = 0x00DF; break;
                case 0x0E0: enc->map[i] = 0x0155; break;
                case 0x0E1: enc->map[i] = 0x00E1; break;
                case 0x0E2: enc->map[i] = 0x00E2; break;
                case 0x0E3: enc->map[i] = 0x0103; break;
                case 0x0E4: enc->map[i] = 0x00E4; break;
                case 0x0E5: enc->map[i] = 0x013A; break;
                case 0x0E6: enc->map[i] = 0x0107; break;
                case 0x0E7: enc->map[i] = 0x00E7; break;
                case 0x0E8: enc->map[i] = 0x010D; break;
                case 0x0E9: enc->map[i] = 0x00E9; break;
                case 0x0EA: enc->map[i] = 0x0119; break;
                case 0x0EB: enc->map[i] = 0x00EB; break;
                case 0x0EC: enc->map[i] = 0x011B; break;
                case 0x0ED: enc->map[i] = 0x00ED; break;
                case 0x0EE: enc->map[i] = 0x00EE; break;
                case 0x0EF: enc->map[i] = 0x010F; break;
                case 0x0F0: enc->map[i] = 0x0111; break;
                case 0x0F1: enc->map[i] = 0x0144; break;
                case 0x0F2: enc->map[i] = 0x0148; break;
                case 0x0F3: enc->map[i] = 0x00F3; break;
                case 0x0F4: enc->map[i] = 0x00F4; break;
                case 0x0F5: enc->map[i] = 0x0151; break;
                case 0x0F6: enc->map[i] = 0x00F6; break;
                case 0x0F7: enc->map[i] = 0x00F7; break;
                case 0x0F8: enc->map[i] = 0x0159; break;
                case 0x0F9: enc->map[i] = 0x016F; break;
                case 0x0FA: enc->map[i] = 0x00FA; break;
                case 0x0FB: enc->map[i] = 0x0171; break;
                case 0x0FC: enc->map[i] = 0x00FC; break;
                case 0x0FD: enc->map[i] = 0x00FD; break;
                case 0x0FE: enc->map[i] = 0x0163; break;
                case 0x0FF: enc->map[i] = 0x02D9; break;

                default:
                    enc->map[i] = -1;
            }
        }
    }
}

void TExpat::startElement(void *userData, const XML_Char *name, const XML_Char **attrs)
{
    if (!name)
        return;

    std::vector<_ELEMENT_t> *ud = (std::vector<_ELEMENT_t> *)userData;
    _ELEMENT_t el;

    mLastName.assign(name);
    mDepth++;
    mAttributes.clear();
    mContent.clear();

    el.depth = mDepth;
    el.name = mLastName;
    el.eType = _ET_START;

    if (attrs && *attrs)
    {
        for (int i = 0; attrs[i]; i += 2)
        {
            _ATTRIBUTE_t at;
            at.name.assign(attrs[i]);
            at.content.assign(attrs[i + 1]);
            mAttributes.push_back(at);
        }

        el.attrs = mAttributes;
    }

    ud->push_back(el);
}

void TExpat::endElement(void *userData, const XML_Char *name)
{
    if (!userData || !name)
        return;

    std::vector<_ELEMENT_t> *ud = (std::vector<_ELEMENT_t> *)userData;

    if (mLastName.compare(name) == 0)
    {
        if (ud->back().depth == mDepth)
        {
            ud->back().eType = _ET_ATOMIC;
            ud->back().content = mContent;

            mDepth--;
            mLastName.clear();
            mContent.clear();
            return;
        }
    }

    _ELEMENT_t el;
    el.depth = mDepth;
    el.name.assign(name);
    el.eType = _ET_END;
    ud->push_back(el);
    mDepth--;

    mLastName.clear();
    mContent.clear();
}

void TExpat::CharacterDataHandler(void *, const XML_Char *s, int len)
{
    if (!s || len <= 0 || mLastName.empty())
        return;

    mContent.append(s, len);
}

int XMLCALL TExpat::cp1250_encoding_handler(void *, const XML_Char *encoding, XML_Encoding *info)
{
    if (!info)
        return XML_STATUS_ERROR;

    if (encoding && strcmp(encoding, "CP1250") != 0)
    {
        MSG_ERROR("Invalid encoding handler (" << encoding << ")");
        TError::setError();
        return XML_STATUS_ERROR;
    }

    memset(info, 0, sizeof(XML_Encoding));
    createCP1250Encoding(info);
    return XML_STATUS_OK;
}