diff options
Diffstat (limited to 'kopete/protocols/jabber/jingle/libjingle/talk/xmllite')
15 files changed, 2214 insertions, 0 deletions
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/Makefile.am new file mode 100644 index 00000000..1e7abcfd --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/Makefile.am @@ -0,0 +1,18 @@ +libcricketxmllite_la_SOURCES = qname.cc \ + xmlbuilder.cc \ + xmlconstants.cc \ + xmlelement.cc \ + xmlnsstack.cc \ + xmlparser.cc \ + xmlprinter.cc + +noinst_HEADERS = qname.h \ + xmlbuilder.h \ + xmlconstants.h \ + xmlelement.h \ + xmlnsstack.h \ + xmlparser.h \ + xmlprinter.h +AM_CPPFLAGS = -DPOSIX -I$(srcdir)/../.. + +noinst_LTLIBRARIES = libcricketxmllite.la diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.cc new file mode 100644 index 00000000..626cfa96 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.cc @@ -0,0 +1,167 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> +#include "talk/base/common.h" +#include "talk/xmllite/xmlelement.h" +#include "talk/xmllite/qname.h" +#include "talk/xmllite/xmlconstants.h" + +//#define new TRACK_NEW + +namespace buzz { + +static int QName_Hash(const std::string & ns, const char * local) { + int result = ns.size() * 101; + while (*local) { + result *= 19; + result += *local; + local += 1; + } + return result; +} + +static const int bits = 9; +static QName::Data * get_qname_table() { + static QName::Data qname_table[1 << bits]; + return qname_table; +} + +static QName::Data * +AllocateOrFind(const std::string & ns, const char * local) { + int index = QName_Hash(ns, local); + int increment = index >> (bits - 1) | 1; + QName::Data * qname_table = get_qname_table(); + for (;;) { + index &= ((1 << bits) - 1); + if (!qname_table[index].Occupied()) { + return new QName::Data(ns, local); + } + if (qname_table[index].localPart_ == local && + qname_table[index].namespace_ == ns) { + qname_table[index].AddRef(); + return qname_table + index; + } + index += increment; + } +} + +static QName::Data * +Add(const std::string & ns, const char * local) { + int index = QName_Hash(ns, local); + int increment = index >> (bits - 1) | 1; + QName::Data * qname_table = get_qname_table(); + for (;;) { + index &= ((1 << bits) - 1); + if (!qname_table[index].Occupied()) { + qname_table[index].namespace_ = ns; + qname_table[index].localPart_ = local; + qname_table[index].AddRef(); // AddRef twice so it's never deleted + qname_table[index].AddRef(); + return qname_table + index; + } + if (qname_table[index].localPart_ == local && + qname_table[index].namespace_ == ns) { + qname_table[index].AddRef(); + return qname_table + index; + } + index += increment; + } +} + +QName::~QName() { + data_->Release(); +} + +QName::QName() : data_(QN_EMPTY.data_) { + data_->AddRef(); +} + +QName::QName(bool add, const std::string & ns, const char * local) : + data_(add ? Add(ns, local) : AllocateOrFind(ns, local)) {} + +QName::QName(bool add, const std::string & ns, const std::string & local) : + data_(add ? Add(ns, local.c_str()) : AllocateOrFind(ns, local.c_str())) {} + +QName::QName(const std::string & ns, const char * local) : + data_(AllocateOrFind(ns, local)) {} + +static std::string +QName_LocalPart(const std::string & name) { + size_t i = name.rfind(':'); + if (i == std::string::npos) + return name; + return name.substr(i + 1); +} + +static std::string +QName_Namespace(const std::string & name) { + size_t i = name.rfind(':'); + if (i == std::string::npos) + return STR_EMPTY; + return name.substr(0, i); +} + +QName::QName(const std::string & mergedOrLocal) : + data_(AllocateOrFind(QName_Namespace(mergedOrLocal), + QName_LocalPart(mergedOrLocal).c_str())) {} + +std::string +QName::Merged() const { + if (data_->namespace_ == STR_EMPTY) + return data_->localPart_; + + std::string result(data_->namespace_); + result.reserve(result.length() + 1 + data_->localPart_.length()); + result += ':'; + result += data_->localPart_; + return result; +} + +bool +QName::operator==(const QName & other) const { + return other.data_ == data_ || + data_->localPart_ == other.data_->localPart_ && + data_->namespace_ == other.data_->namespace_; +} + +int +QName::Compare(const QName & other) const { + if (data_ == other.data_) + return 0; + + int result = data_->localPart_.compare(other.data_->localPart_); + if (result) + return result; + + return data_->namespace_.compare(other.data_->namespace_); +} + +} + + + diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.h new file mode 100644 index 00000000..b1bcec61 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/qname.h @@ -0,0 +1,87 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _qname_h_ +#define _qname_h_ + +#include <string> + +namespace buzz { + + +class QName +{ +public: + explicit QName(); + QName(const QName & qname) : data_(qname.data_) { data_->AddRef(); } + explicit QName(bool add, const std::string & ns, const char * local); + explicit QName(bool add, const std::string & ns, const std::string & local); + explicit QName(const std::string & ns, const char * local); + explicit QName(const std::string & mergedOrLocal); + QName & operator=(const QName & qn) { + qn.data_->AddRef(); + data_->Release(); + data_ = qn.data_; + return *this; + } + ~QName(); + + const std::string & Namespace() const { return data_->namespace_; } + const std::string & LocalPart() const { return data_->localPart_; } + std::string Merged() const; + int Compare(const QName & other) const; + bool operator==(const QName & other) const; + bool operator!=(const QName & other) const { return !operator==(other); } + bool operator<(const QName & other) const { return Compare(other) < 0; } + + class Data { + public: + Data(const std::string & ns, const std::string & local) : + refcount_(1), + namespace_(ns), + localPart_(local) {} + + Data() : refcount_(0) {} + + std::string namespace_; + std::string localPart_; + void AddRef() { refcount_++; } + void Release() { if (!--refcount_) { delete this; } } + bool Occupied() { return !!refcount_; } + + private: + int refcount_; + }; + +private: + Data * data_; +}; + + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.cc new file mode 100644 index 00000000..313c4013 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.cc @@ -0,0 +1,151 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/stl_decl.h" +#include <vector> +#include <set> +#include <expat.h> +#include "talk/base/common.h" +#include "talk/xmllite/xmlelement.h" +#include "talk/xmllite/xmlbuilder.h" + +#define new TRACK_NEW + +namespace buzz { + +XmlBuilder::XmlBuilder() : + pelCurrent_(NULL), + pelRoot_(NULL), + pvParents_(new std::vector<XmlElement *>()) { +} + +void +XmlBuilder::Reset() { + pelRoot_.reset(); + pelCurrent_ = NULL; + pvParents_->clear(); +} + +XmlElement * +XmlBuilder::BuildElement(XmlParseContext * pctx, + const char * name, const char ** atts) { + QName tagName(pctx->ResolveQName(name, false)); + if (tagName == QN_EMPTY) + return NULL; + + XmlElement * pelNew = new XmlElement(tagName); + + if (!*atts) + return pelNew; + + std::set<QName> seenNonlocalAtts; + + while (*atts) { + QName attName(pctx->ResolveQName(*atts, true)); + if (attName == QN_EMPTY) { + delete pelNew; + return NULL; + } + + // verify that namespaced names are unique + if (!attName.Namespace().empty()) { + if (seenNonlocalAtts.count(attName)) { + delete pelNew; + return NULL; + } + seenNonlocalAtts.insert(attName); + } + + pelNew->AddAttr(attName, std::string(*(atts + 1))); + atts += 2; + } + + return pelNew; +} + +void +XmlBuilder::StartElement(XmlParseContext * pctx, + const char * name, const char ** atts) { + XmlElement * pelNew = BuildElement(pctx, name, atts); + if (pelNew == NULL) { + pctx->RaiseError(XML_ERROR_SYNTAX); + return; + } + + if (!pelCurrent_) { + pelCurrent_ = pelNew; + pelRoot_.reset(pelNew); + pvParents_->push_back(NULL); + } else { + pelCurrent_->AddElement(pelNew); + pvParents_->push_back(pelCurrent_); + pelCurrent_ = pelNew; + } +} + +void +XmlBuilder::EndElement(XmlParseContext * pctx, const char * name) { + UNUSED(pctx); + UNUSED(name); + pelCurrent_ = pvParents_->back(); + pvParents_->pop_back(); +} + +void +XmlBuilder::CharacterData(XmlParseContext * pctx, + const char * text, int len) { + UNUSED(pctx); + if (pelCurrent_) { + pelCurrent_->AddParsedText(text, len); + } +} + +void +XmlBuilder::Error(XmlParseContext * pctx, XML_Error err) { + UNUSED(pctx); + UNUSED(err); + pelRoot_.reset(NULL); + pelCurrent_ = NULL; + pvParents_->clear(); +} + +XmlElement * +XmlBuilder::CreateElement() { + return pelRoot_.release(); +} + +XmlElement * +XmlBuilder::BuiltElement() { + return pelRoot_.get(); +} + +XmlBuilder::~XmlBuilder() { +} + + + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.h new file mode 100644 index 00000000..b5b1be59 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlbuilder.h @@ -0,0 +1,79 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xmlbuilder_h_ +#define _xmlbuilder_h_ + +#include <string> +#include "talk/base/scoped_ptr.h" +#include "talk/base/stl_decl.h" +#include "talk/xmllite/xmlparser.h" + +#ifdef OSX +#include "talk/third_party/expat/expat.h" +#else +#include <expat.h> +#endif + +namespace buzz { + +class XmlElement; +class XmlParseContext; + + +class XmlBuilder : public XmlParseHandler { +public: + XmlBuilder(); + + static XmlElement * BuildElement(XmlParseContext * pctx, + const char * name, const char ** atts); + virtual void StartElement(XmlParseContext * pctx, + const char * name, const char ** atts); + virtual void EndElement(XmlParseContext * pctx, const char * name); + virtual void CharacterData(XmlParseContext * pctx, + const char * text, int len); + virtual void Error(XmlParseContext * pctx, XML_Error); + virtual ~XmlBuilder(); + + void Reset(); + + // Take ownership of the built element; second call returns NULL + XmlElement * CreateElement(); + + // Peek at the built element without taking ownership + XmlElement * BuiltElement(); + +private: + XmlElement * pelCurrent_; + scoped_ptr<XmlElement> pelRoot_; + scoped_ptr<std::vector<XmlElement *, std::allocator<XmlElement *> > > + pvParents_; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.cc new file mode 100644 index 00000000..503f832f --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.cc @@ -0,0 +1,65 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "xmlconstants.h" + +using namespace buzz; + +const std::string & XmlConstants::str_empty() { + static const std::string str_empty_; + return str_empty_; +} + +const std::string & XmlConstants::ns_xml() { + static const std::string ns_xml_("http://www.w3.org/XML/1998/namespace"); + return ns_xml_; +} + +const std::string & XmlConstants::ns_xmlns() { + static const std::string ns_xmlns_("http://www.w3.org/2000/xmlns/"); + return ns_xmlns_; +} + +const std::string & XmlConstants::str_xmlns() { + static const std::string str_xmlns_("xmlns"); + return str_xmlns_; +} + +const std::string & XmlConstants::str_xml() { + static const std::string str_xml_("xml"); + return str_xml_; +} + +const std::string & XmlConstants::str_version() { + static const std::string str_version_("version"); + return str_version_; +} + +const std::string & XmlConstants::str_encoding() { + static const std::string str_encoding_("encoding"); + return str_encoding_; +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.h new file mode 100644 index 00000000..8514d6f4 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlconstants.h @@ -0,0 +1,61 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// Because global constant initialization order is undefined +// globals cannot depend on other objects to be instantiated. +// This class creates string objects within static methods +// such that globals may refer to these constants by the +// accessor function and they are guaranteed to be initialized. + +#ifndef TALK_XMLLITE_CONSTANTS_H_ +#define TALK_XMLLITE_CONSTANTS_H_ + +#include <string> + +#define STR_EMPTY XmlConstants::str_empty() +#define NS_XML XmlConstants::ns_xml() +#define NS_XMLNS XmlConstants::ns_xmlns() +#define STR_XMLNS XmlConstants::str_xmlns() +#define STR_XML XmlConstants::str_xml() +#define STR_VERSION XmlConstants::str_version() +#define STR_ENCODING XmlConstants::str_encoding() +namespace buzz { + +class XmlConstants { + public: + static const std::string & str_empty(); + static const std::string & ns_xml(); + static const std::string & ns_xmlns(); + static const std::string & str_xmlns(); + static const std::string & str_xml(); + static const std::string & str_version(); + static const std::string & str_encoding(); +}; + +} + +#endif // TALK_XMLLITE_CONSTANTS_H_ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.cc new file mode 100644 index 00000000..d3619a92 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.cc @@ -0,0 +1,491 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> +#include <iostream> +#include <vector> +#include <sstream> + +#include "talk/base/common.h" +#include "talk/xmllite/xmlelement.h" +#include "talk/xmllite/qname.h" +#include "talk/xmllite/xmlparser.h" +#include "talk/xmllite/xmlbuilder.h" +#include "talk/xmllite/xmlprinter.h" +#include "talk/xmllite/xmlconstants.h" + +#define new TRACK_NEW + +namespace buzz { + +const QName QN_EMPTY(true, STR_EMPTY, STR_EMPTY); +const QName QN_XMLNS(true, STR_EMPTY, STR_XMLNS); + + +XmlChild::~XmlChild() { +} + +bool +XmlText::IsTextImpl() const { + return true; +} + +XmlElement * +XmlText::AsElementImpl() const { + return NULL; +} + +XmlText * +XmlText::AsTextImpl() const { + return const_cast<XmlText *>(this); +} + +void +XmlText::SetText(const std::string & text) { + text_ = text; +} + +void +XmlText::AddParsedText(const char * buf, int len) { + text_.append(buf, len); +} + +void +XmlText::AddText(const std::string & text) { + text_ += text; +} + +XmlText::~XmlText() { +} + +XmlElement::XmlElement(const QName & name) : + name_(name), + pFirstAttr_(NULL), + pLastAttr_(NULL), + pFirstChild_(NULL), + pLastChild_(NULL) { +} + +XmlElement::XmlElement(const XmlElement & elt) : + XmlChild(), + name_(elt.name_), + pFirstAttr_(NULL), + pLastAttr_(NULL), + pFirstChild_(NULL), + pLastChild_(NULL) { + + // copy attributes + XmlAttr * pAttr; + XmlAttr ** ppLastAttr = &pFirstAttr_; + XmlAttr * newAttr = NULL; + for (pAttr = elt.pFirstAttr_; pAttr; pAttr = pAttr->NextAttr()) { + newAttr = new XmlAttr(*pAttr); + *ppLastAttr = newAttr; + ppLastAttr = &(newAttr->pNextAttr_); + } + pLastAttr_ = newAttr; + + // copy children + XmlChild * pChild; + XmlChild ** ppLast = &pFirstChild_; + XmlChild * newChild = NULL; + + for (pChild = elt.pFirstChild_; pChild; pChild = pChild->NextChild()) { + if (pChild->IsText()) { + newChild = new XmlText(*(pChild->AsText())); + } else { + newChild = new XmlElement(*(pChild->AsElement())); + } + *ppLast = newChild; + ppLast = &(newChild->pNextChild_); + } + pLastChild_ = newChild; + +} + +XmlElement::XmlElement(const QName & name, bool useDefaultNs) : + name_(name), + pFirstAttr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL), + pLastAttr_(pFirstAttr_), + pFirstChild_(NULL), + pLastChild_(NULL) { +} + +bool +XmlElement::IsTextImpl() const { + return false; +} + +XmlElement * +XmlElement::AsElementImpl() const { + return const_cast<XmlElement *>(this); +} + +XmlText * +XmlElement::AsTextImpl() const { + return NULL; +} + +const std::string & +XmlElement::BodyText() const { + if (pFirstChild_ && pFirstChild_->IsText() && pLastChild_ == pFirstChild_) { + return pFirstChild_->AsText()->Text(); + } + + return STR_EMPTY; +} + +void +XmlElement::SetBodyText(const std::string & text) { + if (text == STR_EMPTY) { + ClearChildren(); + } else if (pFirstChild_ == NULL) { + AddText(text); + } else if (pFirstChild_->IsText() && pLastChild_ == pFirstChild_) { + pFirstChild_->AsText()->SetText(text); + } else { + ClearChildren(); + AddText(text); + } +} + +const QName & +XmlElement::FirstElementName() const { + const XmlElement * element = FirstElement(); + if (element == NULL) + return QN_EMPTY; + return element->Name(); +} + +XmlAttr * +XmlElement::FirstAttr() { + return pFirstAttr_; +} + +const std::string & +XmlElement::Attr(const QName & name) const { + XmlAttr * pattr; + for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) { + if (pattr->name_ == name) + return pattr->value_; + } + return STR_EMPTY; +} + +bool +XmlElement::HasAttr(const QName & name) const { + XmlAttr * pattr; + for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) { + if (pattr->name_ == name) + return true; + } + return false; +} + +void +XmlElement::SetAttr(const QName & name, const std::string & value) { + XmlAttr * pattr; + for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) { + if (pattr->name_ == name) + break; + } + if (!pattr) { + pattr = new XmlAttr(name, value); + if (pLastAttr_) + pLastAttr_->pNextAttr_ = pattr; + else + pFirstAttr_ = pattr; + pLastAttr_ = pattr; + return; + } + pattr->value_ = value; +} + +void +XmlElement::ClearAttr(const QName & name) { + XmlAttr * pattr; + XmlAttr *pLastAttr = NULL; + for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) { + if (pattr->name_ == name) + break; + pLastAttr = pattr; + } + if (!pattr) + return; + if (!pLastAttr) + pFirstAttr_ = pattr->pNextAttr_; + else + pLastAttr->pNextAttr_ = pattr->pNextAttr_; + if (pLastAttr_ == pattr) + pLastAttr_ = pLastAttr; + delete pattr; +} + +XmlChild * +XmlElement::FirstChild() { + return pFirstChild_; +} + +XmlElement * +XmlElement::FirstElement() { + XmlChild * pChild; + for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) { + if (!pChild->IsText()) + return pChild->AsElement(); + } + return NULL; +} + +XmlElement * +XmlElement::NextElement() { + XmlChild * pChild; + for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) { + if (!pChild->IsText()) + return pChild->AsElement(); + } + return NULL; +} + +XmlElement * +XmlElement::FirstWithNamespace(const std::string & ns) { + XmlChild * pChild; + for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) { + if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns) + return pChild->AsElement(); + } + return NULL; +} + +XmlElement * +XmlElement::NextWithNamespace(const std::string & ns) { + XmlChild * pChild; + for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) { + if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns) + return pChild->AsElement(); + } + return NULL; +} + +XmlElement * +XmlElement::FirstNamed(const QName & name) { + XmlChild * pChild; + for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) { + if (!pChild->IsText() && pChild->AsElement()->Name() == name) + return pChild->AsElement(); + } + return NULL; +} + +XmlElement * +XmlElement::NextNamed(const QName & name) { + XmlChild * pChild; + for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) { + if (!pChild->IsText() && pChild->AsElement()->Name() == name) + return pChild->AsElement(); + } + return NULL; +} + +const std::string & +XmlElement::TextNamed(const QName & name) const { + XmlChild * pChild; + for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) { + if (!pChild->IsText() && pChild->AsElement()->Name() == name) + return pChild->AsElement()->BodyText(); + } + return STR_EMPTY; +} + +void +XmlElement::InsertChildAfter(XmlChild * pPredecessor, XmlChild * pNext) { + if (pPredecessor == NULL) { + pNext->pNextChild_ = pFirstChild_; + pFirstChild_ = pNext; + } + else { + pNext->pNextChild_ = pPredecessor->pNextChild_; + pPredecessor->pNextChild_ = pNext; + } +} + +void +XmlElement::RemoveChildAfter(XmlChild * pPredecessor) { + XmlChild * pNext; + + if (pPredecessor == NULL) { + pNext = pFirstChild_; + pFirstChild_ = pNext->pNextChild_; + } + else { + pNext = pPredecessor->pNextChild_; + pPredecessor->pNextChild_ = pNext->pNextChild_; + } + + if (pLastChild_ == pNext) + pLastChild_ = pPredecessor; + + delete pNext; +} + +void +XmlElement::AddAttr(const QName & name, const std::string & value) { + ASSERT(!HasAttr(name)); + + XmlAttr ** pprev = pLastAttr_ ? &(pLastAttr_->pNextAttr_) : &pFirstAttr_; + pLastAttr_ = (*pprev = new XmlAttr(name, value)); +} + +void +XmlElement::AddAttr(const QName & name, const std::string & value, + int depth) { + XmlElement * element = this; + while (depth--) { + element = element->pLastChild_->AsElement(); + } + element->AddAttr(name, value); +} + +void +XmlElement::AddParsedText(const char * cstr, int len) { + if (len == 0) + return; + + if (pLastChild_ && pLastChild_->IsText()) { + pLastChild_->AsText()->AddParsedText(cstr, len); + return; + } + XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_; + pLastChild_ = *pprev = new XmlText(cstr, len); +} + +void +XmlElement::AddText(const std::string & text) { + if (text == STR_EMPTY) + return; + + if (pLastChild_ && pLastChild_->IsText()) { + pLastChild_->AsText()->AddText(text); + return; + } + XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_; + pLastChild_ = *pprev = new XmlText(text); +} + +void +XmlElement::AddText(const std::string & text, int depth) { + // note: the first syntax is ambigious for msvc 6 + // XmlElement * pel(this); + XmlElement * element = this; + while (depth--) { + element = element->pLastChild_->AsElement(); + } + element->AddText(text); +} + +void +XmlElement::AddElement(XmlElement *pelChild) { + if (pelChild == NULL) + return; + + XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_; + pLastChild_ = *pprev = pelChild; + pelChild->pNextChild_ = NULL; +} + +void +XmlElement::AddElement(XmlElement *pelChild, int depth) { + XmlElement * element = this; + while (depth--) { + element = element->pLastChild_->AsElement(); + } + element->AddElement(pelChild); +} + +void +XmlElement::ClearNamedChildren(const QName & name) { + XmlChild * prev_child = NULL; + XmlChild * next_child; + XmlChild * child; + for (child = FirstChild(); child; child = next_child) { + next_child = child->NextChild(); + if (!child->IsText() && child->AsElement()->Name() == name) + { + RemoveChildAfter(prev_child); + continue; + } + prev_child = child; + } +} + +void +XmlElement::ClearChildren() { + XmlChild * pchild; + for (pchild = pFirstChild_; pchild; ) { + XmlChild * pToDelete = pchild; + pchild = pchild->pNextChild_; + delete pToDelete; + } + pFirstChild_ = pLastChild_ = NULL; +} + +std::string +XmlElement::Str() const { + std::stringstream ss; + Print(&ss, NULL, 0); + return ss.str(); +} + +XmlElement * +XmlElement::ForStr(const std::string & str) { + XmlBuilder builder; + XmlParser::ParseXml(&builder, str); + return builder.CreateElement(); +} + +void +XmlElement::Print( + std::ostream * pout, std::string xmlns[], int xmlnsCount) const { + XmlPrinter::PrintXml(pout, this, xmlns, xmlnsCount); +} + +XmlElement::~XmlElement() { + XmlAttr * pattr; + for (pattr = pFirstAttr_; pattr; ) { + XmlAttr * pToDelete = pattr; + pattr = pattr->pNextAttr_; + delete pToDelete; + } + + XmlChild * pchild; + for (pchild = pFirstChild_; pchild; ) { + XmlChild * pToDelete = pchild; + pchild = pchild->pNextChild_; + delete pToDelete; + } +} + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.h new file mode 100644 index 00000000..06545d89 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlelement.h @@ -0,0 +1,231 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xmlelement_h_ +#define _xmlelement_h_ + +#include <iosfwd> +#include <string> +#include "talk/base/scoped_ptr.h" +#include "talk/xmllite/qname.h" + +namespace buzz { + +extern const QName QN_EMPTY; +extern const QName QN_XMLNS; + + +class XmlChild; +class XmlText; +class XmlElement; +class XmlAttr; + +class XmlChild { +friend class XmlElement; + +public: + + XmlChild * NextChild() { return pNextChild_; } + const XmlChild * NextChild() const { return pNextChild_; } + + bool IsText() const { return IsTextImpl(); } + + XmlElement * AsElement() { return AsElementImpl(); } + const XmlElement * AsElement() const { return AsElementImpl(); } + + XmlText * AsText() { return AsTextImpl(); } + const XmlText * AsText() const { return AsTextImpl(); } + + +protected: + + XmlChild() : + pNextChild_(NULL) { + } + + virtual bool IsTextImpl() const = 0; + virtual XmlElement * AsElementImpl() const = 0; + virtual XmlText * AsTextImpl() const = 0; + + + virtual ~XmlChild(); + +private: + XmlChild(const XmlChild & noimpl); + + XmlChild * pNextChild_; + +}; + +class XmlText : public XmlChild { +public: + explicit XmlText(const std::string & text) : + XmlChild(), + text_(text) { + } + explicit XmlText(const XmlText & t) : + XmlChild(), + text_(t.text_) { + } + explicit XmlText(const char * cstr, size_t len) : + XmlChild(), + text_(cstr, len) { + } + virtual ~XmlText(); + + const std::string & Text() const { return text_; } + void SetText(const std::string & text); + void AddParsedText(const char * buf, int len); + void AddText(const std::string & text); + +protected: + virtual bool IsTextImpl() const; + virtual XmlElement * AsElementImpl() const; + virtual XmlText * AsTextImpl() const; + +private: + std::string text_; +}; + +class XmlAttr { +friend class XmlElement; + +public: + XmlAttr * NextAttr() const { return pNextAttr_; } + const QName & Name() const { return name_; } + const std::string & Value() const { return value_; } + +private: + explicit XmlAttr(const QName & name, const std::string & value) : + pNextAttr_(NULL), + name_(name), + value_(value) { + } + explicit XmlAttr(const XmlAttr & att) : + pNextAttr_(NULL), + name_(att.name_), + value_(att.value_) { + } + + XmlAttr * pNextAttr_; + QName name_; + std::string value_; +}; + +class XmlElement : public XmlChild { +public: + explicit XmlElement(const QName & name); + explicit XmlElement(const QName & name, bool useDefaultNs); + explicit XmlElement(const XmlElement & elt); + + virtual ~XmlElement(); + + const QName & Name() const { return name_; } + + const std::string & BodyText() const; + void SetBodyText(const std::string & text); + + const QName & FirstElementName() const; + + XmlAttr * FirstAttr(); + const XmlAttr * FirstAttr() const + { return const_cast<XmlElement *>(this)->FirstAttr(); } + + //! Attr will return STR_EMPTY if the attribute isn't there: + //! use HasAttr to test presence of an attribute. + const std::string & Attr(const QName & name) const; + bool HasAttr(const QName & name) const; + void SetAttr(const QName & name, const std::string & value); + void ClearAttr(const QName & name); + + XmlChild * FirstChild(); + const XmlChild * FirstChild() const + { return const_cast<XmlElement *>(this)->FirstChild(); } + + XmlElement * FirstElement(); + const XmlElement * FirstElement() const + { return const_cast<XmlElement *>(this)->FirstElement(); } + + XmlElement * NextElement(); + const XmlElement * NextElement() const + { return const_cast<XmlElement *>(this)->NextElement(); } + + XmlElement * FirstWithNamespace(const std::string & ns); + const XmlElement * FirstWithNamespace(const std::string & ns) const + { return const_cast<XmlElement *>(this)->FirstWithNamespace(ns); } + + XmlElement * NextWithNamespace(const std::string & ns); + const XmlElement * NextWithNamespace(const std::string & ns) const + { return const_cast<XmlElement *>(this)->NextWithNamespace(ns); } + + XmlElement * FirstNamed(const QName & name); + const XmlElement * FirstNamed(const QName & name) const + { return const_cast<XmlElement *>(this)->FirstNamed(name); } + + XmlElement * NextNamed(const QName & name); + const XmlElement * NextNamed(const QName & name) const + { return const_cast<XmlElement *>(this)->NextNamed(name); } + + const std::string & TextNamed(const QName & name) const; + + void InsertChildAfter(XmlChild * pPredecessor, XmlChild * pNewChild); + void RemoveChildAfter(XmlChild * pPredecessor); + + void AddParsedText(const char * buf, int len); + void AddText(const std::string & text); + void AddText(const std::string & text, int depth); + void AddElement(XmlElement * pelChild); + void AddElement(XmlElement * pelChild, int depth); + void AddAttr(const QName & name, const std::string & value); + void AddAttr(const QName & name, const std::string & value, int depth); + void ClearNamedChildren(const QName & name); + void ClearChildren(); + + static XmlElement * ForStr(const std::string & str); + std::string Str() const; + + void Print(std::ostream * pout, std::string xmlns[], int xmlnsCount) const; + +protected: + virtual bool IsTextImpl() const; + virtual XmlElement * AsElementImpl() const; + virtual XmlText * AsTextImpl() const; + +private: + QName name_; + XmlAttr * pFirstAttr_; + XmlAttr * pLastAttr_; + XmlChild * pFirstChild_; + XmlChild * pLastChild_; + +}; + + + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.cc new file mode 100644 index 00000000..4dcb6490 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.cc @@ -0,0 +1,205 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/stl_decl.h" +#include <string> +#include <iostream> +#include <vector> +#include <sstream> +#include "talk/xmllite/xmlelement.h" +#include "talk/xmllite/xmlnsstack.h" +#include "talk/xmllite/xmlconstants.h" + +namespace buzz { + +XmlnsStack::XmlnsStack() : + pxmlnsStack_(new std::vector<std::string>), + pxmlnsDepthStack_(new std::vector<size_t>) { +} + +XmlnsStack::~XmlnsStack() {} + +void +XmlnsStack::PushFrame() { + pxmlnsDepthStack_->push_back(pxmlnsStack_->size()); +} + +void +XmlnsStack::PopFrame() { + size_t prev_size = pxmlnsDepthStack_->back(); + pxmlnsDepthStack_->pop_back(); + if (prev_size < pxmlnsStack_->size()) { + pxmlnsStack_->erase(pxmlnsStack_->begin() + prev_size, + pxmlnsStack_->end()); + } +} +const std::pair<std::string, bool> NS_NOT_FOUND(STR_EMPTY, false); +const std::pair<std::string, bool> EMPTY_NS_FOUND(STR_EMPTY, true); +const std::pair<std::string, bool> XMLNS_DEFINITION_FOUND(NS_XMLNS, true); + +const std::string * +XmlnsStack::NsForPrefix(const std::string & prefix) { + if (prefix.length() >= 3 && + (prefix[0] == 'x' || prefix[0] == 'X') && + (prefix[1] == 'm' || prefix[1] == 'M') && + (prefix[2] == 'l' || prefix[2] == 'L')) { + if (prefix == "xml") + return &(NS_XML); + if (prefix == "xmlns") + return &(NS_XMLNS); + return NULL; + } + + std::vector<std::string>::iterator pos; + for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) { + pos -= 2; + if (*pos == prefix) + return &(*(pos + 1)); + } + + if (prefix == STR_EMPTY) + return &(STR_EMPTY); // default namespace + + return NULL; // none found +} + +bool +XmlnsStack::PrefixMatchesNs(const std::string & prefix, const std::string & ns) { + const std::string * match = NsForPrefix(prefix); + if (match == NULL) + return false; + return (*match == ns); +} + +std::pair<std::string, bool> +XmlnsStack::PrefixForNs(const std::string & ns, bool isattr) { + if (ns == NS_XML) + return std::make_pair(std::string("xml"), true); + if (ns == NS_XMLNS) + return std::make_pair(std::string("xmlns"), true); + if (isattr ? ns == STR_EMPTY : PrefixMatchesNs(STR_EMPTY, ns)) + return std::make_pair(STR_EMPTY, true); + + std::vector<std::string>::iterator pos; + for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) { + pos -= 2; + if (*(pos + 1) == ns && + (!isattr || !pos->empty()) && PrefixMatchesNs(*pos, ns)) + return std::make_pair(*pos, true); + } + + return std::make_pair(STR_EMPTY, false); // none found +} + +std::string +XmlnsStack::FormatQName(const QName & name, bool isAttr) { + std::string prefix(PrefixForNs(name.Namespace(), isAttr).first); + if (prefix == STR_EMPTY) + return name.LocalPart(); + else + return prefix + ':' + name.LocalPart(); +} + +void +XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) { + pxmlnsStack_->push_back(prefix); + pxmlnsStack_->push_back(ns); +} + +void +XmlnsStack::RemoveXmlns() { + pxmlnsStack_->pop_back(); + pxmlnsStack_->pop_back(); +} + +static bool IsAsciiLetter(char ch) { + return ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z')); +} + +static std::string AsciiLower(const std::string & s) { + std::string result(s); + size_t i; + for (i = 0; i < result.length(); i++) { + if (result[i] >= 'A' && result[i] <= 'Z') + result[i] += 'a' - 'A'; + } + return result; +} + +static std::string SuggestPrefix(const std::string & ns) { + size_t len = ns.length(); + size_t i = ns.find_last_of('.'); + if (i != std::string::npos && len - i <= 4 + 1) + len = i; // chop off ".html" or ".xsd" or ".?{0,4}" + size_t last = len; + while (last > 0) { + last -= 1; + if (IsAsciiLetter(ns[last])) { + size_t first = last; + last += 1; + while (first > 0) { + if (!IsAsciiLetter(ns[first - 1])) + break; + first -= 1; + } + if (last - first > 4) + last = first + 3; + std::string candidate(AsciiLower(ns.substr(first, last - first))); + if (candidate.find("xml") != 0) + return candidate; + break; + } + } + return "ns"; +} + + +std::pair<std::string, bool> +XmlnsStack::AddNewPrefix(const std::string & ns, bool isAttr) { + if (PrefixForNs(ns, isAttr).second) + return std::make_pair(STR_EMPTY, false); + + std::string base(SuggestPrefix(ns)); + std::string result(base); + int i = 2; + while (NsForPrefix(result) != NULL) { + std::stringstream ss; + ss << base; + ss << (i++); + ss >> result; + } + AddXmlns(result, ns); + return std::make_pair(result, true); +} + +void XmlnsStack::Reset() { + pxmlnsStack_->clear(); + pxmlnsDepthStack_->clear(); +} + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.h new file mode 100644 index 00000000..299ec1ce --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlnsstack.h @@ -0,0 +1,62 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xmlnsstack_h_ +#define _xmlnsstack_h_ + +#include <string> +#include "talk/base/scoped_ptr.h" +#include "talk/base/stl_decl.h" +#include "talk/xmllite/qname.h" + +namespace buzz { + +class XmlnsStack { +public: + XmlnsStack(); + ~XmlnsStack(); + + void AddXmlns(const std::string & prefix, const std::string & ns); + void RemoveXmlns(); + void PushFrame(); + void PopFrame(); + void Reset(); + + const std::string * NsForPrefix(const std::string & prefix); + bool PrefixMatchesNs(const std::string & prefix, const std::string & ns); + std::pair<std::string, bool> PrefixForNs(const std::string & ns, bool isAttr); + std::pair<std::string, bool> AddNewPrefix(const std::string & ns, bool isAttr); + std::string FormatQName(const QName & name, bool isAttr); + +private: + + scoped_ptr<std::vector<std::string, std::allocator<std::string> > > pxmlnsStack_; + scoped_ptr<std::vector<size_t, std::allocator<size_t> > > pxmlnsDepthStack_; +}; +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.cc new file mode 100644 index 00000000..f2b56778 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.cc @@ -0,0 +1,250 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/stl_decl.h" +#include <string> +#include <vector> +#include <iostream> +#include <expat.h> +#include "talk/xmllite/xmlelement.h" +#include "talk/base/common.h" +#include "talk/xmllite/xmlparser.h" +#include "talk/xmllite/xmlnsstack.h" +#include "talk/xmllite/xmlconstants.h" + +#include <expat.h> + +#define new TRACK_NEW + +namespace buzz { + + +static void +StartElementCallback(void * userData, const char *name, const char **atts) { + (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts); +} + +static void +EndElementCallback(void * userData, const char *name) { + (static_cast<XmlParser *>(userData))->ExpatEndElement(name); +} + +static void +CharacterDataCallback(void * userData, const char *text, int len) { + (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len); +} + +static void +XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) { + (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st); +} + +XmlParser::XmlParser(XmlParseHandler *pxph) : + context_(this), pxph_(pxph), sentError_(false) { + expat_ = XML_ParserCreate(NULL); + XML_SetUserData(expat_, this); + XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback); + XML_SetCharacterDataHandler(expat_, CharacterDataCallback); + XML_SetXmlDeclHandler(expat_, XmlDeclCallback); +} + +void +XmlParser::Reset() { + if (!XML_ParserReset(expat_, NULL)) { + XML_ParserFree(expat_); + expat_ = XML_ParserCreate(NULL); + } + XML_SetUserData(expat_, this); + XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback); + XML_SetCharacterDataHandler(expat_, CharacterDataCallback); + XML_SetXmlDeclHandler(expat_, XmlDeclCallback); + context_.Reset(); + sentError_ = false; +} + +static bool +XmlParser_StartsWithXmlns(const char *name) { + return name[0] == 'x' && + name[1] == 'm' && + name[2] == 'l' && + name[3] == 'n' && + name[4] == 's'; +} + +void +XmlParser::ExpatStartElement(const char *name, const char **atts) { + if (context_.RaisedError() != XML_ERROR_NONE) + return; + const char **att; + context_.StartElement(); + for (att = atts; *att; att += 2) { + if (XmlParser_StartsWithXmlns(*att)) { + if ((*att)[5] == '\0') { + context_.StartNamespace("", *(att + 1)); + } + else if ((*att)[5] == ':') { + if (**(att + 1) == '\0') { + // In XML 1.0 empty namespace illegal with prefix (not in 1.1) + context_.RaiseError(XML_ERROR_SYNTAX); + return; + } + context_.StartNamespace((*att) + 6, *(att + 1)); + } + } + } + pxph_->StartElement(&context_, name, atts); +} + +void +XmlParser::ExpatEndElement(const char *name) { + if (context_.RaisedError() != XML_ERROR_NONE) + return; + context_.EndElement(); + pxph_->EndElement(&context_, name); +} + +void +XmlParser::ExpatCharacterData(const char *text, int len) { + if (context_.RaisedError() != XML_ERROR_NONE) + return; + pxph_->CharacterData(&context_, text, len); +} + +void +XmlParser::ExpatXmlDecl(const char * ver, const char * enc, int standalone) { + if (context_.RaisedError() != XML_ERROR_NONE) + return; + + if (ver && std::string("1.0") != ver) { + context_.RaiseError(XML_ERROR_SYNTAX); + return; + } + + if (standalone == 0) { + context_.RaiseError(XML_ERROR_SYNTAX); + return; + } + + if (enc && !((enc[0] == 'U' || enc[0] == 'u') && + (enc[1] == 'T' || enc[1] == 't') && + (enc[2] == 'F' || enc[2] == 'f') && + enc[3] == '-' && enc[4] =='8')) { + context_.RaiseError(XML_ERROR_INCORRECT_ENCODING); + return; + } + +} + +bool +XmlParser::Parse(const char *data, size_t len, bool isFinal) { + if (sentError_) + return false; + + if (XML_Parse(expat_, data, static_cast<int>(len), isFinal) != XML_STATUS_OK) + context_.RaiseError(XML_GetErrorCode(expat_)); + + if (context_.RaisedError() != XML_ERROR_NONE) { + sentError_ = true; + pxph_->Error(&context_, context_.RaisedError()); + return false; + } + + return true; +} + +XmlParser::~XmlParser() { + XML_ParserFree(expat_); +} + +void +XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) { + XmlParser parser(pxph); + parser.Parse(text.c_str(), text.length(), true); +} + +XmlParser::ParseContext::ParseContext(XmlParser *parser) : + parser_(parser), + xmlnsstack_(), + raised_(XML_ERROR_NONE) { +} + +void +XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) { + xmlnsstack_.AddXmlns( + *prefix ? std::string(prefix) : STR_EMPTY, +// ns == NS_CLIENT ? NS_CLIENT : +// ns == NS_ROSTER ? NS_ROSTER : +// ns == NS_GR ? NS_GR : + std::string(ns)); +} + +void +XmlParser::ParseContext::StartElement() { + xmlnsstack_.PushFrame(); +} + +void +XmlParser::ParseContext::EndElement() { + xmlnsstack_.PopFrame(); +} + +QName +XmlParser::ParseContext::ResolveQName(const char *qname, bool isAttr) { + const char *c; + for (c = qname; *c; ++c) { + if (*c == ':') { + const std::string * result; + result = xmlnsstack_.NsForPrefix(std::string(qname, c - qname)); + if (result == NULL) + return QN_EMPTY; + const char * localname = c + 1; + return QName(*result, localname); + } + } + if (isAttr) { + return QName(STR_EMPTY, qname); + } + + const std::string * result; + result = xmlnsstack_.NsForPrefix(STR_EMPTY); + if (result == NULL) + return QN_EMPTY; + + return QName(*result, qname); +} + +void +XmlParser::ParseContext::Reset() { + xmlnsstack_.Reset(); + raised_ = XML_ERROR_NONE; +} + +XmlParser::ParseContext::~ParseContext() { +} + +} + diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.h new file mode 100644 index 00000000..760802e4 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlparser.h @@ -0,0 +1,108 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xmlparser_h_ +#define _xmlparser_h_ + +#include <string> +#include "talk/xmllite/xmlnsstack.h" +#include <expat.h> + +struct XML_ParserStruct; +typedef struct XML_ParserStruct * XML_Parser; + +namespace buzz { + +class XmlParseHandler; +class XmlParseContext; +class XmlParser; + +class XmlParseContext { +public: + virtual QName ResolveQName(const char * qname, bool isAttr) = 0; + virtual void RaiseError(XML_Error err) = 0; +}; + +class XmlParseHandler { +public: + virtual void StartElement(XmlParseContext * pctx, + const char * name, const char ** atts) = 0; + virtual void EndElement(XmlParseContext * pctx, + const char * name) = 0; + virtual void CharacterData(XmlParseContext * pctx, + const char * text, int len) = 0; + virtual void Error(XmlParseContext * pctx, + XML_Error errorCode) = 0; +}; + +class XmlParser { +public: + static void ParseXml(XmlParseHandler * pxph, std::string text); + + explicit XmlParser(XmlParseHandler * pxph); + bool Parse(const char * data, size_t len, bool isFinal); + void Reset(); + virtual ~XmlParser(); + + // expat callbacks + void ExpatStartElement(const char * name, const char ** atts); + void ExpatEndElement(const char * name); + void ExpatCharacterData(const char * text, int len); + void ExpatXmlDecl(const char * ver, const char * enc, int standalone); + +private: + + class ParseContext : public XmlParseContext { + public: + ParseContext(XmlParser * parser); + virtual ~ParseContext(); + virtual QName ResolveQName(const char * qname, bool isAttr); + virtual void RaiseError(XML_Error err) { if (!raised_) raised_ = err; } + XML_Error RaisedError() { return raised_; } + void Reset(); + + void StartElement(); + void EndElement(); + void StartNamespace(const char * prefix, const char * ns); + + private: + const XmlParser * parser_; + XmlnsStack xmlnsstack_; + XML_Error raised_; + }; + + ParseContext context_; + XML_Parser expat_; + XmlParseHandler * pxph_; + bool sentError_; + + +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.cc new file mode 100644 index 00000000..892e2ebb --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.cc @@ -0,0 +1,190 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/stl_decl.h" +#include <string> +#include <iostream> +#include <vector> +#include <sstream> +#include "talk/xmllite/xmlelement.h" +#include "talk/xmllite/xmlprinter.h" +#include "talk/xmllite/xmlnsstack.h" +#include "talk/xmllite/xmlconstants.h" + +namespace buzz { + +class XmlPrinterImpl { +public: + XmlPrinterImpl(std::ostream * pout, + const std::string * const xmlns, int xmlnsCount); + void PrintElement(const XmlElement * element); + void PrintQuotedValue(const std::string & text); + void PrintBodyText(const std::string & text); + +private: + std::ostream *pout_; + XmlnsStack xmlnsStack_; +}; + +void +XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element) { + PrintXml(pout, element, NULL, 0); +} + +void +XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element, + const std::string * const xmlns, int xmlnsCount) { + XmlPrinterImpl printer(pout, xmlns, xmlnsCount); + printer.PrintElement(element); +} + +XmlPrinterImpl::XmlPrinterImpl(std::ostream * pout, + const std::string * const xmlns, int xmlnsCount) : + pout_(pout), + xmlnsStack_() { + int i; + for (i = 0; i < xmlnsCount; i += 2) { + xmlnsStack_.AddXmlns(xmlns[i], xmlns[i + 1]); + } +} + +void +XmlPrinterImpl::PrintElement(const XmlElement * element) { + xmlnsStack_.PushFrame(); + + // first go through attrs of pel to add xmlns definitions + const XmlAttr * pattr; + for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) { + if (pattr->Name() == QN_XMLNS) + xmlnsStack_.AddXmlns(STR_EMPTY, pattr->Value()); + else if (pattr->Name().Namespace() == NS_XMLNS) + xmlnsStack_.AddXmlns(pattr->Name().LocalPart(), + pattr->Value()); + } + + // then go through qnames to make sure needed xmlns definitons are added + std::vector<std::string> newXmlns; + std::pair<std::string, bool> prefix; + prefix = xmlnsStack_.AddNewPrefix(element->Name().Namespace(), false); + if (prefix.second) { + newXmlns.push_back(prefix.first); + newXmlns.push_back(element->Name().Namespace()); + } + + for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) { + prefix = xmlnsStack_.AddNewPrefix(pattr->Name().Namespace(), true); + if (prefix.second) { + newXmlns.push_back(prefix.first); + newXmlns.push_back(element->Name().Namespace()); + } + } + + // print the element name + *pout_ << '<' << xmlnsStack_.FormatQName(element->Name(), false); + + // and the attributes + for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) { + *pout_ << ' ' << xmlnsStack_.FormatQName(pattr->Name(), true) << "=\""; + PrintQuotedValue(pattr->Value()); + *pout_ << '"'; + } + + // and the extra xmlns declarations + std::vector<std::string>::iterator i(newXmlns.begin()); + while (i < newXmlns.end()) { + if (*i == STR_EMPTY) + *pout_ << " xmlns=\"" << *(i + 1) << '"'; + else + *pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"'; + i += 2; + } + + // now the children + const XmlChild * pchild = element->FirstChild(); + + if (pchild == NULL) + *pout_ << "/>"; + else { + *pout_ << '>'; + while (pchild) { + if (pchild->IsText()) + PrintBodyText(pchild->AsText()->Text()); + else + PrintElement(pchild->AsElement()); + pchild = pchild->NextChild(); + } + *pout_ << "</" << xmlnsStack_.FormatQName(element->Name(), false) << '>'; + } + + xmlnsStack_.PopFrame(); +} + +void +XmlPrinterImpl::PrintQuotedValue(const std::string & text) { + size_t safe = 0; + for (;;) { + size_t unsafe = text.find_first_of("<>&\"", safe); + if (unsafe == std::string::npos) + unsafe = text.length(); + *pout_ << text.substr(safe, unsafe - safe); + if (unsafe == text.length()) + return; + switch (text[unsafe]) { + case '<': *pout_ << "<"; break; + case '>': *pout_ << ">"; break; + case '&': *pout_ << "&"; break; + case '"': *pout_ << """; break; + } + safe = unsafe + 1; + if (safe == text.length()) + return; + } +} + +void +XmlPrinterImpl::PrintBodyText(const std::string & text) { + size_t safe = 0; + for (;;) { + size_t unsafe = text.find_first_of("<>&", safe); + if (unsafe == std::string::npos) + unsafe = text.length(); + *pout_ << text.substr(safe, unsafe - safe); + if (unsafe == text.length()) + return; + switch (text[unsafe]) { + case '<': *pout_ << "<"; break; + case '>': *pout_ << ">"; break; + case '&': *pout_ << "&"; break; + } + safe = unsafe + 1; + if (safe == text.length()) + return; + } +} + + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.h new file mode 100644 index 00000000..96900d0d --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/xmlprinter.h @@ -0,0 +1,49 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xmlprinter_h_ +#define _xmlprinter_h_ + +#include <iosfwd> +#include <string> +#include "talk/base/scoped_ptr.h" + +namespace buzz { + +class XmlElement; + +class XmlPrinter { +public: + static void PrintXml(std::ostream * pout, const XmlElement * pelt); + + static void PrintXml(std::ostream * pout, const XmlElement * pelt, + const std::string * const xmlns, int xmlnsCount); +}; + +} + +#endif |