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