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