<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgDB/XmlParser>
#include <osgDB/FileUtils>

#include <osg/Notify>

using namespace osgDB;

XmlNode* osgDB::readXmlFile(const std::string& filename,const Options* options)
{
    std::string foundFile = osgDB::findDataFile(filename, options);
    if (!foundFile.empty())
    {
        XmlNode::Input input;
        input.open(foundFile);
        input.readAllDataIntoBuffer();

        if (!input)
        {
            OSG_NOTICE<<"Could not open XML file: "<<filename<<std::endl;
            return 0;
        }

        osg::ref_ptr<XmlNode> root = new XmlNode;
        root->read(input);

        return root.release();
    }
    else
    {
        OSG_NOTICE<<"Could not find XML file: "<<filename<<std::endl;
        return 0;
    }
}

std::string osgDB::trimEnclosingSpaces(const std::string& str)
{
    if (str.empty()) return str;

    const std::string whitespaces(" \t\f\v\n\r");

    std::string::size_type start = str.find_first_not_of(whitespaces);
    if (start==std::string::npos) return std::string();

    std::string::size_type end = str.find_last_not_of(whitespaces);
    if (end==std::string::npos) return std::string();

    return std::string(str, start, (end-start)+1);
}

XmlNode* osgDB::readXmlStream(std::istream& fin)
{
    XmlNode::Input input;
    input.attach(fin);
    input.readAllDataIntoBuffer();

    if (!input)
    {
        OSG_NOTICE<<"Could not attach to XML stream."<<std::endl;
        return 0;
    }

    osg::ref_ptr<XmlNode> root = new XmlNode;
    root->read(input);

    return root.release();
}

XmlNode::ControlMap::ControlMap()
{
    setUpControlMappings();
}

void XmlNode::ControlMap::addControlToCharacter(const std::string& control, int c)
{
    _controlToCharacterMap[control] = c;
    _characterToControlMap[c] = control;
}

void XmlNode::ControlMap::setUpControlMappings()
{
    addControlToCharacter("&",'&');
    addControlToCharacter("<",'<');
    addControlToCharacter(">",'>');
    addControlToCharacter(""",'"');
    addControlToCharacter("'",'\'');
}

XmlNode::Input::Input():
    _currentPos(0)
{
}

XmlNode::Input::Input(const Input&):
    ControlMap(),
    _currentPos(0)
{
}

XmlNode::Input::~Input()
{
}
void XmlNode::Input::open(const std::string& filename)
{
    _fin.open(filename.c_str());
}

void XmlNode::Input::attach(std::istream& fin)
{
    std::ios &fios = _fin;
    fios.rdbuf(fin.rdbuf());
}

void XmlNode::Input::readAllDataIntoBuffer()
{
    while(_fin)
    {
        int c = _fin.get();
        if (c>=0 && c<=255)
        {
            _buffer.push_back(c);
        }
    }
}

void XmlNode::Input::skipWhiteSpace()
{
    while(_currentPos<_buffer.size() && (_buffer[_currentPos]==' ' || _buffer[_currentPos]=='\t' || _buffer[_currentPos]=='\n' || _buffer[_currentPos]=='\r'))
    {
        //OSG_NOTICE<<"_currentPos="<<_currentPos<<"_buffer.size()="<<_buffer.size()<<" v="<<int(_buffer[_currentPos])<<std::endl;
        ++_currentPos;
    }
    //OSG_NOTICE<<"done"<<std::endl;
}

XmlNode::XmlNode()
{
    type = UNASSIGNED;
}

bool XmlNode::read(Input& input)
{
    if (type == UNASSIGNED) type = ROOT;

    while(input)
    {
        //input.skipWhiteSpace();
        if (input.match("<!--"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::COMMENT;
            children.push_back(commentNode);

            input += 4;
            XmlNode::Input::size_type end = input.find("-->");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid Comment record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+3);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed Comment record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("</"))
        {
            input += 2;
            XmlNode::Input::size_type end = input.find(">");
            std::string comment = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid end tag ["<<comment<<"]"<<std::endl;
                input += (end+1);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed end tag ["<<comment<<"]"<<std::endl;
                input += end;
            }

            if (comment==name) { OSG_INFO<<"end tag is matched correctly"<<std::endl; }
            else { OSG_NOTICE<<"Error: end tag is not matched correctly"<<std::endl; }

            return true;
        }
        else if (input.match("<!DOCTYPE"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::INFORMATION;
            children.push_back(commentNode);

            ++input;
            XmlNode::Input::size_type end = input.find(">");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid information record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+2);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed information record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("<![CDATA["))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::INFORMATION;
            children.push_back(commentNode);

            input += 9;
            XmlNode::Input::size_type end = input.find("]]>");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid information record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+2);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed information record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("<?"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::INFORMATION;
            children.push_back(commentNode);

            input += 2;
            XmlNode::Input::size_type end = input.find("?>");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid information record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+2);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed information record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("<"))
        {
            XmlNode* childNode = new XmlNode;
            childNode->type = XmlNode::NODE;
            children.push_back(childNode);

            input += 1;

            input.skipWhiteSpace();

            int c = 0;
            while ((c=input[0])>=0 && c!=' ' && c!='\n' && c!='\r' && c!='>' && c!='/')
            {
                childNode->name.push_back(c);
                ++input;
            }

            while ((c=input[0])>=0 && c!='>' && c!='/')
            {
                Input::size_type prev_pos = input.currentPosition();

                input.skipWhiteSpace();
                std::string option;
                std::string value;

                if (input[0]=='"')
                {
                    option.push_back(input[0]);
                    ++input;
                    while((c=input[0])>=0 && c!='"')
                    {
                        if (c=='&')
                            readAndReplaceControl(option, input);
                        else
                        {
                            option.push_back(c);
                            ++input;
                        }
                    }
                    option.push_back(input[0]);
                    ++input;
                }
                else
                {
                    while((c=input[0])>=0 && c!='>' && c!='/' && c!='"' && c!='\'' && c!='=' && c!=' ' && c!='\n' && c!='\r')
                    {
                        option.push_back(c);
                        ++input;
                    }
                }

                input.skipWhiteSpace();
                if (input[0]=='=')
                {
                    ++input;

                    input.skipWhiteSpace();

                    if (input[0]=='"')
                    {
                        ++input;
                        while((c=input[0])>=0 && c!='"')
                        {
                            if (c=='&')
                                readAndReplaceControl(value, input);
                            else
                            {
                                value.push_back(c);
                                ++input;
                            }
                        }
                        ++input;
                    }
                    else if (input[0]=='\'')
                    {
                        ++input;
                        while((c=input[0])>=0 && c!='\'')
                        {
                            if (c=='&')
                                readAndReplaceControl(value, input);
                            else
                            {
                                value.push_back(c);
                                ++input;
                            }
                        }
                        ++input;
                    }
                    else
                    {
                        ++input;
                        while((c=input[0])>=0 && c!=' ' && c!='\n' && c!='\r' && c!='"' && c!='\'' && c!='>')
                        {
                            value.push_back(c);
                            ++input;
                        }
                    }
                }

                if (prev_pos == input.currentPosition())
                {
                    OSG_NOTICE<<"Error, parser iterator not advanced, position: "<<input.substr(0,50)<<std::endl;
                    ++input;
                }

                if (!option.empty())
                {
                    OSG_INFO<<"Assigning option "<<option<<" with value "<<value<<std::endl;
                    childNode->properties[option] = value;
                }
            }

            if ((c=input[0])>=0 && (c=='>' || c=='/'))
            {
                ++input;

                OSG_INFO<<"Valid tag ["<<childNode->name<<"]"<<std::endl;

                if (c=='/')
                {
                    if ((c=input[0])>=0 && c=='>')
                    {
                        ++input;
                        OSG_INFO<<"tag is closed correctly"<<std::endl;
                        childNode->type = ATOM;
                    }
                    else
                        OSG_NOTICE<<"Error: tag is not closed correctly"<<std::endl;
                }
                else
                {
                    bool result = childNode->read(input);
                    if (!result) return false;
                }

                if (type==NODE && !children.empty()) type = GROUP;
            }
            else
            {
                OSG_NOTICE<<"Unclosed tag ["<<childNode->name<<"]"<<std::endl;
                return false;
            }

        }
        else
        {
            int c = input[0];

            if (c=='&')
            {
                readAndReplaceControl(contents, input);
            }
            else
            {
                contents.push_back( c );
                ++input;
            }

        }
    }

    if (type==NODE && !children.empty()) type = GROUP;
    return false;
}

bool XmlNode::write(std::ostream& fout, const std::string& indent) const
{
    ControlMap controlMap;
    return write(controlMap, fout, indent);
}

bool XmlNode::write(const ControlMap& controlMap, std::ostream& fout, const std::string& indent) const
{
    switch(type)
    {
        case(UNASSIGNED):
            OSG_NOTICE<<"UNASSIGNED"<<std::endl;
            return false;
        case(ATOM):
        {
            fout<<indent<<"<"<<name;
            writeProperties(controlMap, fout);
            fout<<" />"<<std::endl;
            return true;
        }
        case(ROOT):
        {
            writeChildren(controlMap, fout, indent);
            return true;
        }
        case(NODE):
            fout<<indent<<"<"<<name;
            writeProperties(controlMap,fout);
            fout<<">"; writeString(controlMap, fout, contents); fout<<"</"<<name<<">"<<std::endl;
            return true;
        case(GROUP):
        {
            fout<<indent<<"<"<<name;
            writeProperties(controlMap,fout);
            fout<<">"<<std::endl;

            writeChildren(controlMap, fout, indent + "  ");

            fout<<indent<<"</"<<name<<">"<<std::endl;
            return true;
        }
        case(COMMENT):
        {
            fout<<indent<<"<!--"<<contents<<"-->"<<std::endl;
            return true;
        }
        case(INFORMATION):
        {
            fout<<indent<<"<?"<<contents<<"?>"<<std::endl;
            return true;
        }
    }
    return false;
}

bool XmlNode::writeString(const ControlMap& controlMap, std::ostream& fout, const std::string& str) const
{
    for(std::string::const_iterator itr = str.begin();
        itr != str.end();
        ++itr)
    {
        int c = *itr;
        ControlMap::CharacterToControlMap::const_iterator citr = controlMap._characterToControlMap.find(c);
        if (citr != controlMap._characterToControlMap.end()) fout << citr->second;
        else fout.put(c);
    }
    return true;
}

bool XmlNode::writeChildren(const ControlMap& /*controlMap*/, std::ostream& fout, const std::string& indent) const
{
    for(Children::const_iterator citr = children.begin();
        citr != children.end();
        ++citr)
    {
        if (!(*citr)->write(fout, indent))
            return false;
    }

    return true;
}

bool XmlNode::writeProperties(const ControlMap& controlMap, std::ostream& fout) const
{
    for(Properties::const_iterator oitr = properties.begin();
        oitr != properties.end();
        ++oitr)
    {
        fout<<" "<<oitr->first<<"=\"";
        if (!writeString(controlMap,fout,oitr->second))
            return false;
        fout<<"\"";
    }

    return true;
}

bool XmlNode::readAndReplaceControl(std::string& contents, XmlNode::Input& input)
{
    int c = 0;
    std::string value;
    while(input && (c=input.get())!=';') { value.push_back(c); }
    value.push_back(c);

    if (input._controlToCharacterMap.count(value)!=0)
    {
        c = input._controlToCharacterMap[value];
        OSG_INFO<<"Read control character "<<value<<" converted to "<<char(c)<<std::endl;
        contents.push_back(c);
        return true;
    }
    else
    {
        OSG_NOTICE<<"Warning: read control character "<<value<<", but have no mapping to convert it to."<<std::endl;
        return false;
    }
}
<commit_msg>Added &nl; xml control character to allow one to put newlines into a single text string in Present3D presentations<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgDB/XmlParser>
#include <osgDB/FileUtils>

#include <osg/Notify>

using namespace osgDB;

XmlNode* osgDB::readXmlFile(const std::string& filename,const Options* options)
{
    std::string foundFile = osgDB::findDataFile(filename, options);
    if (!foundFile.empty())
    {
        XmlNode::Input input;
        input.open(foundFile);
        input.readAllDataIntoBuffer();

        if (!input)
        {
            OSG_NOTICE<<"Could not open XML file: "<<filename<<std::endl;
            return 0;
        }

        osg::ref_ptr<XmlNode> root = new XmlNode;
        root->read(input);

        return root.release();
    }
    else
    {
        OSG_NOTICE<<"Could not find XML file: "<<filename<<std::endl;
        return 0;
    }
}

std::string osgDB::trimEnclosingSpaces(const std::string& str)
{
    if (str.empty()) return str;

    const std::string whitespaces(" \t\f\v\n\r");

    std::string::size_type start = str.find_first_not_of(whitespaces);
    if (start==std::string::npos) return std::string();

    std::string::size_type end = str.find_last_not_of(whitespaces);
    if (end==std::string::npos) return std::string();

    return std::string(str, start, (end-start)+1);
}

XmlNode* osgDB::readXmlStream(std::istream& fin)
{
    XmlNode::Input input;
    input.attach(fin);
    input.readAllDataIntoBuffer();

    if (!input)
    {
        OSG_NOTICE<<"Could not attach to XML stream."<<std::endl;
        return 0;
    }

    osg::ref_ptr<XmlNode> root = new XmlNode;
    root->read(input);

    return root.release();
}

XmlNode::ControlMap::ControlMap()
{
    setUpControlMappings();
}

void XmlNode::ControlMap::addControlToCharacter(const std::string& control, int c)
{
    _controlToCharacterMap[control] = c;
    _characterToControlMap[c] = control;
}

void XmlNode::ControlMap::setUpControlMappings()
{
    addControlToCharacter("&",'&');
    addControlToCharacter("<",'<');
    addControlToCharacter(">",'>');
    addControlToCharacter(""",'"');
    addControlToCharacter("'",'\'');
    addControlToCharacter("&nl;",'\n');
}

XmlNode::Input::Input():
    _currentPos(0)
{
}

XmlNode::Input::Input(const Input&):
    ControlMap(),
    _currentPos(0)
{
}

XmlNode::Input::~Input()
{
}
void XmlNode::Input::open(const std::string& filename)
{
    _fin.open(filename.c_str());
}

void XmlNode::Input::attach(std::istream& fin)
{
    std::ios &fios = _fin;
    fios.rdbuf(fin.rdbuf());
}

void XmlNode::Input::readAllDataIntoBuffer()
{
    while(_fin)
    {
        int c = _fin.get();
        if (c>=0 && c<=255)
        {
            _buffer.push_back(c);
        }
    }
}

void XmlNode::Input::skipWhiteSpace()
{
    while(_currentPos<_buffer.size() && (_buffer[_currentPos]==' ' || _buffer[_currentPos]=='\t' || _buffer[_currentPos]=='\n' || _buffer[_currentPos]=='\r'))
    {
        //OSG_NOTICE<<"_currentPos="<<_currentPos<<"_buffer.size()="<<_buffer.size()<<" v="<<int(_buffer[_currentPos])<<std::endl;
        ++_currentPos;
    }
    //OSG_NOTICE<<"done"<<std::endl;
}

XmlNode::XmlNode()
{
    type = UNASSIGNED;
}

bool XmlNode::read(Input& input)
{
    if (type == UNASSIGNED) type = ROOT;

    while(input)
    {
        //input.skipWhiteSpace();
        if (input.match("<!--"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::COMMENT;
            children.push_back(commentNode);

            input += 4;
            XmlNode::Input::size_type end = input.find("-->");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid Comment record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+3);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed Comment record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("</"))
        {
            input += 2;
            XmlNode::Input::size_type end = input.find(">");
            std::string comment = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid end tag ["<<comment<<"]"<<std::endl;
                input += (end+1);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed end tag ["<<comment<<"]"<<std::endl;
                input += end;
            }

            if (comment==name) { OSG_INFO<<"end tag is matched correctly"<<std::endl; }
            else { OSG_NOTICE<<"Error: end tag is not matched correctly"<<std::endl; }

            return true;
        }
        else if (input.match("<!DOCTYPE"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::INFORMATION;
            children.push_back(commentNode);

            ++input;
            XmlNode::Input::size_type end = input.find(">");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid information record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+2);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed information record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("<![CDATA["))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::INFORMATION;
            children.push_back(commentNode);

            input += 9;
            XmlNode::Input::size_type end = input.find("]]>");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid information record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+2);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed information record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("<?"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::INFORMATION;
            children.push_back(commentNode);

            input += 2;
            XmlNode::Input::size_type end = input.find("?>");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                OSG_INFO<<"Valid information record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+2);
            }
            else
            {
                OSG_NOTICE<<"Error: Unclosed information record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("<"))
        {
            XmlNode* childNode = new XmlNode;
            childNode->type = XmlNode::NODE;
            children.push_back(childNode);

            input += 1;

            input.skipWhiteSpace();

            int c = 0;
            while ((c=input[0])>=0 && c!=' ' && c!='\n' && c!='\r' && c!='>' && c!='/')
            {
                childNode->name.push_back(c);
                ++input;
            }

            while ((c=input[0])>=0 && c!='>' && c!='/')
            {
                Input::size_type prev_pos = input.currentPosition();

                input.skipWhiteSpace();
                std::string option;
                std::string value;

                if (input[0]=='"')
                {
                    option.push_back(input[0]);
                    ++input;
                    while((c=input[0])>=0 && c!='"')
                    {
                        if (c=='&')
                            readAndReplaceControl(option, input);
                        else
                        {
                            option.push_back(c);
                            ++input;
                        }
                    }
                    option.push_back(input[0]);
                    ++input;
                }
                else
                {
                    while((c=input[0])>=0 && c!='>' && c!='/' && c!='"' && c!='\'' && c!='=' && c!=' ' && c!='\n' && c!='\r')
                    {
                        option.push_back(c);
                        ++input;
                    }
                }

                input.skipWhiteSpace();
                if (input[0]=='=')
                {
                    ++input;

                    input.skipWhiteSpace();

                    if (input[0]=='"')
                    {
                        ++input;
                        while((c=input[0])>=0 && c!='"')
                        {
                            if (c=='&')
                                readAndReplaceControl(value, input);
                            else
                            {
                                value.push_back(c);
                                ++input;
                            }
                        }
                        ++input;
                    }
                    else if (input[0]=='\'')
                    {
                        ++input;
                        while((c=input[0])>=0 && c!='\'')
                        {
                            if (c=='&')
                                readAndReplaceControl(value, input);
                            else
                            {
                                value.push_back(c);
                                ++input;
                            }
                        }
                        ++input;
                    }
                    else
                    {
                        ++input;
                        while((c=input[0])>=0 && c!=' ' && c!='\n' && c!='\r' && c!='"' && c!='\'' && c!='>')
                        {
                            value.push_back(c);
                            ++input;
                        }
                    }
                }

                if (prev_pos == input.currentPosition())
                {
                    OSG_NOTICE<<"Error, parser iterator not advanced, position: "<<input.substr(0,50)<<std::endl;
                    ++input;
                }

                if (!option.empty())
                {
                    OSG_INFO<<"Assigning option "<<option<<" with value "<<value<<std::endl;
                    childNode->properties[option] = value;
                }
            }

            if ((c=input[0])>=0 && (c=='>' || c=='/'))
            {
                ++input;

                OSG_INFO<<"Valid tag ["<<childNode->name<<"]"<<std::endl;

                if (c=='/')
                {
                    if ((c=input[0])>=0 && c=='>')
                    {
                        ++input;
                        OSG_INFO<<"tag is closed correctly"<<std::endl;
                        childNode->type = ATOM;
                    }
                    else
                        OSG_NOTICE<<"Error: tag is not closed correctly"<<std::endl;
                }
                else
                {
                    bool result = childNode->read(input);
                    if (!result) return false;
                }

                if (type==NODE && !children.empty()) type = GROUP;
            }
            else
            {
                OSG_NOTICE<<"Unclosed tag ["<<childNode->name<<"]"<<std::endl;
                return false;
            }

        }
        else
        {
            int c = input[0];

            if (c=='&')
            {
                readAndReplaceControl(contents, input);
            }
            else
            {
                contents.push_back( c );
                ++input;
            }

        }
    }

    if (type==NODE && !children.empty()) type = GROUP;
    return false;
}

bool XmlNode::write(std::ostream& fout, const std::string& indent) const
{
    ControlMap controlMap;
    return write(controlMap, fout, indent);
}

bool XmlNode::write(const ControlMap& controlMap, std::ostream& fout, const std::string& indent) const
{
    switch(type)
    {
        case(UNASSIGNED):
            OSG_NOTICE<<"UNASSIGNED"<<std::endl;
            return false;
        case(ATOM):
        {
            fout<<indent<<"<"<<name;
            writeProperties(controlMap, fout);
            fout<<" />"<<std::endl;
            return true;
        }
        case(ROOT):
        {
            writeChildren(controlMap, fout, indent);
            return true;
        }
        case(NODE):
            fout<<indent<<"<"<<name;
            writeProperties(controlMap,fout);
            fout<<">"; writeString(controlMap, fout, contents); fout<<"</"<<name<<">"<<std::endl;
            return true;
        case(GROUP):
        {
            fout<<indent<<"<"<<name;
            writeProperties(controlMap,fout);
            fout<<">"<<std::endl;

            writeChildren(controlMap, fout, indent + "  ");

            fout<<indent<<"</"<<name<<">"<<std::endl;
            return true;
        }
        case(COMMENT):
        {
            fout<<indent<<"<!--"<<contents<<"-->"<<std::endl;
            return true;
        }
        case(INFORMATION):
        {
            fout<<indent<<"<?"<<contents<<"?>"<<std::endl;
            return true;
        }
    }
    return false;
}

bool XmlNode::writeString(const ControlMap& controlMap, std::ostream& fout, const std::string& str) const
{
    for(std::string::const_iterator itr = str.begin();
        itr != str.end();
        ++itr)
    {
        int c = *itr;
        ControlMap::CharacterToControlMap::const_iterator citr = controlMap._characterToControlMap.find(c);
        if (citr != controlMap._characterToControlMap.end()) fout << citr->second;
        else fout.put(c);
    }
    return true;
}

bool XmlNode::writeChildren(const ControlMap& /*controlMap*/, std::ostream& fout, const std::string& indent) const
{
    for(Children::const_iterator citr = children.begin();
        citr != children.end();
        ++citr)
    {
        if (!(*citr)->write(fout, indent))
            return false;
    }

    return true;
}

bool XmlNode::writeProperties(const ControlMap& controlMap, std::ostream& fout) const
{
    for(Properties::const_iterator oitr = properties.begin();
        oitr != properties.end();
        ++oitr)
    {
        fout<<" "<<oitr->first<<"=\"";
        if (!writeString(controlMap,fout,oitr->second))
            return false;
        fout<<"\"";
    }

    return true;
}

bool XmlNode::readAndReplaceControl(std::string& contents, XmlNode::Input& input)
{
    int c = 0;
    std::string value;
    while(input && (c=input.get())!=';') { value.push_back(c); }
    value.push_back(c);

    if (input._controlToCharacterMap.count(value)!=0)
    {
        c = input._controlToCharacterMap[value];
        OSG_INFO<<"Read control character "<<value<<" converted to "<<char(c)<<std::endl;
        contents.push_back(c);
        return true;
    }
    else
    {
        OSG_NOTICE<<"Warning: read control character "<<value<<", but have no mapping to convert it to."<<std::endl;
        return false;
    }
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgDB/XmlParser>
#include <osgDB/FileUtils>

#include <osg/Notify>

using namespace osgDB;

XmlNode* osgDB::readXmlFile(const std::string& filename,const Options* options)
{
    std::string foundFile = osgDB::findDataFile(filename, options);
    if (!foundFile.empty())
    {
        XmlNode::Input input;
        input.open(foundFile);
        if (!input)
        {
            osg::notify(osg::NOTICE)<<"Could not open XML file: "<<filename<<std::endl;
            return 0;
        }

        input.readAllDataIntoBuffer();

        osg::ref_ptr<XmlNode> root = new XmlNode;
        root->read(input);

        return root.release();
    }
    else
    {
        osg::notify(osg::NOTICE)<<"Could not find XML file: "<<filename<<std::endl;
        return 0;
    }
}

XmlNode* osgDB::readXmlStream(std::istream& fin)
{
    XmlNode::Input input;
    input.attach(fin);
    if (!input)
    {
        osg::notify(osg::NOTICE)<<"Could not attach to XML stream."<<std::endl;
        return 0;
    }

    input.readAllDataIntoBuffer();

    osg::ref_ptr<XmlNode> root = new XmlNode;
    root->read(input);

    return root.release();
}

XmlNode::Input::Input():
    _currentPos(0)
{
    setUpControlMappings();
}

XmlNode::Input::Input(const Input&):
    _currentPos(0)
{
    setUpControlMappings();
}

XmlNode::Input::~Input()
{
}

void XmlNode::Input::setUpControlMappings()
{
    addControlToCharacter("&",'&');
    addControlToCharacter("<",'<');
    addControlToCharacter(">",'>');
    addControlToCharacter(""",'"');
    addControlToCharacter("'",'\'');
}

void XmlNode::Input::addControlToCharacter(const std::string& control, int c)
{
    _controlToCharacterMap[control] = c;
    _characterToControlMap[c] = control;
}

void XmlNode::Input::open(const std::string& filename)
{
    _fin.open(filename.c_str());
}

void XmlNode::Input::attach(std::istream& fin)
{
    std::ios &fios = _fin;
    fios.rdbuf(fin.rdbuf());
}

void XmlNode::Input::readAllDataIntoBuffer()
{
    while(_fin)
    {
        int c = _fin.get();
        if (c>=0 && c<=255)
        {
            _buffer.push_back(c);
        }
    }
}

void XmlNode::Input::skipWhiteSpace()
{
    while(_currentPos<_buffer.size() && _buffer[_currentPos]==' ')
    {
        // osg::notify(osg::NOTICE)<<"_currentPos="<<_currentPos<<"_buffer.size()="<<_buffer.size()<<" v="<<_buffer[_currentPos]<<std::endl;
        ++_currentPos;
    }
    //osg::notify(osg::NOTICE)<<"done"<<std::endl;
}

XmlNode::XmlNode()
{
    type = UNASSIGNED;
}

bool XmlNode::read(Input& input)
{
    if (type == UNASSIGNED) type = ROOT;

    while(input)
    {
        //input.skipWhiteSpace();
        if (input.match("<!--"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::COMMENT;
            children.push_back(commentNode);

            input += 4;
            XmlNode::Input::size_type end = input.find("-->");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                osg::notify(osg::INFO)<<"Valid Comment record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+3);
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Error: Unclosed Comment record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("</"))
        {
            input += 2;
            XmlNode::Input::size_type end = input.find(">");
            std::string comment = input.substr(0, end);
            if (end!=std::string::npos)
            {
                osg::notify(osg::INFO)<<"Valid end tag ["<<comment<<"]"<<std::endl;
                input += (end+1);
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Error: Unclosed end tag ["<<comment<<"]"<<std::endl;
                input += end;
            }

            if (comment==name) osg::notify(osg::INFO)<<"end tag is matched correctly"<<std::endl;
            else osg::notify(osg::NOTICE)<<"Error: end tag is not matched correctly"<<std::endl;

            return true;
        }
        else if (input.match("<?"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::INFORMATION;
            children.push_back(commentNode);

            input += 2;
            XmlNode::Input::size_type end = input.find("?>");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                osg::notify(osg::INFO)<<"Valid infomation record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+2);
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Error: Unclosed infomation record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("<"))
        {
            XmlNode* childNode = new XmlNode;
            childNode->type = XmlNode::NODE;
            children.push_back(childNode);

            input += 1;

            input.skipWhiteSpace();

            int c = 0;
            while ((c=input[0])>=0 && c!=' ' && c!='>' )
            {
                childNode->name.push_back(c);
                ++input;
            }

            while ((c=input[0])>=0 && c!='>')
            {
                Input::size_type prev_pos = input.currentPosition();

                input.skipWhiteSpace();
                std::string option;
                std::string value;
                while((c=input[0])>=0 && c!='>' && c!='"' && c!='\'' && c!='=' && c!=' ')
                {
                    option.push_back(c);
                    ++input;
                }
                input.skipWhiteSpace();
                if (input[0]=='=')
                {
                    ++input;

                    input.skipWhiteSpace();

                    if (input[0]=='"')
                    {
                        ++input;
                        while((c=input[0])>=0 && c!='"')
                        {
                            value.push_back(c);
                            ++input;
                        }
                        ++input;
                    }
                    else if (input[0]=='\'')
                    {
                        ++input;
                        while((c=input[0])>=0 && c!='\'')
                        {
                            value.push_back(c);
                            ++input;
                        }
                        ++input;
                    }
                    else
                    {
                        ++input;
                        while((c=input[0])>=0 && c!=' ' && c!='"' && c!='\'' && c!='>')
                        {
                            value.push_back(c);
                            ++input;
                        }
                    }
                }

                if (prev_pos == input.currentPosition())
                {
                    osg::notify(osg::NOTICE)<<"Error, parser iterator note advanced, position: "<<input.substr(0,50)<<std::endl;
                    ++input;
                }

                if (!option.empty())
                {
                    osg::notify(osg::NOTICE)<<"Assigning option "<<option<<" with value "<<value<<std::endl;
                    childNode->properties[option] = value;
                }
            }

            if ((c=input[0])>=0 && c=='>' )
            {
                ++input;

                osg::notify(osg::INFO)<<"Valid tag ["<<childNode->name<<"]"<<std::endl;

                bool result = childNode->read(input);
                if (!result) return false;

                if (type==NODE && !children.empty()) type = GROUP;
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Unclosed tag ["<<childNode->name<<"]"<<std::endl;
                return false;
            }

        }
        else
        {
            int c = input[0];

            if (c=='&')
            {
                std::string value;
                while(input && (c=input.get())!=';') { value.push_back(c); }
                value.push_back(c);

                if (input._controlToCharacterMap.count(value)!=0)
                {
                    c = input._controlToCharacterMap[value];
                    osg::notify(osg::INFO)<<"Read control character "<<value<<" converted to "<<char(c)<<std::endl;
                    contents.push_back(c);
                }
                else
                {
                    osg::notify(osg::NOTICE)<<"Warning: read control character "<<value<<", but have no mapping to convert it to."<<std::endl;
                }
            }
            else
            {
                contents.push_back( c );
                ++input;
            }

        }
    }

    if (type==NODE && !children.empty()) type = GROUP;
    return false;
}

bool XmlNode::write(std::ostream& fout) const
{
    switch(type)
    {
        case(UNASSIGNED):
            return false;
        case(ATOM):
        {
            fout<<"<"<<name;
            for(Properties::const_iterator oitr = properties.begin();
                oitr != properties.end();
                ++oitr)
            {
                fout<<oitr->first<<"\"";
                writeString(fout,oitr->second);
                fout<<"\""<<std::endl;
            }
            return true;
        }
        case(ROOT):
        {
            for(Children::const_iterator citr = children.begin();
                citr != children.end();
                ++citr)
            {
                (*citr)->write(fout);
            }
            return true;
        }
        case(NODE):
        {
            fout<<"<"<<name;
            for(Properties::const_iterator oitr = properties.begin();
                oitr != properties.end();
                ++oitr)
            {
                fout<<" "<<oitr->first<<"=\"";
                writeString(fout,oitr->second);
                fout<<"\"";
            }
            fout<<">";

            for(Children::const_iterator citr = children.begin();
                citr != children.end();
                ++citr)
            {
                (*citr)->write(fout);
            }

            if (!contents.empty()) writeString(fout,contents);

            fout<<"</"<<name<<">"<<std::endl;
            return true;
        }
        case(GROUP):
        {
            fout<<"<"<<name;
            for(Properties::const_iterator oitr = properties.begin();
                oitr != properties.end();
                ++oitr)
            {
                fout<<" "<<oitr->first<<"=\"";
                writeString(fout,oitr->second);
                fout<<"\"";
            }
            fout<<">"<<std::endl;

            for(Children::const_iterator citr = children.begin();
                citr != children.end();
                ++citr)
            {
                (*citr)->write(fout);
            }

            fout<<"</"<<name<<">"<<std::endl;
            return true;
        }
        case(COMMENT):
        {
            fout<<"<!--"<<contents<<"-->"<<std::endl;
            return true;
        }
        case(INFORMATION):
        {
            fout<<"<?"<<contents<<"?>"<<std::endl;
            return true;
        }
    }
    return false;
}

bool XmlNode::writeString(std::ostream& fout, const std::string& str) const
{
    fout<<str;
    return true;
}
<commit_msg>Added tabs to treatment as white space to skyWhiteSpace()<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgDB/XmlParser>
#include <osgDB/FileUtils>

#include <osg/Notify>

using namespace osgDB;

XmlNode* osgDB::readXmlFile(const std::string& filename,const Options* options)
{
    std::string foundFile = osgDB::findDataFile(filename, options);
    if (!foundFile.empty())
    {
        XmlNode::Input input;
        input.open(foundFile);
        if (!input)
        {
            osg::notify(osg::NOTICE)<<"Could not open XML file: "<<filename<<std::endl;
            return 0;
        }

        input.readAllDataIntoBuffer();

        osg::ref_ptr<XmlNode> root = new XmlNode;
        root->read(input);

        return root.release();
    }
    else
    {
        osg::notify(osg::NOTICE)<<"Could not find XML file: "<<filename<<std::endl;
        return 0;
    }
}

XmlNode* osgDB::readXmlStream(std::istream& fin)
{
    XmlNode::Input input;
    input.attach(fin);
    if (!input)
    {
        osg::notify(osg::NOTICE)<<"Could not attach to XML stream."<<std::endl;
        return 0;
    }

    input.readAllDataIntoBuffer();

    osg::ref_ptr<XmlNode> root = new XmlNode;
    root->read(input);

    return root.release();
}

XmlNode::Input::Input():
    _currentPos(0)
{
    setUpControlMappings();
}

XmlNode::Input::Input(const Input&):
    _currentPos(0)
{
    setUpControlMappings();
}

XmlNode::Input::~Input()
{
}

void XmlNode::Input::setUpControlMappings()
{
    addControlToCharacter("&",'&');
    addControlToCharacter("<",'<');
    addControlToCharacter(">",'>');
    addControlToCharacter(""",'"');
    addControlToCharacter("'",'\'');
}

void XmlNode::Input::addControlToCharacter(const std::string& control, int c)
{
    _controlToCharacterMap[control] = c;
    _characterToControlMap[c] = control;
}

void XmlNode::Input::open(const std::string& filename)
{
    _fin.open(filename.c_str());
}

void XmlNode::Input::attach(std::istream& fin)
{
    std::ios &fios = _fin;
    fios.rdbuf(fin.rdbuf());
}

void XmlNode::Input::readAllDataIntoBuffer()
{
    while(_fin)
    {
        int c = _fin.get();
        if (c>=0 && c<=255)
        {
            _buffer.push_back(c);
        }
    }
}

void XmlNode::Input::skipWhiteSpace()
{
    while(_currentPos<_buffer.size() && _buffer[_currentPos]==' ' || _buffer[_currentPos]=='\t' )
    {
        // osg::notify(osg::NOTICE)<<"_currentPos="<<_currentPos<<"_buffer.size()="<<_buffer.size()<<" v="<<_buffer[_currentPos]<<std::endl;
        ++_currentPos;
    }
    //osg::notify(osg::NOTICE)<<"done"<<std::endl;
}

XmlNode::XmlNode()
{
    type = UNASSIGNED;
}

bool XmlNode::read(Input& input)
{
    if (type == UNASSIGNED) type = ROOT;

    while(input)
    {
        //input.skipWhiteSpace();
        if (input.match("<!--"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::COMMENT;
            children.push_back(commentNode);

            input += 4;
            XmlNode::Input::size_type end = input.find("-->");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                osg::notify(osg::INFO)<<"Valid Comment record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+3);
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Error: Unclosed Comment record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("</"))
        {
            input += 2;
            XmlNode::Input::size_type end = input.find(">");
            std::string comment = input.substr(0, end);
            if (end!=std::string::npos)
            {
                osg::notify(osg::INFO)<<"Valid end tag ["<<comment<<"]"<<std::endl;
                input += (end+1);
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Error: Unclosed end tag ["<<comment<<"]"<<std::endl;
                input += end;
            }

            if (comment==name) osg::notify(osg::INFO)<<"end tag is matched correctly"<<std::endl;
            else osg::notify(osg::NOTICE)<<"Error: end tag is not matched correctly"<<std::endl;

            return true;
        }
        else if (input.match("<?"))
        {
            XmlNode* commentNode = new XmlNode;
            commentNode->type = XmlNode::INFORMATION;
            children.push_back(commentNode);

            input += 2;
            XmlNode::Input::size_type end = input.find("?>");
            commentNode->contents = input.substr(0, end);
            if (end!=std::string::npos)
            {
                osg::notify(osg::INFO)<<"Valid infomation record ["<<commentNode->contents<<"]"<<std::endl;
                input += (end+2);
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Error: Unclosed infomation record ["<<commentNode->contents<<"]"<<std::endl;
                input += end;
            }
        }
        else if (input.match("<"))
        {
            XmlNode* childNode = new XmlNode;
            childNode->type = XmlNode::NODE;
            children.push_back(childNode);

            input += 1;

            input.skipWhiteSpace();

            int c = 0;
            while ((c=input[0])>=0 && c!=' ' && c!='>' )
            {
                childNode->name.push_back(c);
                ++input;
            }

            while ((c=input[0])>=0 && c!='>')
            {
                Input::size_type prev_pos = input.currentPosition();

                input.skipWhiteSpace();
                std::string option;
                std::string value;
                while((c=input[0])>=0 && c!='>' && c!='"' && c!='\'' && c!='=' && c!=' ')
                {
                    option.push_back(c);
                    ++input;
                }
                input.skipWhiteSpace();
                if (input[0]=='=')
                {
                    ++input;

                    input.skipWhiteSpace();

                    if (input[0]=='"')
                    {
                        ++input;
                        while((c=input[0])>=0 && c!='"')
                        {
                            value.push_back(c);
                            ++input;
                        }
                        ++input;
                    }
                    else if (input[0]=='\'')
                    {
                        ++input;
                        while((c=input[0])>=0 && c!='\'')
                        {
                            value.push_back(c);
                            ++input;
                        }
                        ++input;
                    }
                    else
                    {
                        ++input;
                        while((c=input[0])>=0 && c!=' ' && c!='"' && c!='\'' && c!='>')
                        {
                            value.push_back(c);
                            ++input;
                        }
                    }
                }

                if (prev_pos == input.currentPosition())
                {
                    osg::notify(osg::NOTICE)<<"Error, parser iterator note advanced, position: "<<input.substr(0,50)<<std::endl;
                    ++input;
                }

                if (!option.empty())
                {
                    osg::notify(osg::NOTICE)<<"Assigning option "<<option<<" with value "<<value<<std::endl;
                    childNode->properties[option] = value;
                }
            }

            if ((c=input[0])>=0 && c=='>' )
            {
                ++input;

                osg::notify(osg::INFO)<<"Valid tag ["<<childNode->name<<"]"<<std::endl;

                bool result = childNode->read(input);
                if (!result) return false;

                if (type==NODE && !children.empty()) type = GROUP;
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Unclosed tag ["<<childNode->name<<"]"<<std::endl;
                return false;
            }

        }
        else
        {
            int c = input[0];

            if (c=='&')
            {
                std::string value;
                while(input && (c=input.get())!=';') { value.push_back(c); }
                value.push_back(c);

                if (input._controlToCharacterMap.count(value)!=0)
                {
                    c = input._controlToCharacterMap[value];
                    osg::notify(osg::INFO)<<"Read control character "<<value<<" converted to "<<char(c)<<std::endl;
                    contents.push_back(c);
                }
                else
                {
                    osg::notify(osg::NOTICE)<<"Warning: read control character "<<value<<", but have no mapping to convert it to."<<std::endl;
                }
            }
            else
            {
                contents.push_back( c );
                ++input;
            }

        }
    }

    if (type==NODE && !children.empty()) type = GROUP;
    return false;
}

bool XmlNode::write(std::ostream& fout) const
{
    switch(type)
    {
        case(UNASSIGNED):
            return false;
        case(ATOM):
        {
            fout<<"<"<<name;
            for(Properties::const_iterator oitr = properties.begin();
                oitr != properties.end();
                ++oitr)
            {
                fout<<oitr->first<<"\"";
                writeString(fout,oitr->second);
                fout<<"\""<<std::endl;
            }
            return true;
        }
        case(ROOT):
        {
            for(Children::const_iterator citr = children.begin();
                citr != children.end();
                ++citr)
            {
                (*citr)->write(fout);
            }
            return true;
        }
        case(NODE):
        {
            fout<<"<"<<name;
            for(Properties::const_iterator oitr = properties.begin();
                oitr != properties.end();
                ++oitr)
            {
                fout<<" "<<oitr->first<<"=\"";
                writeString(fout,oitr->second);
                fout<<"\"";
            }
            fout<<">";

            for(Children::const_iterator citr = children.begin();
                citr != children.end();
                ++citr)
            {
                (*citr)->write(fout);
            }

            if (!contents.empty()) writeString(fout,contents);

            fout<<"</"<<name<<">"<<std::endl;
            return true;
        }
        case(GROUP):
        {
            fout<<"<"<<name;
            for(Properties::const_iterator oitr = properties.begin();
                oitr != properties.end();
                ++oitr)
            {
                fout<<" "<<oitr->first<<"=\"";
                writeString(fout,oitr->second);
                fout<<"\"";
            }
            fout<<">"<<std::endl;

            for(Children::const_iterator citr = children.begin();
                citr != children.end();
                ++citr)
            {
                (*citr)->write(fout);
            }

            fout<<"</"<<name<<">"<<std::endl;
            return true;
        }
        case(COMMENT):
        {
            fout<<"<!--"<<contents<<"-->"<<std::endl;
            return true;
        }
        case(INFORMATION):
        {
            fout<<"<?"<<contents<<"?>"<<std::endl;
            return true;
        }
    }
    return false;
}

bool XmlNode::writeString(std::ostream& fout, const std::string& str) const
{
    fout<<str;
    return true;
}
<|endoftext|>


<commit_before>/*
 * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Affero 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 Affero General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Ordered alphabetically using scriptname.
 * Scriptnames of files in this file should be prefixed with "npc_pet_dk_".
 */

#include "Cell.h"
#include "CellImpl.h"
#include "CombatAI.h"
#include "GridNotifiers.h"
#include "PassiveAI.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"

// TODO: this import is not necessary for compilation and marked as unused by the IDE
//  however, for some reasons removing it would cause a damn linking issue
//  there is probably some underlying problem with imports which should properly addressed
//  see: https://github.com/azerothcore/azerothcore-wotlk/issues/9766
#include "GridNotifiersImpl.h"

enum DeathKnightSpells
{
    SPELL_DK_SUMMON_GARGOYLE_1      = 49206,
    SPELL_DK_SUMMON_GARGOYLE_2      = 50514,
    SPELL_DK_DISMISS_GARGOYLE       = 50515,
    SPELL_DK_SANCTUARY              = 54661,
    SPELL_DK_NIGHT_OF_THE_DEAD      = 62137,
    SPELL_DK_PET_SCALING            = 61017
};

class npc_pet_dk_ebon_gargoyle : public CreatureScript
{
public:
    npc_pet_dk_ebon_gargoyle() : CreatureScript("npc_pet_dk_ebon_gargoyle") { }

    struct npc_pet_dk_ebon_gargoyleAI : ScriptedAI
    {
        npc_pet_dk_ebon_gargoyleAI(Creature* creature) : ScriptedAI(creature)
        {
            _despawnTimer = 36000; // 30 secs + 4 fly out + 2 initial attack timer
            _despawning = false;
            _initialSelection = true;
            _targetGUID.Clear();
        }

        void MovementInform(uint32 type, uint32 point) override
        {
            if (type == POINT_MOTION_TYPE && point == 1)
            {
                me->SetCanFly(false);
                me->SetDisableGravity(false);
            }
        }

        void InitializeAI() override
        {
            ScriptedAI::InitializeAI();
            Unit* owner = me->GetOwner();
            if (!owner)
                return;

            // Xinef: Night of the Dead avoidance
            if (Aura* aur = me->GetAura(SPELL_DK_NIGHT_OF_THE_DEAD))
                if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2718, 0))
                {
                    if (aur->GetEffect(0))
                    {
                        aur->GetEffect(0)->SetAmount(-aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue());
                    }
                }

            me->SetCanFly(true);
            me->SetDisableGravity(true);

            float tz = me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), true, MAX_FALL_DISTANCE);
            me->GetMotionMaster()->MoveCharge(me->GetPositionX(), me->GetPositionY(), tz, 7.0f, 1);
            me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
            _selectionTimer = 2000;
            _initialCastTimer = 0;
        }

        void MySelectNextTarget()
        {
            Unit* owner = me->GetOwner();
            if (owner && owner->GetTypeId() == TYPEID_PLAYER && (!me->GetVictim() || me->GetVictim()->IsImmunedToSpell(sSpellMgr->GetSpellInfo(51963)) || !me->IsValidAttackTarget(me->GetVictim()) || !owner->CanSeeOrDetect(me->GetVictim())))
            {
                Unit* selection = owner->ToPlayer()->GetSelectedUnit();
                if (selection && selection != me->GetVictim() && me->IsValidAttackTarget(selection))
                {
                    me->GetMotionMaster()->Clear(false);
                    SetGazeOn(selection);
                }

                else if (!me->GetVictim() || !owner->CanSeeOrDetect(me->GetVictim()))
                {
                    me->CombatStop(true);
                    me->GetMotionMaster()->Clear(false);
                    me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, 0.0f);
                    RemoveTargetAura();
                }
            }
        }

        void AttackStart(Unit* who) override
        {
            RemoveTargetAura();
            _targetGUID = who->GetGUID();
            me->AddAura(SPELL_DK_SUMMON_GARGOYLE_1, who);
            ScriptedAI::AttackStart(who);
        }

        void RemoveTargetAura()
        {
            if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID))
                target->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetGUID());
        }

        void Reset() override
        {
            _selectionTimer = 0;
            me->SetReactState(REACT_PASSIVE);
            MySelectNextTarget();
        }

        // Fly away when dismissed
        void FlyAway()
        {
            RemoveTargetAura();

            // Stop Fighting
            me->CombatStop(true);
            me->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE, true);

            // Sanctuary
            me->CastSpell(me, SPELL_DK_SANCTUARY, true);
            me->SetReactState(REACT_PASSIVE);

            me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
            me->SetSpeed(MOVE_RUN, 1.0f, true);
            float x = me->GetPositionX() + 20 * cos(me->GetOrientation());
            float y = me->GetPositionY() + 20 * std::sin(me->GetOrientation());
            float z = me->GetPositionZ() + 40;
            me->DisableSpline();
            me->GetMotionMaster()->Clear(false);

            me->GetMotionMaster()->MoveCharge(x, y, z, 7.0f, 1);
            me->SetCanFly(true);
            me->SetDisableGravity(true);

            _despawning = true;
        }

        void UpdateAI(uint32 diff) override
        {
            if (_initialSelection)
            {
                _initialSelection = false;
                // Find victim of Summon Gargoyle spell
                std::list<Unit*> targets;
                Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50.0f);
                Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
                Cell::VisitAllObjects(me, searcher, 50.0f);
                for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
                    if ((*iter)->GetAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID()))
                    {
                        (*iter)->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID());
                        SetGazeOn(*iter);
                        _targetGUID = (*iter)->GetGUID();
                        break;
                    }
            }
            if (_despawnTimer > 4000)
            {
                _despawnTimer -= diff;
                if (!UpdateVictimWithGaze())
                {
                    MySelectNextTarget();
                    return;
                }

                _initialCastTimer += diff;
                _selectionTimer += diff;
                if (_selectionTimer >= 1000)
                {
                    MySelectNextTarget();
                    _selectionTimer = 0;
                }
                if (_initialCastTimer >= 2000 && !me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_LOST_CONTROL) && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
                    me->CastSpell(me->GetVictim(), 51963, false);
            }
            else
            {
                if (!_despawning)
                    FlyAway();

                if (_despawnTimer > diff)
                    _despawnTimer -= diff;
                else
                    me->DespawnOrUnsummon();
            }
        }

    private:
        ObjectGuid _targetGUID;
        uint32 _despawnTimer;
        uint32 _selectionTimer;
        uint32 _initialCastTimer;
        bool _despawning;
        bool _initialSelection;
    };

    CreatureAI* GetAI(Creature* creature) const override
    {
        return new npc_pet_dk_ebon_gargoyleAI(creature);
    }
};

class npc_pet_dk_ghoul : public CreatureScript
{
public:
    npc_pet_dk_ghoul() : CreatureScript("npc_pet_dk_ghoul") { }

    struct npc_pet_dk_ghoulAI : public CombatAI
    {
        npc_pet_dk_ghoulAI(Creature* c) : CombatAI(c) { }

        void JustDied(Unit* /*who*/) override
        {
            if (me->IsGuardian() || me->IsSummon())
                me->ToTempSummon()->UnSummon();
        }
    };

    CreatureAI* GetAI(Creature* pCreature) const override
    {
        return new npc_pet_dk_ghoulAI (pCreature);
    }
};

class npc_pet_dk_army_of_the_dead : public CreatureScript
{
public:
    npc_pet_dk_army_of_the_dead() : CreatureScript("npc_pet_dk_army_of_the_dead") { }

    struct npc_pet_dk_army_of_the_deadAI : public CombatAI
    {
        npc_pet_dk_army_of_the_deadAI(Creature* creature) : CombatAI(creature) { }

        void InitializeAI() override
        {
            CombatAI::InitializeAI();
            ((Minion*)me)->SetFollowAngle(rand_norm() * 2 * M_PI);

            // Heroism / Bloodlust immunity
            me->ApplySpellImmune(0, IMMUNITY_ID, 32182, true);
            me->ApplySpellImmune(0, IMMUNITY_ID, 2825, true);
        }
    };

    CreatureAI* GetAI(Creature* creature) const override
    {
        return new npc_pet_dk_army_of_the_deadAI (creature);
    }
};

class npc_pet_dk_dancing_rune_weapon : public CreatureScript
{
public:
    npc_pet_dk_dancing_rune_weapon() : CreatureScript("npc_pet_dk_dancing_rune_weapon") { }

    struct npc_pet_dk_dancing_rune_weaponAI : public NullCreatureAI
    {
        npc_pet_dk_dancing_rune_weaponAI(Creature* creature) : NullCreatureAI(creature) { }

        void InitializeAI() override
        {
            // Xinef: Hit / Expertise scaling
            me->AddAura(61017, me);
            if (Unit* owner = me->GetOwner())
                me->GetMotionMaster()->MoveFollow(owner, 0.01f, me->GetFollowAngle(), MOTION_SLOT_CONTROLLED);

            NullCreatureAI::InitializeAI();
        }
    };

    CreatureAI* GetAI(Creature* creature) const override
    {
        return new npc_pet_dk_dancing_rune_weaponAI (creature);
    }
};

class spell_pet_dk_gargoyle_strike : public SpellScript
{
    PrepareSpellScript(spell_pet_dk_gargoyle_strike);

    void HandleDamageCalc(SpellEffIndex /*effIndex*/)
    {
        int32 damage = 60;
        if (Unit* caster = GetCaster())
        {
            if (caster->getLevel() >= 60)
            {
                damage += (caster->getLevel() - 60) * 4;
            }
        }

        SetHitDamage(damage);
    }

    void Register() override
    {
        OnEffectHitTarget += SpellEffectFn(spell_pet_dk_gargoyle_strike::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
    }
};

void AddSC_deathknight_pet_scripts()
{
    new npc_pet_dk_ebon_gargoyle();
    new npc_pet_dk_ghoul();
    new npc_pet_dk_army_of_the_dead();
    new npc_pet_dk_dancing_rune_weapon();
    RegisterSpellScript(spell_pet_dk_gargoyle_strike);
}
<commit_msg>fix(Scripts/Spell): Gargoyle's damage (#11389)<commit_after>/*
 * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Affero 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 Affero General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Ordered alphabetically using scriptname.
 * Scriptnames of files in this file should be prefixed with "npc_pet_dk_".
 */

#include "Cell.h"
#include "CellImpl.h"
#include "CombatAI.h"
#include "GridNotifiers.h"
#include "PassiveAI.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"

// TODO: this import is not necessary for compilation and marked as unused by the IDE
//  however, for some reasons removing it would cause a damn linking issue
//  there is probably some underlying problem with imports which should properly addressed
//  see: https://github.com/azerothcore/azerothcore-wotlk/issues/9766
#include "GridNotifiersImpl.h"

enum DeathKnightSpells
{
    SPELL_DK_SUMMON_GARGOYLE_1      = 49206,
    SPELL_DK_SUMMON_GARGOYLE_2      = 50514,
    SPELL_DK_DISMISS_GARGOYLE       = 50515,
    SPELL_DK_SANCTUARY              = 54661,
    SPELL_DK_NIGHT_OF_THE_DEAD      = 62137,
    SPELL_DK_PET_SCALING            = 61017
};

class npc_pet_dk_ebon_gargoyle : public CreatureScript
{
public:
    npc_pet_dk_ebon_gargoyle() : CreatureScript("npc_pet_dk_ebon_gargoyle") { }

    struct npc_pet_dk_ebon_gargoyleAI : ScriptedAI
    {
        npc_pet_dk_ebon_gargoyleAI(Creature* creature) : ScriptedAI(creature)
        {
            _despawnTimer = 36000; // 30 secs + 4 fly out + 2 initial attack timer
            _despawning = false;
            _initialSelection = true;
            _targetGUID.Clear();
        }

        void MovementInform(uint32 type, uint32 point) override
        {
            if (type == POINT_MOTION_TYPE && point == 1)
            {
                me->SetCanFly(false);
                me->SetDisableGravity(false);
            }
        }

        void InitializeAI() override
        {
            ScriptedAI::InitializeAI();
            Unit* owner = me->GetOwner();
            if (!owner)
                return;

            // Xinef: Night of the Dead avoidance
            if (Aura* aur = me->GetAura(SPELL_DK_NIGHT_OF_THE_DEAD))
                if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2718, 0))
                {
                    if (aur->GetEffect(0))
                    {
                        aur->GetEffect(0)->SetAmount(-aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue());
                    }
                }

            me->SetCanFly(true);
            me->SetDisableGravity(true);

            float tz = me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), true, MAX_FALL_DISTANCE);
            me->GetMotionMaster()->MoveCharge(me->GetPositionX(), me->GetPositionY(), tz, 7.0f, 1);
            me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
            _selectionTimer = 2000;
            _initialCastTimer = 0;
        }

        void MySelectNextTarget()
        {
            Unit* owner = me->GetOwner();
            if (owner && owner->GetTypeId() == TYPEID_PLAYER && (!me->GetVictim() || me->GetVictim()->IsImmunedToSpell(sSpellMgr->GetSpellInfo(51963)) || !me->IsValidAttackTarget(me->GetVictim()) || !owner->CanSeeOrDetect(me->GetVictim())))
            {
                Unit* selection = owner->ToPlayer()->GetSelectedUnit();
                if (selection && selection != me->GetVictim() && me->IsValidAttackTarget(selection))
                {
                    me->GetMotionMaster()->Clear(false);
                    SetGazeOn(selection);
                }

                else if (!me->GetVictim() || !owner->CanSeeOrDetect(me->GetVictim()))
                {
                    me->CombatStop(true);
                    me->GetMotionMaster()->Clear(false);
                    me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, 0.0f);
                    RemoveTargetAura();
                }
            }
        }

        void AttackStart(Unit* who) override
        {
            RemoveTargetAura();
            _targetGUID = who->GetGUID();
            me->AddAura(SPELL_DK_SUMMON_GARGOYLE_1, who);
            ScriptedAI::AttackStart(who);
        }

        void RemoveTargetAura()
        {
            if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID))
                target->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetGUID());
        }

        void Reset() override
        {
            _selectionTimer = 0;
            me->SetReactState(REACT_PASSIVE);
            MySelectNextTarget();
        }

        // Fly away when dismissed
        void FlyAway()
        {
            RemoveTargetAura();

            // Stop Fighting
            me->CombatStop(true);
            me->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE, true);

            // Sanctuary
            me->CastSpell(me, SPELL_DK_SANCTUARY, true);
            me->SetReactState(REACT_PASSIVE);

            me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
            me->SetSpeed(MOVE_RUN, 1.0f, true);
            float x = me->GetPositionX() + 20 * cos(me->GetOrientation());
            float y = me->GetPositionY() + 20 * std::sin(me->GetOrientation());
            float z = me->GetPositionZ() + 40;
            me->DisableSpline();
            me->GetMotionMaster()->Clear(false);

            me->GetMotionMaster()->MoveCharge(x, y, z, 7.0f, 1);
            me->SetCanFly(true);
            me->SetDisableGravity(true);

            _despawning = true;
        }

        void UpdateAI(uint32 diff) override
        {
            if (_initialSelection)
            {
                _initialSelection = false;
                // Find victim of Summon Gargoyle spell
                std::list<Unit*> targets;
                Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50.0f);
                Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
                Cell::VisitAllObjects(me, searcher, 50.0f);
                for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
                    if ((*iter)->GetAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID()))
                    {
                        (*iter)->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID());
                        SetGazeOn(*iter);
                        _targetGUID = (*iter)->GetGUID();
                        break;
                    }
            }
            if (_despawnTimer > 4000)
            {
                _despawnTimer -= diff;
                if (!UpdateVictimWithGaze())
                {
                    MySelectNextTarget();
                    return;
                }

                _initialCastTimer += diff;
                _selectionTimer += diff;
                if (_selectionTimer >= 1000)
                {
                    MySelectNextTarget();
                    _selectionTimer = 0;
                }
                if (_initialCastTimer >= 2000 && !me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_LOST_CONTROL) && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
                    me->CastSpell(me->GetVictim(), 51963, false);
            }
            else
            {
                if (!_despawning)
                    FlyAway();

                if (_despawnTimer > diff)
                    _despawnTimer -= diff;
                else
                    me->DespawnOrUnsummon();
            }
        }

    private:
        ObjectGuid _targetGUID;
        uint32 _despawnTimer;
        uint32 _selectionTimer;
        uint32 _initialCastTimer;
        bool _despawning;
        bool _initialSelection;
    };

    CreatureAI* GetAI(Creature* creature) const override
    {
        return new npc_pet_dk_ebon_gargoyleAI(creature);
    }
};

class npc_pet_dk_ghoul : public CreatureScript
{
public:
    npc_pet_dk_ghoul() : CreatureScript("npc_pet_dk_ghoul") { }

    struct npc_pet_dk_ghoulAI : public CombatAI
    {
        npc_pet_dk_ghoulAI(Creature* c) : CombatAI(c) { }

        void JustDied(Unit* /*who*/) override
        {
            if (me->IsGuardian() || me->IsSummon())
                me->ToTempSummon()->UnSummon();
        }
    };

    CreatureAI* GetAI(Creature* pCreature) const override
    {
        return new npc_pet_dk_ghoulAI (pCreature);
    }
};

class npc_pet_dk_army_of_the_dead : public CreatureScript
{
public:
    npc_pet_dk_army_of_the_dead() : CreatureScript("npc_pet_dk_army_of_the_dead") { }

    struct npc_pet_dk_army_of_the_deadAI : public CombatAI
    {
        npc_pet_dk_army_of_the_deadAI(Creature* creature) : CombatAI(creature) { }

        void InitializeAI() override
        {
            CombatAI::InitializeAI();
            ((Minion*)me)->SetFollowAngle(rand_norm() * 2 * M_PI);

            // Heroism / Bloodlust immunity
            me->ApplySpellImmune(0, IMMUNITY_ID, 32182, true);
            me->ApplySpellImmune(0, IMMUNITY_ID, 2825, true);
        }
    };

    CreatureAI* GetAI(Creature* creature) const override
    {
        return new npc_pet_dk_army_of_the_deadAI (creature);
    }
};

class npc_pet_dk_dancing_rune_weapon : public CreatureScript
{
public:
    npc_pet_dk_dancing_rune_weapon() : CreatureScript("npc_pet_dk_dancing_rune_weapon") { }

    struct npc_pet_dk_dancing_rune_weaponAI : public NullCreatureAI
    {
        npc_pet_dk_dancing_rune_weaponAI(Creature* creature) : NullCreatureAI(creature) { }

        void InitializeAI() override
        {
            // Xinef: Hit / Expertise scaling
            me->AddAura(61017, me);
            if (Unit* owner = me->GetOwner())
                me->GetMotionMaster()->MoveFollow(owner, 0.01f, me->GetFollowAngle(), MOTION_SLOT_CONTROLLED);

            NullCreatureAI::InitializeAI();
        }
    };

    CreatureAI* GetAI(Creature* creature) const override
    {
        return new npc_pet_dk_dancing_rune_weaponAI (creature);
    }
};

class spell_pet_dk_gargoyle_strike : public SpellScript
{
    PrepareSpellScript(spell_pet_dk_gargoyle_strike);

    void HandleDamageCalc(SpellEffIndex /*effIndex*/)
    {
        int32 damage = 60;
        if (Unit* caster = GetCaster())
        {
            if (caster->getLevel() >= 60)
            {
                damage += (caster->getLevel() - 60) * 4;
            }
        }

        SetEffectValue(damage);
    }

    void Register() override
    {
        OnEffectHitTarget += SpellEffectFn(spell_pet_dk_gargoyle_strike::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
    }
};

void AddSC_deathknight_pet_scripts()
{
    new npc_pet_dk_ebon_gargoyle();
    new npc_pet_dk_ghoul();
    new npc_pet_dk_army_of_the_dead();
    new npc_pet_dk_dancing_rune_weapon();
    RegisterSpellScript(spell_pet_dk_gargoyle_strike);
}
<|endoftext|>


<commit_before><commit_msg>Linux: reap the sandbox helper process.<commit_after><|endoftext|>


<commit_before><commit_msg>Remove stray semicolon<commit_after><|endoftext|>


<commit_before><commit_msg>cf-fbx skin processing<commit_after><|endoftext|>


<commit_before>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/test/ui/npapi_test_helper.h"

#include "base/file_util.h"
#include "base/test/test_file_util.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_WIN)
static const char kNpapiTestPluginName[] = "npapi_test_plugin.dll";
#elif defined(OS_MACOSX)
static const char kNpapiTestPluginName[] = "npapi_test_plugin.plugin";
static const char kLayoutPluginName[] = "TestNetscapePlugIn.plugin";
#elif defined(OS_LINUX)
static const char kNpapiTestPluginName[] = "libnpapi_test_plugin.so";
#endif

namespace npapi_test {
const char kTestCompleteCookie[] = "status";
const char kTestCompleteSuccess[] = "OK";
}  // namespace npapi_test.

NPAPITesterBase::NPAPITesterBase(const std::string& test_plugin_name)
  : test_plugin_name_(test_plugin_name) {
}

void NPAPITesterBase::SetUp() {
  // We need to copy our test-plugin into the plugins directory so that
  // the browser can load it.
  // TODO(tc): We should copy the plugins as a build step, not during
  // the tests.  Then we don't have to clean up after the copy in the test.
  FilePath plugins_directory = GetPluginsDirectory();
  FilePath plugin_src = browser_directory_.AppendASCII(test_plugin_name_);
  ASSERT_TRUE(file_util::PathExists(plugin_src));
  test_plugin_path_ = plugins_directory.AppendASCII(test_plugin_name_);

  file_util::CreateDirectory(plugins_directory);
  ASSERT_TRUE(file_util::CopyDirectory(plugin_src, test_plugin_path_, true))
      << "Copy failed from " << plugin_src.value()
      << " to " << test_plugin_path_.value();
#if defined(OS_MACOSX)
  // The plugins directory isn't read by default on the Mac, so it needs to be
  // explicitly registered.
  launch_arguments_.AppendSwitchPath(switches::kExtraPluginDir,
                                     plugins_directory);
#endif

  UITest::SetUp();
}

void NPAPITesterBase::TearDown() {
  // Tear down the UI test first so that the browser stops using the plugin
  // files.
  UITest::TearDown();
}

FilePath NPAPITesterBase::GetPluginsDirectory() {
  FilePath plugins_directory = browser_directory_.AppendASCII("plugins");
  return plugins_directory;
}

NPAPITester::NPAPITester() : NPAPITesterBase(kNpapiTestPluginName) {
}

void NPAPITester::SetUp() {
#if defined(OS_MACOSX)
  // TODO(stuartmorgan): Remove this whole subclass once the WebKit build is
  // changed to copy the plugin into a plugins directory next to the app as
  // is done on Linux and Windows.
  FilePath layout_src = browser_directory_.AppendASCII(kLayoutPluginName);
  ASSERT_TRUE(file_util::PathExists(layout_src));
  FilePath plugins_directory = GetPluginsDirectory();
  layout_plugin_path_ = plugins_directory.AppendASCII(kLayoutPluginName);
  file_util::CreateDirectory(plugins_directory);
  ASSERT_TRUE(file_util::CopyDirectory(layout_src, layout_plugin_path_, true));
#endif

  NPAPITesterBase::SetUp();
}

void NPAPITester::TearDown() {
  // Tear down the base class first so that the browser stops using the plugin
  // files.
  NPAPITesterBase::TearDown();
}

// NPAPIVisiblePluginTester members.
void NPAPIVisiblePluginTester::SetUp() {
  show_window_ = true;
  NPAPITester::SetUp();
}

// NPAPIIncognitoTester members.
void NPAPIIncognitoTester::SetUp() {
  launch_arguments_.AppendSwitch(switches::kIncognito);
  NPAPITester::SetUp();
}
<commit_msg>Only copy the plugin if it doesn't already exist.<commit_after>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/test/ui/npapi_test_helper.h"

#include "base/file_util.h"
#include "base/test/test_file_util.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_WIN)
static const char kNpapiTestPluginName[] = "npapi_test_plugin.dll";
#elif defined(OS_MACOSX)
static const char kNpapiTestPluginName[] = "npapi_test_plugin.plugin";
static const char kLayoutPluginName[] = "TestNetscapePlugIn.plugin";
#elif defined(OS_LINUX)
static const char kNpapiTestPluginName[] = "libnpapi_test_plugin.so";
#endif

namespace npapi_test {
const char kTestCompleteCookie[] = "status";
const char kTestCompleteSuccess[] = "OK";
}  // namespace npapi_test.

NPAPITesterBase::NPAPITesterBase(const std::string& test_plugin_name)
  : test_plugin_name_(test_plugin_name) {
}

void NPAPITesterBase::SetUp() {
  // We need to copy our test-plugin into the plugins directory so that
  // the browser can load it.
  // TODO(tc): We should copy the plugins as a build step, not during
  // the tests.  Then we don't have to clean up after the copy in the test.
  FilePath plugins_directory = GetPluginsDirectory();
  FilePath plugin_src = browser_directory_.AppendASCII(test_plugin_name_);
  ASSERT_TRUE(file_util::PathExists(plugin_src));
  test_plugin_path_ = plugins_directory.AppendASCII(test_plugin_name_);

  file_util::CreateDirectory(plugins_directory);
  if (!file_util::PathExists(test_plugin_path_)) {
    ASSERT_TRUE(file_util::CopyDirectory(plugin_src, test_plugin_path_, true))
        << "Copy failed from " << plugin_src.value()
        << " to " << test_plugin_path_.value();
  }
#if defined(OS_MACOSX)
  // The plugins directory isn't read by default on the Mac, so it needs to be
  // explicitly registered.
  launch_arguments_.AppendSwitchPath(switches::kExtraPluginDir,
                                     plugins_directory);
#endif

  UITest::SetUp();
}

void NPAPITesterBase::TearDown() {
  // Tear down the UI test first so that the browser stops using the plugin
  // files.
  UITest::TearDown();
}

FilePath NPAPITesterBase::GetPluginsDirectory() {
  FilePath plugins_directory = browser_directory_.AppendASCII("plugins");
  return plugins_directory;
}

NPAPITester::NPAPITester() : NPAPITesterBase(kNpapiTestPluginName) {
}

void NPAPITester::SetUp() {
#if defined(OS_MACOSX)
  // TODO(stuartmorgan): Remove this whole subclass once the WebKit build is
  // changed to copy the plugin into a plugins directory next to the app as
  // is done on Linux and Windows.
  FilePath layout_src = browser_directory_.AppendASCII(kLayoutPluginName);
  ASSERT_TRUE(file_util::PathExists(layout_src));
  FilePath plugins_directory = GetPluginsDirectory();
  layout_plugin_path_ = plugins_directory.AppendASCII(kLayoutPluginName);
  file_util::CreateDirectory(plugins_directory);
  ASSERT_TRUE(file_util::CopyDirectory(layout_src, layout_plugin_path_, true));
#endif

  NPAPITesterBase::SetUp();
}

void NPAPITester::TearDown() {
  // Tear down the base class first so that the browser stops using the plugin
  // files.
  NPAPITesterBase::TearDown();
}

// NPAPIVisiblePluginTester members.
void NPAPIVisiblePluginTester::SetUp() {
  show_window_ = true;
  NPAPITester::SetUp();
}

// NPAPIIncognitoTester members.
void NPAPIIncognitoTester::SetUp() {
  launch_arguments_.AppendSwitch(switches::kIncognito);
  NPAPITester::SetUp();
}
<|endoftext|>