MyGUI
3.2.0
|
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 == "&") ret += '&'; 00057 else if (tag == "<") ret += '<'; 00058 else if (tag == ">") ret += '>'; 00059 else if (tag == "'") ret += '\''; 00060 else if (tag == """) 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 += "&"; 00090 else if (_string[pos] == '<') ret += "<"; 00091 else if (_string[pos] == '>') ret += ">"; 00092 else if (_string[pos] == '\'') ret += "'"; 00093 else if (_string[pos] == '\"') ret += """; 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