MyGUI  3.2.1
MyGUI_XmlDocument.cpp
Go to the documentation of this file.
00001 /*
00002  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
00003  * Distributed under the MIT License
00004  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
00005  */
00006 
00007 #include "MyGUI_Precompiled.h"
00008 #include "MyGUI_XmlDocument.h"
00009 #include "MyGUI_DataManager.h"
00010 
00011 namespace MyGUI
00012 {
00013     namespace xml
00014     {
00015 
00016         namespace utility
00017         {
00018             static std::string convert_from_xml(const std::string& _string, bool& _ok)
00019             {
00020                 std::string ret;
00021                 _ok = true;
00022 
00023                 size_t pos = _string.find("&");
00024                 if (pos == std::string::npos) return _string;
00025 
00026                 ret.reserve(_string.size());
00027                 size_t old = 0;
00028                 while (pos != std::string::npos)
00029                 {
00030                     ret += _string.substr(old, pos - old);
00031 
00032                     size_t end = _string.find(";", pos + 1);
00033                     if (end == std::string::npos)
00034                     {
00035                         _ok = false;
00036                         return ret;
00037                     }
00038                     else
00039                     {
00040                         std::string tag = _string.substr(pos, end - pos + 1);
00041                         if (tag == "&") ret += '&';
00042                         else if (tag == "&lt;") ret += '<';
00043                         else if (tag == "&gt;") ret += '>';
00044                         else if (tag == "&apos;") ret += '\'';
00045                         else if (tag == "&quot;") ret += '\"';
00046                         else
00047                         {
00048                             _ok = false;
00049                             return ret;
00050                         }
00051                     }
00052 
00053                     old = end + 1;
00054                     pos = _string.find("&", old);
00055                 }
00056                 ret += _string.substr(old, std::string::npos);
00057 
00058                 return ret;
00059             }
00060 
00061             static std::string convert_to_xml(const std::string& _string)
00062             {
00063                 std::string ret;
00064 
00065                 size_t pos = _string.find_first_of("&<>'\"");
00066                 if (pos == std::string::npos) return _string;
00067 
00068                 ret.reserve(_string.size() * 2);
00069                 size_t old = 0;
00070                 while (pos != std::string::npos)
00071                 {
00072                     ret += _string.substr(old, pos - old);
00073 
00074                     if (_string[pos] == '&') ret += "&amp;";
00075                     else if (_string[pos] == '<') ret += "&lt;";
00076                     else if (_string[pos] == '>') ret += "&gt;";
00077                     else if (_string[pos] == '\'') ret += "&apos;";
00078                     else if (_string[pos] == '\"') ret += "&quot;";
00079 
00080                     old = pos + 1;
00081                     pos = _string.find_first_of("&<>'\"", old);
00082                 }
00083                 ret += _string.substr(old, std::string::npos);
00084 
00085                 return ret;
00086             }
00087 
00088         }
00089 
00090         //----------------------------------------------------------------------//
00091         // class ElementEnumerator
00092         //----------------------------------------------------------------------//
00093         ElementEnumerator::ElementEnumerator(VectorElement::iterator _begin, VectorElement::iterator _end) :
00094             m_first(true),
00095             m_current(_begin),
00096             m_end(_end)
00097         {
00098         }
00099 
00100         bool ElementEnumerator::next()
00101         {
00102             if (m_current == m_end)
00103                 return false;
00104             else if (m_first)
00105             {
00106                 m_first = false;
00107                 return true;
00108             }
00109             ++ m_current;
00110             if (m_current == m_end)
00111                 return false;
00112             return true;
00113         }
00114 
00115         bool ElementEnumerator::next(const std::string& _name)
00116         {
00117             while (next())
00118             {
00119                 if ((*m_current)->getName() == _name)
00120                     return true;
00121             }
00122             return false;
00123         }
00124 
00125         ElementPtr ElementEnumerator::operator->() const
00126         {
00127             assert(m_current != m_end);
00128             return (*m_current);
00129         }
00130 
00131         ElementPtr ElementEnumerator::current()
00132         {
00133             assert(m_current != m_end);
00134             return (*m_current);
00135         }
00136 
00137         //----------------------------------------------------------------------//
00138         // class Element
00139         //----------------------------------------------------------------------//
00140         Element::Element(const std::string& _name, ElementPtr _parent, ElementType _type, const std::string& _content) :
00141             mName(_name),
00142             mContent(_content),
00143             mParent(_parent),
00144             mType(_type)
00145         {
00146         }
00147 
00148         Element::~Element()
00149         {
00150             for (VectorElement::iterator iter = mChilds.begin(); iter != mChilds.end(); ++iter)
00151             {
00152                 delete *iter;
00153             }
00154             mChilds.clear();
00155         }
00156 
00157         void Element::save(std::ostream& _stream, size_t _level)
00158         {
00159             // сначала табуляции намутим
00160             for (size_t tab = 0; tab < _level; ++tab)
00161                 _stream  << "    ";
00162 
00163             // теперь заголовок тега
00164             if (mType == ElementType::Declaration)
00165                 _stream << "<?";
00166             else if (mType == ElementType::Comment)
00167                 _stream << "<!--";
00168             else
00169                 _stream << "<";
00170 
00171             _stream << mName;
00172 
00173             for (VectorAttributes::iterator iter = mAttributes.begin(); iter != mAttributes.end(); ++iter)
00174             {
00175                 _stream << " " << iter->first << "=\"" << utility::convert_to_xml(iter->second) << "\"";
00176             }
00177 
00178             bool empty = mChilds.empty();
00179             // если детей нет то закрываем
00180             if (empty && mContent.empty())
00181             {
00182                 if (mType == ElementType::Declaration)
00183                     _stream << "?>\n";
00184                 else if (mType == ElementType::Comment)
00185                     _stream << "-->\n";
00186                 else
00187                     _stream << "/>\n";
00188             }
00189             else
00190             {
00191                 _stream << ">";
00192                 if (!empty)
00193                     _stream << "\n";
00194                 // если есть тело то сначало оно
00195                 if (!mContent.empty())
00196                 {
00197                     if (!empty)
00198                     {
00199                         for (size_t tab = 0; tab <= _level; ++tab) _stream  << "    ";
00200                     }
00201                     _stream << utility::convert_to_xml(mContent);
00202 
00203                     if (!empty)
00204                         _stream << "\n";
00205                 }
00206                 // если есть детишки путь сохранятся
00207                 for (size_t child = 0; child < mChilds.size(); child++)
00208                 {
00209                     mChilds[child]->save(_stream, _level + 1);
00210                 }
00211 
00212                 if (!empty)
00213                 {
00214                     for (size_t tab = 0; tab < _level; ++tab)
00215                         _stream  << "    ";
00216                 }
00217                 _stream << "</" << mName << ">\n";
00218             }
00219         }
00220 
00221         ElementPtr Element::createChild(const std::string& _name, const std::string& _content, ElementType _type)
00222         {
00223             ElementPtr node = new Element(_name, this, _type, _content);
00224             mChilds.push_back(node);
00225             return node;
00226         }
00227 
00228         void Element::removeChild(ElementPtr _child)
00229         {
00230             VectorElement::iterator item = std::find(mChilds.begin(), mChilds.end(), _child);
00231             if (item != mChilds.end())
00232             {
00233                 delete (*item);
00234                 mChilds.erase(item);
00235             }
00236         }
00237 
00238         void Element::clear()
00239         {
00240             for (VectorElement::iterator iter = mChilds.begin(); iter != mChilds.end(); ++iter) delete *iter;
00241             mChilds.clear();
00242             mContent.clear();
00243             mAttributes.clear();
00244         }
00245 
00246         bool Element::findAttribute(const std::string& _name, std::string& _value)
00247         {
00248             for (VectorAttributes::iterator iter = mAttributes.begin(); iter != mAttributes.end(); ++iter)
00249             {
00250                 if ( (*iter).first == _name)
00251                 {
00252                     _value = (*iter).second;
00253                     return true;
00254                 }
00255             }
00256             return false;
00257         }
00258 
00259         std::string Element::findAttribute(const std::string& _name)
00260         {
00261             for (VectorAttributes::iterator iter = mAttributes.begin(); iter != mAttributes.end(); ++iter)
00262             {
00263                 if ((*iter).first == _name)
00264                     return (*iter).second;
00265             }
00266             return "";
00267         }
00268 
00269         void Element::addAttribute(const std::string& _key, const std::string& _value)
00270         {
00271             mAttributes.push_back(PairAttribute(_key, _value));
00272         }
00273 
00274         void Element::removeAttribute(const std::string& _key)
00275         {
00276             for (size_t index = 0; index < mAttributes.size(); ++index)
00277             {
00278                 if (mAttributes[index].first == _key)
00279                 {
00280                     mAttributes.erase(mAttributes.begin() + index);
00281                     return;
00282                 }
00283             }
00284         }
00285 
00286         ElementPtr Element::createCopy()
00287         {
00288             Element* elem = new Element(mName, nullptr, mType, mContent);
00289             elem->mAttributes = mAttributes;
00290 
00291             for (VectorElement::iterator iter = mChilds.begin(); iter != mChilds.end(); ++iter)
00292             {
00293                 Element* child = (*iter)->createCopy();
00294                 child->mParent = elem;
00295                 elem->mChilds.push_back(child);
00296             }
00297 
00298             return elem;
00299         }
00300 
00301         void Element::setAttribute(const std::string& _key, const std::string& _value)
00302         {
00303             for (size_t index = 0; index < mAttributes.size(); ++index)
00304             {
00305                 if (mAttributes[index].first == _key)
00306                 {
00307                     mAttributes[index].second = _value;
00308                     return;
00309                 }
00310             }
00311             mAttributes.push_back(PairAttribute(_key, _value));
00312         }
00313 
00314         void Element::addContent(const std::string& _content)
00315         {
00316             if (mContent.empty())
00317             {
00318                 mContent = _content;
00319             }
00320             else
00321             {
00322                 mContent += " ";
00323                 mContent += _content;
00324             }
00325         }
00326 
00327         void Element::setContent(const std::string& _content)
00328         {
00329             mContent = _content;
00330         }
00331 
00332         const std::string& Element::getName() const
00333         {
00334             return mName;
00335         }
00336 
00337         const std::string& Element::getContent() const
00338         {
00339             return mContent;
00340         }
00341 
00342         const VectorAttributes& Element::getAttributes() const
00343         {
00344             return mAttributes;
00345         }
00346 
00347         ElementPtr Element::getParent() const
00348         {
00349             return mParent;
00350         }
00351 
00352         ElementEnumerator Element::getElementEnumerator()
00353         {
00354             return ElementEnumerator(mChilds.begin(), mChilds.end());
00355         }
00356 
00357         ElementType Element::getType() const
00358         {
00359             return mType;
00360         }
00361 
00362 #if MYGUI_COMPILER == MYGUI_COMPILER_MSVC && !defined(STLPORT)
00363         inline void open_stream(std::ofstream& _stream, const std::wstring& _wide)
00364         {
00365             _stream.open(_wide.c_str());
00366         }
00367         inline void open_stream(std::ifstream& _stream, const std::wstring& _wide)
00368         {
00369             _stream.open(_wide.c_str());
00370         }
00371 #else
00372         inline void open_stream(std::ofstream& _stream, const std::wstring& _wide)
00373         {
00374             _stream.open(UString(_wide).asUTF8_c_str());
00375         }
00376         inline void open_stream(std::ifstream& _stream, const std::wstring& _wide)
00377         {
00378             _stream.open(UString(_wide).asUTF8_c_str());
00379         }
00380 #endif
00381 
00382         //----------------------------------------------------------------------//
00383         // class Document
00384         //----------------------------------------------------------------------//
00385         Document::Document():
00386             mRoot(0),
00387             mDeclaration(0),
00388             mLastErrorFile(""),
00389             mLine(0),
00390             mCol(0)
00391         {
00392         }
00393 
00394         Document::~Document()
00395         {
00396             clear();
00397         }
00398 
00399         // открывает обычным файлом, имя файла в utf8
00400         bool Document::open(const std::string& _filename)
00401         {
00402             std::ifstream stream;
00403             stream.open(_filename.c_str());
00404 
00405             if (!stream.is_open())
00406             {
00407                 mLastError = ErrorType::OpenFileFail;
00408                 setLastFileError(_filename);
00409                 return false;
00410             }
00411 
00412             bool result = open(stream);
00413 
00414             stream.close();
00415             return result;
00416         }
00417 
00418         // открывает обычным файлом, имя файла в utf16 или utf32
00419         bool Document::open(const std::wstring& _filename)
00420         {
00421             std::ifstream stream;
00422             open_stream(stream, _filename);
00423 
00424             if (!stream.is_open())
00425             {
00426                 mLastError = ErrorType::OpenFileFail;
00427                 setLastFileError(_filename);
00428                 return false;
00429             }
00430 
00431             bool result = open(stream);
00432 
00433             stream.close();
00434             return result;
00435         }
00436 
00437         bool Document::open(std::istream& _stream)
00438         {
00439             DataStream* data = new DataStream(&_stream);
00440 
00441             bool result = open(data);
00442             delete data;
00443 
00444             return result;
00445         }
00446 
00447         // сохраняет файл, имя файла в кодировке utf8
00448         bool Document::save(const std::string& _filename)
00449         {
00450             std::ofstream stream;
00451             stream.open(_filename.c_str());
00452 
00453             if (!stream.is_open())
00454             {
00455                 mLastError = ErrorType::CreateFileFail;
00456                 setLastFileError(_filename);
00457                 return false;
00458             }
00459 
00460             bool result = save(stream);
00461 
00462             if (!result)
00463             {
00464                 setLastFileError(_filename);
00465             }
00466 
00467             stream.close();
00468             return result;
00469         }
00470 
00471         // сохраняет файл, имя файла в кодировке utf16 или utf32
00472         bool Document::save(const std::wstring& _filename)
00473         {
00474             std::ofstream stream;
00475             open_stream(stream, _filename);
00476 
00477             if (!stream.is_open())
00478             {
00479                 mLastError = ErrorType::CreateFileFail;
00480                 setLastFileError(_filename);
00481                 return false;
00482             }
00483 
00484             bool result = save(stream);
00485 
00486             if (!result)
00487             {
00488                 setLastFileError(_filename);
00489             }
00490 
00491             stream.close();
00492             return result;
00493         }
00494 
00495         // открывает обычным потоком
00496         bool Document::open(IDataStream* _stream)
00497         {
00498             clear();
00499 
00500             // это текущая строка для разбора
00501             std::string line;
00502             // это строка из файла
00503             std::string read;
00504             // текущий узел для разбора
00505             ElementPtr currentNode = 0;
00506 
00507             while (!_stream->eof())
00508             {
00509                 // берем новую строку
00510                 _stream->readline(read, '\n');
00511                 if (read.empty())
00512                     continue;
00513                 if (read[read.size() - 1] == '\r')
00514                     read.erase(read.size() - 1, 1);
00515                 if (read.empty())
00516                     continue;
00517 
00518                 mLine ++;
00519                 mCol = 0; // потом проверить на многострочных тэгах
00520                 if (read.empty())
00521                     continue;
00522                 // текущая строка для разбора и то что еще прочитали
00523                 line += read;
00524 
00525                 if (!parseLine(line, currentNode))
00526                 {
00527                     return false;
00528                 }
00529 
00530             } // while (!stream.eof())
00531 
00532             if (currentNode)
00533             {
00534                 mLastError = ErrorType::NotClosedElements;
00535                 return false;
00536             }
00537 
00538             return true;
00539         }
00540 
00541         bool Document::save(std::ostream& _stream)
00542         {
00543             if (!mDeclaration)
00544             {
00545                 mLastError = ErrorType::NoXMLDeclaration;
00546                 return false;
00547             }
00548 
00549             // заголовок utf8
00550             _stream << (char)0xEFu;
00551             _stream << (char)0xBBu;
00552             _stream << (char)0xBFu;
00553 
00554             mDeclaration->save(_stream, 0);
00555             if (mRoot)
00556                 mRoot->save(_stream, 0);
00557 
00558             return true;
00559         }
00560 
00561         void Document::clear()
00562         {
00563             clearDeclaration();
00564             clearRoot();
00565             mLine = 0;
00566             mCol = 0;
00567         }
00568 
00569         bool Document::parseTag(ElementPtr& _currentNode, std::string _content)
00570         {
00571             // убераем лишнее
00572             MyGUI::utility::trim(_content);
00573 
00574             if (_content.empty())
00575             {
00576                 // создаем пустой тег
00577                 if (_currentNode)
00578                 {
00579                     _currentNode = _currentNode->createChild("");
00580                 }
00581                 else
00582                 {
00583                     _currentNode = new Element("", 0);
00584                     // если это первый то запоминаем
00585                     if (!mRoot)
00586                         mRoot = _currentNode;
00587                 }
00588                 return true;
00589             }
00590 
00591             char simbol = _content[0];
00592             bool tagDeclaration = false;
00593 
00594             // проверяем на коментарии
00595             if (simbol == '!')
00596             {
00597                 if (_currentNode != 0)
00598                 {
00599                     //_currentNode->createChild("", _content, ElementType::Comment);
00600                 }
00601                 return true;
00602             }
00603             // проверяем на информационный тег
00604             else if (simbol == '?')
00605             {
00606                 tagDeclaration = true;
00607                 _content.erase(0, 1); // удаляем первый символ
00608             }
00609 
00610             size_t start = 0;
00611             size_t end = 0;
00612             // проверяем на закрытие тега
00613             if (simbol == '/')
00614             {
00615                 if (_currentNode == 0)
00616                 {
00617                     // чета мы закрывам а ниче даже и не открыто
00618                     if (!mRoot)
00619                     {
00620                         mLastError = ErrorType::CloseNotOpenedElement;
00621                         return false;
00622                     }
00623                 }
00624                 // обрезаем имя тэга
00625                 start = _content.find_first_not_of(" \t", 1);
00626                 if (start == _content.npos)
00627                 {
00628                     // тег пустой
00629                     _content.clear();
00630                 }
00631                 else
00632                 {
00633                     end = _content.find_last_not_of(" \t");
00634                     _content = _content.substr(start, end - start + 1);
00635                 }
00636                 // проверяем соответствие открывающего и закрывающего тегов
00637                 if (_currentNode->getName() != _content)
00638                 {
00639                     mLastError = ErrorType::InconsistentOpenCloseElements;
00640                     return false;
00641                 }
00642                 // а теперь снижаем текущий узел вниз
00643                 _currentNode = _currentNode->getParent();
00644             }
00645             else
00646             {
00647                 // выделяем имя до первого пробела или закрывающего тега
00648                 std::string cut = _content;
00649                 start = _content.find_first_of(" \t/?", 1); // << превед
00650                 if (start != _content.npos)
00651                 {
00652                     cut = _content.substr(0, start);
00653                     _content = _content.substr(start);
00654                 }
00655                 else
00656                 {
00657                     _content.clear();
00658                 }
00659 
00660                 if (_currentNode)
00661                 {
00662                     _currentNode = _currentNode->createChild(cut);
00663                 }
00664                 else
00665                 {
00666                     if (tagDeclaration)
00667                     {
00668                         // информационный тег
00669                         if (mDeclaration)
00670                         {
00671                             mLastError = ErrorType::MoreThanOneXMLDeclaration;
00672                             return false;
00673                         }
00674                         _currentNode = new Element(cut, 0, ElementType::Declaration);
00675                         mDeclaration = _currentNode;
00676                     }
00677                     else
00678                     {
00679                         // рутовый тег
00680                         if (mRoot)
00681                         {
00682                             mLastError = ErrorType::MoreThanOneRootElement;
00683                             return false;
00684                         }
00685                         _currentNode = new Element(cut, 0, ElementType::Normal);
00686                         mRoot = _currentNode;
00687                     }
00688                 }
00689 
00690                 // проверим на пустоту
00691                 start = _content.find_last_not_of(" \t");
00692                 if (start == _content.npos)
00693                     return true;
00694 
00695                 // сразу отделим закрывающийся тэг
00696                 bool close = false;
00697                 if ((_content[start] == '/') || (_content[start] == '?'))
00698                 {
00699                     close = true;
00700                     // не будем резать строку, просто поставим пробел
00701                     _content[start] = ' ';
00702                     // проверим на пустоту
00703                     start = _content.find_last_not_of(" \t");
00704                     if (start == _content.npos)
00705                     {
00706                         // возвращаем все назад и уходим
00707                         _currentNode = _currentNode->getParent();
00708                         return true;
00709                     }
00710                 }
00711 
00712                 // а вот здесь уже в цикле разбиваем на атрибуты
00713                 while (true)
00714                 {
00715                     // ищем равно
00716                     start = _content.find('=');
00717                     if (start == _content.npos)
00718                     {
00719                         mLastError = ErrorType::IncorrectAttribute;
00720                         return false;
00721                     }
00722                     // ищем вторые ковычки
00723                     end = _content.find_first_of("\"\'", start + 1);
00724                     if (end == _content.npos)
00725                     {
00726                         mLastError = ErrorType::IncorrectAttribute;
00727                         return false;
00728                     }
00729                     end = _content.find_first_of("\"\'", end + 1);
00730                     if (end == _content.npos)
00731                     {
00732                         mLastError = ErrorType::IncorrectAttribute;
00733                         return false;
00734                     }
00735 
00736                     std::string key = _content.substr(0, start);
00737                     std::string value = _content.substr(start + 1, end - start);
00738 
00739                     // проверка на валидность
00740                     if (! checkPair(key, value))
00741                     {
00742                         mLastError = ErrorType::IncorrectAttribute;
00743                         return false;
00744                     }
00745 
00746                     // добавляем пару в узел
00747                     _currentNode->addAttribute(key, value);
00748 
00749                     // следующий кусок
00750                     _content = _content.substr(end + 1);
00751 
00752                     // в строке не осталось символов
00753                     start = _content.find_first_not_of(" \t");
00754                     if (start == _content.npos)
00755                         break;
00756 
00757                     mCol += start;
00758                 }
00759 
00760                 // был закрывающий тег для текущего тега
00761                 if (close)
00762                 {
00763                     // не проверяем имена, потому что это наш тэг
00764                     _currentNode = _currentNode->getParent();
00765                 }
00766 
00767             }
00768             return true;
00769         }
00770 
00771         bool Document::checkPair(std::string& _key, std::string& _value)
00772         {
00773             // в ключе не должно быть ковычек и пробелов
00774             MyGUI::utility::trim(_key);
00775             if (_key.empty())
00776                 return false;
00777             size_t start = _key.find_first_of(" \t\"\'&");
00778             if (start != _key.npos)
00779                 return false;
00780 
00781             // в значении, ковычки по бокам
00782             MyGUI::utility::trim(_value);
00783             if (_value.size() < 2)
00784                 return false;
00785             if (((_value[0] != '"') || (_value[_value.length() - 1] != '"')) &&
00786                 ((_value[0] != '\'') || (_value[_value.length() - 1] != '\'')))
00787                 return false;
00788             bool ok = true;
00789             _value = utility::convert_from_xml(_value.substr(1, _value.length() - 2), ok);
00790             return ok;
00791         }
00792 
00793         // ищет символ без учета ковычек
00794         size_t Document::find(const std::string& _text, char _char, size_t _start)
00795         {
00796             // ковычки
00797             bool kov = false;
00798 
00799             // буфер для поиска
00800             char buff[16] = "\"_\0";
00801             buff[1] = _char;
00802 
00803             size_t pos = _start;
00804 
00805             while (true)
00806             {
00807                 pos = _text.find_first_of(buff, pos);
00808 
00809                 // если уже конец, то досвидания
00810                 if (pos == _text.npos)
00811                 {
00812                     break;
00813                 }
00814                 // нашли ковычку
00815                 else if (_text[pos] == '"')
00816                 {
00817                     kov = !kov;
00818                     pos ++;
00819                 }
00820                 // если мы в ковычках, то идем дальше
00821                 else if (kov)
00822                 {
00823                     pos ++;
00824                 }
00825                 // мы не в ковычках
00826                 else
00827                 {
00828                     break;
00829                 }
00830             }
00831 
00832             return pos;
00833         }
00834 
00835         void Document::clearDeclaration()
00836         {
00837             if (mDeclaration)
00838             {
00839                 delete mDeclaration;
00840                 mDeclaration = 0;
00841             }
00842         }
00843 
00844         void Document::clearRoot()
00845         {
00846             if (mRoot)
00847             {
00848                 delete mRoot;
00849                 mRoot = 0;
00850             }
00851         }
00852 
00853         ElementPtr Document::createDeclaration(const std::string& _version, const std::string& _encoding)
00854         {
00855             clearDeclaration();
00856             mDeclaration = new Element("xml", 0, ElementType::Declaration);
00857             mDeclaration->addAttribute("version", _version);
00858             mDeclaration->addAttribute("encoding", _encoding);
00859             return mDeclaration;
00860         }
00861 
00862         ElementPtr Document::createRoot(const std::string& _name)
00863         {
00864             clearRoot();
00865             mRoot = new Element(_name, 0, ElementType::Normal);
00866             return mRoot;
00867         }
00868 
00869         bool Document::parseLine(std::string& _line, ElementPtr& _element)
00870         {
00871             // крутимся пока в строке есть теги
00872             while (true)
00873             {
00874                 // сначала ищем по угловым скобкам
00875                 size_t start = find(_line, '<');
00876                 if (start == _line.npos)
00877                     break;
00878                 size_t end = _line.npos;
00879 
00880                 // пытаемся вырезать многострочный коментарий
00881                 if ((start + 3 < _line.size()) && (_line[start + 1] == '!') && (_line[start + 2] == '-') && (_line[start + 3] == '-'))
00882                 {
00883                     end = _line.find("-->", start + 4);
00884                     if (end == _line.npos)
00885                         break;
00886                     end += 2;
00887                 }
00888                 else
00889                 {
00890                     end = find(_line, '>', start + 1);
00891                     if (end == _line.npos)
00892                         break;
00893                 }
00894                 // проверяем на наличее тела
00895                 size_t body = _line.find_first_not_of(" \t<");
00896                 if (body < start)
00897                 {
00898                     std::string body_str = _line.substr(0, start);
00899                     // текущий символ
00900                     mCol = 0;
00901 
00902                     if (_element != 0)
00903                     {
00904                         bool ok = true;
00905                         _element->setContent(utility::convert_from_xml(body_str, ok));
00906                         if (!ok)
00907                         {
00908                             mLastError = ErrorType::IncorrectContent;
00909                             return false;
00910                         }
00911                     }
00912                 }
00913                 // вырезаем наш тэг и парсим
00914                 if (!parseTag(_element, _line.substr(start + 1, end - start - 1)))
00915                 {
00916                     return false;
00917                 }
00918                 // и обрезаем текущую строку разбора
00919                 _line = _line.substr(end + 1);
00920             }
00921             return true;
00922         }
00923 
00924         std::string Document::getLastError()
00925         {
00926             const std::string& error = mLastError.print();
00927             if (error.empty())
00928                 return error;
00929             return MyGUI::utility::toString("'", error, "' ,  file='", mLastErrorFile, "' ,  line=", mLine, " ,  col=", mCol);
00930         }
00931 
00932         bool Document::open(const UString& _filename)
00933         {
00934             return open(_filename.asWStr());
00935         }
00936 
00937         bool Document::save(const UString& _filename)
00938         {
00939             return save(_filename.asWStr());
00940         }
00941 
00942         void Document::clearLastError()
00943         {
00944             mLastError = ErrorType::MAX;
00945         }
00946 
00947         ElementPtr Document::getRoot() const
00948         {
00949             return mRoot;
00950         }
00951 
00952         void Document::setLastFileError(const std::string& _filename)
00953         {
00954             mLastErrorFile = _filename;
00955         }
00956 
00957         void Document::setLastFileError(const std::wstring& _filename)
00958         {
00959             mLastErrorFile = UString(_filename).asUTF8();
00960         }
00961 
00962     } // namespace xml
00963 
00964 } // namespace MyGUI