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