diff --git a/uppsrc/Core/XML.cpp b/uppsrc/Core/XML.cpp index 69845ad39..98955fbf5 100644 --- a/uppsrc/Core/XML.cpp +++ b/uppsrc/Core/XML.cpp @@ -2,7 +2,7 @@ NAMESPACE_UPP -#define LLOG(x) // LOG(x); +#define LLOG(x) // LOG(x) static inline void sDeXmlChar(StringBuffer& result, char chr, byte charset, bool escapelf) { @@ -208,13 +208,14 @@ inline static bool IsXmlNameChar(int c) } void XmlParser::LoadMore0() -{ - if(in) { +{ // WARNING: Invalidates pointers to buffer + if(in && !in->IsEof()) { int pos = int(term - begin); if(len - pos < MCHARS) { + LLOG("LoadMore0 " << pos << ", " << len); begincolumn = GetColumn0(); len -= pos; - memcpy(buffer, term, len); + memmove(buffer, term, len); term = begin = buffer; len += in->Get(~buffer + len, CHUNK); buffer[len] = '\0'; @@ -223,10 +224,11 @@ void XmlParser::LoadMore0() } bool XmlParser::More() -{ +{ // WARNING: Invalidates pointers to buffer begincolumn = GetColumn(); - if(!in) + if(!in || in->IsEof()) return false; + LLOG("More " << (int)CHUNK); len = in->Get(buffer, CHUNK); buffer[len] = '\0'; term = begin = buffer; @@ -262,6 +264,7 @@ void XmlParser::Next() if(empty_tag) { empty_tag = false; type = XML_END; + LLOG("XML_END (empty tag) " << tagtext); return; } @@ -270,6 +273,7 @@ void XmlParser::Next() for(;;) { if(!HasMore()) { type = XML_EOF; + LLOG("XML_EOF"); return; } LoadMore(); @@ -312,8 +316,10 @@ void XmlParser::Next() if(cdata.GetCount() && (npreserve || preserveall)) type = XML_TEXT; - if(type == XML_TEXT) + if(type == XML_TEXT) { + LLOG("XML_TEXT " << cdata); return; + } term++; LoadMore(); @@ -355,6 +361,7 @@ void XmlParser::Next() line++; tagtext.Cat(*term++); } + LLOG("XML_DECL " << tagtext); } else if(*term == '?') { @@ -372,6 +379,7 @@ void XmlParser::Next() line++; tagtext.Cat(*term++); } + LLOG("XML_PI " << tagtext); } else if(*term == '/') { @@ -381,6 +389,7 @@ void XmlParser::Next() while(IsXmlNameChar(*term)) term++; tagtext = String(t, term); + LLOG("XML_END " << tagtext); if(*term != '>') throw XmlError("Unterminated end-tag"); term++; @@ -388,9 +397,10 @@ void XmlParser::Next() else { type = XML_TAG; const char *t = term; - while(HasMore() && IsXmlNameChar(*term)) + while(IsXmlNameChar(*term)) term++; tagtext = String(t, term); + LLOG("XML_TAG " << tagtext); for(;;) { SkipWhites(); if(*term == '>') { @@ -405,8 +415,9 @@ void XmlParser::Next() } if(!HasMore()) throw XmlError("Unterminated tag"); + LoadMore(); const char *t = term++; - while(HasMore() && (byte)*term > ' ' && *term != '=' && *term != '>') + while((byte)*term > ' ' && *term != '=' && *term != '>') term++; String attr(t, term); SkipWhites(); @@ -458,7 +469,7 @@ String XmlParser::ReadTag(bool next) { if(type != XML_TAG) throw XmlError("Expected tag"); - LLOG("ReadTag " << text); + LLOG("ReadTag " << tagtext); String h = tagtext; if(next) { stack.Add(Nesting(h, npreserve)); @@ -520,7 +531,7 @@ bool XmlParser::End() if(IsEof()) throw XmlError("Unexpected end of file"); if(IsEnd()) { - LLOG("EndTag " << text); + LLOG("EndTag " << tagtext); if(stack.IsEmpty()) throw XmlError(NFormat("Unexpected end-tag: ", tagtext)); if(stack.Top().tag != tagtext && !relaxed) { @@ -847,6 +858,17 @@ void XmlNode::Shrink() node.Shrink(); } +XmlNode::XmlNode(const XmlNode& n, int) +{ + type = n.type; + text = n.text; + node <<= n.node; + if(n.attr) { + attr.Create(); + *attr <<= *n.attr; + } +} + bool Ignore(XmlParser& p, dword style) { if((XML_IGNORE_DECLS & style) && p.IsDecl() || @@ -891,6 +913,8 @@ static XmlNode sReadXmlNode(XmlParser& p, ParseXmlFilter *filter, dword style) m.CreateComment(p.ReadComment()); return m; } + if(!p.IsText()) + throw XmlError("Invalid XML."); m.CreateText(p.ReadText()); m.Shrink(); return m; @@ -972,55 +996,6 @@ bool ShouldPreserve(const String& s) return false; } -/* -String AsXML(const XmlNode& node, dword style) -{ - StringBuffer r; - if(style & XML_HEADER) - r << XmlHeader(); - if(style & XML_DOCTYPE) - for(int i = 0; i < node.GetCount(); i++) { - const XmlNode& m = node.Node(i); - if(m.GetType() == XML_TAG) { - r << XmlDocType(m.GetText()); - break; - } - } - style &= ~(XML_HEADER|XML_DOCTYPE); - switch(node.GetType()) { - case XML_PI: - r << "\r\n"; - break; - case XML_DECL: - r << "\r\n"; - break; - case XML_COMMENT: - r << "\r\n"; - break; - case XML_DOC: - for(int i = 0; i < node.GetCount(); i++) - r << AsXML(node.Node(i), style); - break; - case XML_TEXT: - r << DeXml(node.GetText()); - break; - case XML_TAG: - XmlTag tag(node.GetText()); - for(int i = 0; i < node.GetAttrCount(); i++) - tag(node.AttrId(i), node.Attr(i)); - if(node.GetCount()) { - StringBuffer body; - for(int i = 0; i < node.GetCount(); i++) - body << AsXML(node.Node(i), style); - r << tag(~body); - } - else - r << tag(); - } - return r; -} -*/ - static void sAsXML(Stream& out, const XmlNode& node, dword style, const String& indent) { if(style & XML_HEADER) { diff --git a/uppsrc/Core/XML.h b/uppsrc/Core/XML.h index ed1b1b0a8..afd7bcbd2 100644 --- a/uppsrc/Core/XML.h +++ b/uppsrc/Core/XML.h @@ -160,7 +160,7 @@ public: XmlParser(Stream& in); }; -class XmlNode { +class XmlNode : Moveable< XmlNode, DeepCopyOption > { int type; String text; Array node; @@ -215,8 +215,12 @@ public: void SetAttrsPick(pick_ VectorMap& a); void Shrink(); + + bool IsPicked() const { return node.IsPicked(); } - XmlNode() { type = XML_DOC; } + XmlNode(const XmlNode& n, int); + + XmlNode() { type = XML_DOC; } }; enum { diff --git a/uppsrc/Core/src.tpp/XmlNode$en-us.tpp b/uppsrc/Core/src.tpp/XmlNode$en-us.tpp index 18aa46637..f2f75e5ec 100644 --- a/uppsrc/Core/src.tpp/XmlNode$en-us.tpp +++ b/uppsrc/Core/src.tpp/XmlNode$en-us.tpp @@ -18,6 +18,9 @@ structure `- each XmlNode can contain any number of child XmlNodes. XmlNode is mutable and U`+`+ provides function to parse XML and store it to XmlNode and also to take XmlNode and create corresponding XML document.&] +[s9;%% XmlNode is [*/^topic`:`/`/Core`/srcdoc`/Moveable`$en`-us^ moveable][*/ +]type with [*/^topic`:`/`/Core`/srcdoc`/pick`_`$en`-us^ pick and +optional deep copy] transfer semantics&] [s3; &] [s0; &] [ {{10000F(128)G(128)@1 [s0;%% [* Public Member List]]}}&] @@ -223,16 +226,28 @@ r]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) int]_[*@3 val])& [s2;%% Replaces all attributes to [%-*@3 a] using pick operation ([%-*@3 a] is destroyed in operation).&] [s3; &] +[s4; &] +[s5;:XmlNode`:`:Shrink`(`): [@(0.0.255) void]_[* Shrink]()&] +[s2;%% Attempts to minimize memory footprint.&] +[s3; &] +[s4; &] +[s5;:XmlNode`:`:IsPicked`(`)const: [@(0.0.255) bool]_[* IsPicked]()_[@(0.0.255) const]&] +[s2;%% Returns true if picked&] [s0; &] [ {{10000F(128)G(128)@1 [s0;%% [* Constructor detail]]}}&] [s3;%% &] [s0; [* XmlNode]()&] [s2;%% Construct an empty XmlNode.&] [s3; &] -[s0; &] +[s4; &] +[s5;:XmlNode`:`:XmlNode`(const XmlNode`&`,int`): [* XmlNode]([@(0.0.255) const]_[* XmlNode][@(0.0.255) `& +]_[*@3 n], [@(0.0.255) int])&] +[s2;%% Deep copy constructor.&] +[s3;%% &] [s0; &] [s0; &] [ {{10000@(113.42.0) [s0;%% [*@7;4 XmlNode `- parse and output functions]]}}&] +[s3;%% &] [s4;H0; &] [s5;:ParseXML`(XmlParser`&`,dword`): [_^XmlNode^ XmlNode]_[* ParseXML]([_^XmlParser^ XmlPar ser][@(0.0.255) `&]_[*@3 p], [_^dword^ dword]_[*@3 style]_`=_XML`_IGNORE`_DECLS[@(0.0.255) `|