MyGUI
3.2.1
|
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 == "<") ret += '<'; 00043 else if (tag == ">") ret += '>'; 00044 else if (tag == "'") ret += '\''; 00045 else if (tag == """) 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 += "&"; 00075 else if (_string[pos] == '<') ret += "<"; 00076 else if (_string[pos] == '>') ret += ">"; 00077 else if (_string[pos] == '\'') ret += "'"; 00078 else if (_string[pos] == '\"') ret += """; 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