diff --git a/cef.gyp b/cef.gyp index 9a8a8ab8c..00b5695a4 100644 --- a/cef.gyp +++ b/cef.gyp @@ -98,6 +98,7 @@ 'tests/unittests/test_handler.h', 'tests/unittests/test_suite.h', 'tests/unittests/v8_unittest.cc', + 'tests/unittests/xml_reader_unittest.cc', ], 'include_dirs': [ '.', @@ -157,6 +158,7 @@ '../third_party/icu/icu.gyp:icuuc', '../third_party/libjpeg/libjpeg.gyp:libjpeg', '../third_party/libpng/libpng.gyp:libpng', + '../third_party/libxml/libxml.gyp:libxml', '../third_party/libxslt/libxslt.gyp:libxslt', '../third_party/mesa/mesa.gyp:osmesa', '../third_party/modp_b64/modp_b64.gyp:modp_b64', @@ -216,6 +218,8 @@ 'libcef_dll/cpptoc/stream_writer_cpptoc.h', 'libcef_dll/cpptoc/v8value_cpptoc.cc', 'libcef_dll/cpptoc/v8value_cpptoc.h', + 'libcef_dll/cpptoc/xml_reader_cpptoc.cc', + 'libcef_dll/cpptoc/xml_reader_cpptoc.h', 'libcef_dll/ctocpp/ctocpp.h', 'libcef_dll/ctocpp/download_handler_ctocpp.cc', 'libcef_dll/ctocpp/download_handler_ctocpp.h', @@ -274,6 +278,7 @@ '..', ], 'sources': [ + 'include/cef_wrapper.h', 'libcef_dll/cef_logging.h', 'libcef_dll/cpptoc/cpptoc.h', 'libcef_dll/cpptoc/download_handler_cpptoc.cc', @@ -309,8 +314,11 @@ 'libcef_dll/cpptoc/task_cpptoc.h', 'libcef_dll/ctocpp/v8value_ctocpp.cc', 'libcef_dll/ctocpp/v8value_ctocpp.h', + 'libcef_dll/ctocpp/xml_reader_ctocpp.cc', + 'libcef_dll/ctocpp/xml_reader_ctocpp.h', 'libcef_dll/transfer_util.cpp', 'libcef_dll/transfer_util.h', + 'libcef_dll/wrapper/cef_xml_object.cc', 'libcef_dll/wrapper/libcef_dll_wrapper.cc', ], }, @@ -344,6 +352,7 @@ '../third_party/icu/icu.gyp:icuuc', '../third_party/libjpeg/libjpeg.gyp:libjpeg', '../third_party/libpng/libpng.gyp:libpng', + '../third_party/libxml/libxml.gyp:libxml', '../third_party/libxslt/libxslt.gyp:libxslt', '../third_party/mesa/mesa.gyp:osmesa', '../third_party/modp_b64/modp_b64.gyp:modp_b64', @@ -423,6 +432,8 @@ 'libcef/v8_impl.h', 'libcef/webview_host.h', 'libcef/webwidget_host.h', + 'libcef/xml_reader_impl.cc', + 'libcef/xml_reader_impl.h', ], 'conditions': [ ['OS=="win"', { diff --git a/include/cef.h b/include/cef.h index 8155c8da9..f95a136da 100644 --- a/include/cef.h +++ b/include/cef.h @@ -265,6 +265,24 @@ public: void Lock() { m_critsec.Lock(); } void Unlock() { m_critsec.Unlock(); } + // A helper class that acquires the lock for the given CefThreadSafeBase while + // the CefAutoLock is in scope. + class AutoLock + { + public: + AutoLock(CefThreadSafeBase* base) : base_(base) + { + base_->Lock(); + } + ~AutoLock() + { + base_->Unlock(); + } + + private: + CefThreadSafeBase* base_; + }; + protected: long m_dwRef; CefCriticalSection m_critsec; @@ -1005,7 +1023,7 @@ public: class CefStreamWriter : public CefBase { public: - // Create a new CefStreamWriter object. + // Create a new CefStreamWriter object. /*--cef()--*/ static CefRefPtr CreateForFile(const std::wstring& fileName); /*--cef()--*/ @@ -1232,4 +1250,166 @@ public: virtual void Complete() =0; }; + +// Class that supports the reading of XML data via the libxml streaming API. +/*--cef(source=library)--*/ +class CefXmlReader : public CefBase +{ +public: + typedef cef_xml_encoding_type_t EncodingType; + typedef cef_xml_node_type_t NodeType; + + // Create a new CefXmlReader object. The returned object's methods can only + // be called from the thread that created the object. + /*--cef()--*/ + static CefRefPtr Create(CefRefPtr stream, + EncodingType encodingType, + const std::wstring& URI); + + // Moves the cursor to the next element node in the document. This method + // must be called at least once to set the current cursor position. Returns + // true if the cursor position was set successfully. + /*--cef()--*/ + virtual bool MoveToNextElement() =0; + + // Close the document. This must be called directly to ensure that cleanup + // occurs on the correct thread. + /*--cef()--*/ + virtual bool Close() =0; + + // Returns true if an error has been reported by the XML parser. + /*--cef()--*/ + virtual bool HasError() =0; + + // Returns the error string. + /*--cef()--*/ + virtual std::wstring GetError() =0; + + + // The below methods retrieve data for the node at the current cursor + // position. + + // Returns the node type. + /*--cef()--*/ + virtual NodeType GetType() =0; + + // Returns the node depth. Depth starts at 0 for the root node. + /*--cef()--*/ + virtual int GetDepth() =0; + + // Returns the local name. See + // http://www.w3.org/TR/REC-xml-names/#NT-LocalPart for additional details. + /*--cef()--*/ + virtual std::wstring GetLocalName() =0; + + // Returns the namespace prefix. See http://www.w3.org/TR/REC-xml-names/ for + // additional details. + /*--cef()--*/ + virtual std::wstring GetPrefix() =0; + + // Returns the qualified name, equal to (Prefix:)LocalName. See + // http://www.w3.org/TR/REC-xml-names/#ns-qualnames for additional details. + /*--cef()--*/ + virtual std::wstring GetQualifiedName() =0; + + // Returns the URI defining the namespace associated with the node. See + // http://www.w3.org/TR/REC-xml-names/ for additional details. + /*--cef()--*/ + virtual std::wstring GetNamespaceURI() =0; + + // Returns the base URI of the node. See http://www.w3.org/TR/xmlbase/ for + // additional details. + /*--cef()--*/ + virtual std::wstring GetBaseURI() =0; + + // Returns the xml:lang scope within which the node resides. See + // http://www.w3.org/TR/REC-xml/#sec-lang-tag for additional details. + /*--cef()--*/ + virtual std::wstring GetXmlLang() =0; + + // Returns true if the node represents an empty element. is considered + // empty but is not. + /*--cef()--*/ + virtual bool IsEmptyElement() =0; + + // Returns true if the node has a text value. + /*--cef()--*/ + virtual bool HasValue() =0; + + // Returns the text value. + /*--cef()--*/ + virtual std::wstring GetValue() =0; + + // Returns true if the node has attributes. + /*--cef()--*/ + virtual bool HasAttributes() =0; + + // Returns the number of attributes. + /*--cef()--*/ + virtual size_t GetAttributeCount() =0; + + // Returns the value of the attribute at the specified 0-based index. + /*--cef(capi_name=get_attribute_byindex)--*/ + virtual std::wstring GetAttribute(int index) =0; + + // Returns the value of the attribute with the specified qualified name. + /*--cef(capi_name=get_attribute_byqname)--*/ + virtual std::wstring GetAttribute(const std::wstring& qualifiedName) =0; + + // Returns the value of the attribute with the specified local name and + // namespace URI. + /*--cef(capi_name=get_attribute_bylname)--*/ + virtual std::wstring GetAttribute(const std::wstring& localName, + const std::wstring& namespaceURI) =0; + + // Returns an XML representation of the current node's children. + /*--cef()--*/ + virtual std::wstring GetInnerXml() =0; + + // Returns an XML representation of the current node including its children. + /*--cef()--*/ + virtual std::wstring GetOuterXml() =0; + + // Returns the line number for the current node. + /*--cef()--*/ + virtual int GetLineNumber() =0; + + + // Attribute nodes are not traversed by default. The below methods can be + // used to move the cursor to an attribute node. MoveToCarryingElement() can + // be called afterwards to return the cursor to the carrying element. The + // depth of an attribute node will be 1 + the depth of the carrying element. + + // Moves the cursor to the attribute at the specified 0-based index. Returns + // true if the cursor position was set successfully. + /*--cef(capi_name=move_to_attribute_byindex)--*/ + virtual bool MoveToAttribute(int index) =0; + + // Moves the cursor to the attribute with the specified qualified name. + // Returns true if the cursor position was set successfully. + /*--cef(capi_name=move_to_attribute_byqname)--*/ + virtual bool MoveToAttribute(const std::wstring& qualifiedName) =0; + + // Moves the cursor to the attribute with the specified local name and + // namespace URI. Returns true if the cursor position was set successfully. + /*--cef(capi_name=move_to_attribute_bylname)--*/ + virtual bool MoveToAttribute(const std::wstring& localName, + const std::wstring& namespaceURI) =0; + + // Moves the cursor to the first attribute in the current element. Returns + // true if the cursor position was set successfully. + /*--cef()--*/ + virtual bool MoveToFirstAttribute() =0; + + // Moves the cursor to the next attribute in the current element. Returns + // true if the cursor position was set successfully. + /*--cef()--*/ + virtual bool MoveToNextAttribute() =0; + + // Moves the cursor back to the carrying element. Returns true if the cursor + // position was set successfully. + /*--cef()--*/ + virtual bool MoveToCarryingElement() =0; +}; + #endif // _CEF_H diff --git a/include/cef_capi.h b/include/cef_capi.h index cfd08d484..1d28f221d 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -1004,6 +1004,159 @@ typedef struct _cef_download_handler_t } cef_download_handler_t; +// Structure that supports the reading of XML data via the libxml streaming API. +typedef struct _cef_xml_reader_t +{ + // Base structure. + cef_base_t base; + + // Moves the cursor to the next element node in the document. This function + // must be called at least once to set the current cursor position. Returns + // true (1) if the cursor position was set successfully. + int (CEF_CALLBACK *move_to_next_element)(struct _cef_xml_reader_t* self); + + // Close the document. This must be called directly to ensure that cleanup + // occurs on the correct thread. + int (CEF_CALLBACK *close)(struct _cef_xml_reader_t* self); + + // Returns true (1) if an error has been reported by the XML parser. + int (CEF_CALLBACK *has_error)(struct _cef_xml_reader_t* self); + + // Returns the error string. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_error)(struct _cef_xml_reader_t* self); + + + // The below functions retrieve data for the node at the current cursor + // position. + + // Returns the node type. + enum cef_xml_node_type_t (CEF_CALLBACK *get_type)( + struct _cef_xml_reader_t* self); + + // Returns the node depth. Depth starts at 0 for the root node. + int (CEF_CALLBACK *get_depth)(struct _cef_xml_reader_t* self); + + // Returns the local name. See http://www.w3.org/TR/REC-xml-names/#NT- + // LocalPart for additional details. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_local_name)(struct _cef_xml_reader_t* self); + + // Returns the namespace prefix. See http://www.w3.org/TR/REC-xml-names/ for + // additional details. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_prefix)(struct _cef_xml_reader_t* self); + + // Returns the qualified name, equal to (Prefix:)LocalName. See + // http://www.w3.org/TR/REC-xml-names/#ns-qualnames for additional details. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_qualified_name)( + struct _cef_xml_reader_t* self); + + // Returns the URI defining the namespace associated with the node. See + // http://www.w3.org/TR/REC-xml-names/ for additional details. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_namespace_uri)( + struct _cef_xml_reader_t* self); + + // Returns the base URI of the node. See http://www.w3.org/TR/xmlbase/ for + // additional details. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_base_uri)(struct _cef_xml_reader_t* self); + + // Returns the xml:lang scope within which the node resides. See + // http://www.w3.org/TR/REC-xml/#sec-lang-tag for additional details. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_xml_lang)(struct _cef_xml_reader_t* self); + + // Returns true (1) if the node represents an NULL element. is considered + // NULL but is not. + int (CEF_CALLBACK *is_empty_element)(struct _cef_xml_reader_t* self); + + // Returns true (1) if the node has a text value. + int (CEF_CALLBACK *has_value)(struct _cef_xml_reader_t* self); + + // Returns the text value. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_value)(struct _cef_xml_reader_t* self); + + // Returns true (1) if the node has attributes. + int (CEF_CALLBACK *has_attributes)(struct _cef_xml_reader_t* self); + + // Returns the number of attributes. + size_t (CEF_CALLBACK *get_attribute_count)(struct _cef_xml_reader_t* self); + + // Returns the value of the attribute at the specified 0-based index. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_attribute_byindex)( + struct _cef_xml_reader_t* self, int index); + + // Returns the value of the attribute with the specified qualified name. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_attribute_byqname)( + struct _cef_xml_reader_t* self, const wchar_t* qualifiedName); + + // Returns the value of the attribute with the specified local name and + // namespace URI. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_attribute_bylname)( + struct _cef_xml_reader_t* self, const wchar_t* localName, + const wchar_t* namespaceURI); + + // Returns an XML representation of the current node's children. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_inner_xml)(struct _cef_xml_reader_t* self); + + // Returns an XML representation of the current node including its children. + // The resulting string must be freed by calling cef_string_free(). + cef_string_t (CEF_CALLBACK *get_outer_xml)(struct _cef_xml_reader_t* self); + + // Returns the line number for the current node. + int (CEF_CALLBACK *get_line_number)(struct _cef_xml_reader_t* self); + + + // Attribute nodes are not traversed by default. The below functions can be + // used to move the cursor to an attribute node. move_to_carrying_element() + // can be called afterwards to return the cursor to the carrying element. The + // depth of an attribute node will be 1 + the depth of the carrying element. + + // Moves the cursor to the attribute at the specified 0-based index. Returns + // true (1) if the cursor position was set successfully. + int (CEF_CALLBACK *move_to_attribute_byindex)(struct _cef_xml_reader_t* self, + int index); + + // Moves the cursor to the attribute with the specified qualified name. + // Returns true (1) if the cursor position was set successfully. + int (CEF_CALLBACK *move_to_attribute_byqname)(struct _cef_xml_reader_t* self, + const wchar_t* qualifiedName); + + // Moves the cursor to the attribute with the specified local name and + // namespace URI. Returns true (1) if the cursor position was set + // successfully. + int (CEF_CALLBACK *move_to_attribute_bylname)(struct _cef_xml_reader_t* self, + const wchar_t* localName, const wchar_t* namespaceURI); + + // Moves the cursor to the first attribute in the current element. Returns + // true (1) if the cursor position was set successfully. + int (CEF_CALLBACK *move_to_first_attribute)(struct _cef_xml_reader_t* self); + + // Moves the cursor to the next attribute in the current element. Returns true + // (1) if the cursor position was set successfully. + int (CEF_CALLBACK *move_to_next_attribute)(struct _cef_xml_reader_t* self); + + // Moves the cursor back to the carrying element. Returns true (1) if the + // cursor position was set successfully. + int (CEF_CALLBACK *move_to_carrying_element)(struct _cef_xml_reader_t* self); + +} cef_xml_reader_t; + + +// Create a new cef_xml_reader_t object. The returned object's functions can +// only be called from the thread that created the object. +CEF_EXPORT cef_xml_reader_t* cef_xml_reader_create(cef_stream_reader_t* stream, + enum cef_xml_encoding_type_t encodingType, const wchar_t* URI); + + #ifdef __cplusplus } #endif diff --git a/include/cef_types.h b/include/cef_types.h index 18ffb4941..9b3b10b95 100644 --- a/include/cef_types.h +++ b/include/cef_types.h @@ -301,6 +301,35 @@ typedef struct _cef_print_options_t struct cef_print_margins paper_margins; } cef_print_options_t; +// Supported XML encoding types. The parser supports ASCII, ISO-8859-1, and +// UTF16 (LE and BE) by default. All other types must be translated to UTF8 +// before being passed to the parser. If a BOM is detected and the correct +// decoder is available then that decoder will be used automatically. +enum cef_xml_encoding_type_t +{ + XML_ENCODING_NONE = 0, + XML_ENCODING_UTF8, + XML_ENCODING_UTF16LE, + XML_ENCODING_UTF16BE, + XML_ENCODING_ASCII, +}; + +// XML node types. +enum cef_xml_node_type_t +{ + XML_NODE_UNSUPPORTED = 0, + XML_NODE_PROCESSING_INSTRUCTION, + XML_NODE_DOCUMENT_TYPE, + XML_NODE_ELEMENT_START, + XML_NODE_ELEMENT_END, + XML_NODE_ATTRIBUTE, + XML_NODE_TEXT, + XML_NODE_CDATA, + XML_NODE_ENTITY_REFERENCE, + XML_NODE_WHITESPACE, + XML_NODE_COMMENT, +}; + #ifdef __cplusplus } #endif diff --git a/include/cef_wrapper.h b/include/cef_wrapper.h new file mode 100644 index 000000000..947fdf74f --- /dev/null +++ b/include/cef_wrapper.h @@ -0,0 +1,152 @@ +// Copyright (c) 2010 Marshall A. Greenblatt. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the name Chromium Embedded +// Framework nor the names of its contributors may be used to endorse +// or promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "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 COPYRIGHT +// OWNER OR CONTRIBUTORS 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. +// +// --------------------------------------------------------------------------- +// +// The contents of this file are only available to applications that link +// against the libcef_dll_wrapper target. +// + +#ifndef _CEF_WRAPPER_H +#define _CEF_WRAPPER_H + +#include "cef.h" +#include +#include + +// Thread safe class for representing XML data as a structured object. This +// class should not be used with large XML documents because all data will be +// resident in memory at the same time. This implementation supports a +// restricted set of XML features: +// (1) Processing instructions, whitespace and comments are ignored. +// (2) Elements and attributes must always be referenced using the fully +// qualified name (ie, namespace:localname). +// (3) Empty elements () and elements with zero-length values () +// are considered the same. +// (4) Element nodes are considered part of a value if: +// (a) The element node follows a non-element node at the same depth +// (see 5), or +// (b) The element node does not have a namespace and the parent node does. +// (5) Mixed node types at the same depth are combined into a single element +// value as follows: +// (a) All node values are concatenated to form a single string value. +// (b) Entity reference nodes are resolved to the corresponding entity +// value. +// (c) Element nodes are represented by their outer XML string. +class CefXmlObject : public CefThreadSafeBase +{ +public: + typedef std::vector > ObjectVector; + typedef std::map AttributeMap; + + // Create a new object with the specified name. An object name must always be + // at least one character long. + CefXmlObject(const std::wstring& name); + virtual ~CefXmlObject(); + + // Load the contents of the specified XML stream into this object. The + // existing children and attributes, if any, will first be cleared. + bool Load(CefRefPtr stream, + CefXmlReader::EncodingType encodingType, + const std::wstring& URI, std::wstring* loadError); + + // Set the name, children and attributes of this object to a duplicate of the + // specified object's contents. The existing children and attributes, if any, + // will first be cleared. + void Set(CefRefPtr object); + + // Append a duplicate of the children and attributes of the specified object + // to this object. If |overwriteAttributes| is true then any attributes in + // this object that also exist in the specified object will be overwritten + // with the new values. The name of this object is not changed. + void Append(CefRefPtr object, bool overwriteAttributes); + + // Return a new object with the same name, children and attributes as this + // object. The parent of the new object will be NULL. + CefRefPtr Duplicate(); + + // Clears this object's children and attributes. The name and parenting of + // this object are not changed. + void Clear(); + + // Access the object's name. An object name must always be at least one + // character long. + std::wstring GetName(); + bool SetName(const std::wstring& name); + + // Access the object's parent. The parent can be NULL if this object has not + // been added as the child on another object. + bool HasParent(); + CefRefPtr GetParent(); + + // Access the object's value. An object cannot have a value if it also has + // children. Attempting to set the value while children exist will fail. + bool HasValue(); + std::wstring GetValue(); + bool SetValue(const std::wstring& value); + + // Access the object's attributes. Attributes must have unique names. + bool HasAttributes(); + size_t GetAttributeCount(); + bool HasAttribute(const std::wstring& name); + std::wstring GetAttributeValue(const std::wstring& name); + bool SetAttributeValue(const std::wstring& name, const std::wstring& value); + size_t GetAttributes(AttributeMap& attributes); + void ClearAttributes(); + + // Access the object's children. Each object can only have one parent so + // attempting to add an object that already has a parent will fail. Removing a + // child will set the child's parent to NULL. Adding a child will set the + // child's parent to this object. This object's value, if any, will be cleared + // if a child is added. + bool HasChildren(); + size_t GetChildCount(); + bool HasChild(CefRefPtr child); + bool AddChild(CefRefPtr child); + bool RemoveChild(CefRefPtr child); + size_t GetChildren(ObjectVector& children); + void ClearChildren(); + + // Find the first child with the specified name. + CefRefPtr FindChild(const std::wstring& name); + + // Find all children with the specified name. + size_t FindChildren(const std::wstring& name, ObjectVector& children); + +private: + void SetParent(CefXmlObject* parent); + + std::wstring name_; + CefXmlObject* parent_; + std::wstring value_; + AttributeMap attributes_; + ObjectVector children_; +}; + +#endif // _CEF_WRAPPER_H diff --git a/libcef/xml_reader_impl.cc b/libcef/xml_reader_impl.cc new file mode 100644 index 000000000..e26ba6458 --- /dev/null +++ b/libcef/xml_reader_impl.cc @@ -0,0 +1,506 @@ +// Copyright (c) 20010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "xml_reader_impl.h" +#include "base/logging.h" +#include "base/utf_string_conversions.h" + +// Static functions + +//static +CefRefPtr CefXmlReader::Create(CefRefPtr stream, + EncodingType encodingType, + const std::wstring& URI) +{ + CefRefPtr impl(new CefXmlReaderImpl()); + if (!impl->Initialize(stream, encodingType, URI)) + return NULL; + return impl.get(); +} + + +// CefXmlReaderImpl + +namespace { + +/** + * xmlInputReadCallback: + * @context: an Input context + * @buffer: the buffer to store data read + * @len: the length of the buffer in bytes + * + * Callback used in the I/O Input API to read the resource + * + * Returns the number of bytes read or -1 in case of error + */ +int XMLCALL xml_read_callback(void * context, char * buffer, int len) +{ + CefRefPtr reader(static_cast(context)); + return reader->Read(buffer, 1, len); +} + +/** + * xmlInputCloseCallback: + * @context: an Input context + * + * Callback used in the I/O Input API to close the resource + * + * Returns 0 or -1 in case of error + */ +int XMLCALL xml_close_callback(void * context) +{ + CefRefPtr reader(static_cast(context)); + + // Release the reference added by CefXmlReaderImpl::Initialize(). + reader->Release(); + return 1; +} + +/** + * xmlTextReaderErrorFunc: + * @arg: the user argument + * @msg: the message + * @severity: the severity of the error + * @locator: a locator indicating where the error occured + * + * Signature of an error callback from a reader parser + */ +void XMLCALL xml_error_callback(void *arg, const char *msg, + xmlParserSeverities severity, xmlTextReaderLocatorPtr locator) +{ + if (!msg) + return; + + std::wstring error_str; + UTF8ToWide(msg, strlen(msg), &error_str); + + if (!error_str.empty() && error_str[error_str.length()-1] == '\n') + error_str.resize(error_str.length()-1); + + std::wstringstream ss; + ss << error_str << L", line " << xmlTextReaderLocatorLineNumber(locator); + + LOG(INFO) << ss.str(); + + CefRefPtr impl(static_cast(arg)); + impl->AppendError(ss.str()); +} + +/** + * xmlStructuredErrorFunc: + * @userData: user provided data for the error callback + * @error: the error being raised. + * + * Signature of the function to use when there is an error and + * the module handles the new error reporting mechanism. + */ +void XMLCALL xml_structured_error_callback(void *userData, xmlErrorPtr error) +{ + if (!error->message) + return; + + std::wstring error_str; + UTF8ToWide(error->message, strlen(error->message), &error_str); + + if (!error_str.empty() && error_str[error_str.length()-1] == '\n') + error_str.resize(error_str.length()-1); + + std::wstringstream ss; + ss << error_str << L", line " << error->line; + + LOG(INFO) << ss.str(); + + CefRefPtr impl(static_cast(userData)); + impl->AppendError(ss.str()); +} + +std::wstring xmlCharToWString(const xmlChar* xmlStr, bool free) +{ + if (!xmlStr) + return std::wstring(); + + const char* str = reinterpret_cast(xmlStr); + std::wstring wstr; + UTF8ToWide(str, strlen(str), &wstr); + + if (free) + xmlFree(const_cast(xmlStr)); + + return wstr; +} + +} // namespace + +CefXmlReaderImpl::CefXmlReaderImpl() + : supported_thread_id_(PlatformThread::CurrentId()), reader_(NULL) +{ +} + +CefXmlReaderImpl::~CefXmlReaderImpl() +{ + if (reader_ != NULL) { + if (!VerifyContext()) { + // Close() is supposed to be called directly. We'll try to free the reader + // now on the wrong thread but there's no guarantee this call won't crash. + xmlFreeTextReader(reader_); + } else { + Close(); + } + } +} + +bool CefXmlReaderImpl::Initialize(CefRefPtr stream, + EncodingType encodingType, + const std::wstring& URI) +{ + xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; + switch (encodingType) { + case XML_ENCODING_UTF8: + enc = XML_CHAR_ENCODING_UTF8; + break; + case XML_ENCODING_UTF16LE: + enc = XML_CHAR_ENCODING_UTF16LE; + break; + case XML_ENCODING_UTF16BE: + enc = XML_CHAR_ENCODING_UTF16BE; + break; + case XML_ENCODING_ASCII: + enc = XML_CHAR_ENCODING_ASCII; + break; + default: + break; + } + + // Create the input buffer. + xmlParserInputBufferPtr input_buffer = xmlAllocParserInputBuffer(enc); + if (!input_buffer) + return false; + + // Add a reference that will be released by xml_close_callback(). + stream->AddRef(); + + input_buffer->context = stream.get(); + input_buffer->readcallback = xml_read_callback; + input_buffer->closecallback = xml_close_callback; + + // Create the text reader. + reader_ = xmlNewTextReader(input_buffer, WideToUTF8(URI).c_str()); + if (!reader_) { + // Free the input buffer. + xmlFreeParserInputBuffer(input_buffer); + return false; + } + + // Register the error callbacks. + xmlTextReaderSetErrorHandler(reader_, xml_error_callback, this); + xmlTextReaderSetStructuredErrorHandler(reader_, + xml_structured_error_callback, this); + + return true; +} + +bool CefXmlReaderImpl::MoveToNextElement() +{ + if (!VerifyContext()) + return false; + + return xmlTextReaderRead(reader_) == 1 ? true : false; +} + +bool CefXmlReaderImpl::Close() +{ + if (!VerifyContext()) + return false; + + // The input buffer will be freed automatically. + xmlFreeTextReader(reader_); + reader_ = NULL; + return true; +} + +bool CefXmlReaderImpl::HasError() +{ + if (!VerifyContext()) + return false; + + return !error_buf_.str().empty(); +} + +std::wstring CefXmlReaderImpl::GetError() +{ + if (!VerifyContext()) + return std::wstring(); + + return error_buf_.str(); +} + +CefXmlReader::NodeType CefXmlReaderImpl::GetType() +{ + if (!VerifyContext()) + return XML_NODE_UNSUPPORTED; + + switch (xmlTextReaderNodeType(reader_)) { + case XML_READER_TYPE_ELEMENT: + return XML_NODE_ELEMENT_START; + case XML_READER_TYPE_END_ELEMENT: + return XML_NODE_ELEMENT_END; + case XML_READER_TYPE_ATTRIBUTE: + return XML_NODE_ATTRIBUTE; + case XML_READER_TYPE_TEXT: + return XML_NODE_TEXT; + case XML_READER_TYPE_SIGNIFICANT_WHITESPACE: + case XML_READER_TYPE_WHITESPACE: + return XML_NODE_WHITESPACE; + case XML_READER_TYPE_CDATA: + return XML_NODE_CDATA; + case XML_READER_TYPE_ENTITY_REFERENCE: + return XML_NODE_ENTITY_REFERENCE; + case XML_READER_TYPE_PROCESSING_INSTRUCTION: + return XML_NODE_PROCESSING_INSTRUCTION; + case XML_READER_TYPE_COMMENT: + return XML_NODE_COMMENT; + case XML_READER_TYPE_DOCUMENT_TYPE: + return XML_NODE_DOCUMENT_TYPE; + default: + break; + } + + return XML_NODE_UNSUPPORTED; +} + +int CefXmlReaderImpl::GetDepth() +{ + if (!VerifyContext()) + return -1; + + return xmlTextReaderDepth(reader_); +} + +std::wstring CefXmlReaderImpl::GetLocalName() +{ + if (!VerifyContext()) + return std::wstring(); + + return xmlCharToWString(xmlTextReaderConstLocalName(reader_), false); +} + +std::wstring CefXmlReaderImpl::GetPrefix() +{ + if (!VerifyContext()) + return std::wstring(); + + return xmlCharToWString(xmlTextReaderConstPrefix(reader_), false); +} + +std::wstring CefXmlReaderImpl::GetQualifiedName() +{ + if (!VerifyContext()) + return std::wstring(); + + return xmlCharToWString(xmlTextReaderConstName(reader_), false); +} + +std::wstring CefXmlReaderImpl::GetNamespaceURI() +{ + if (!VerifyContext()) + return std::wstring(); + + return xmlCharToWString(xmlTextReaderConstNamespaceUri(reader_), false); +} + +std::wstring CefXmlReaderImpl::GetBaseURI() +{ + if (!VerifyContext()) + return std::wstring(); + + return xmlCharToWString(xmlTextReaderConstBaseUri(reader_), false); +} + +std::wstring CefXmlReaderImpl::GetXmlLang() +{ + if (!VerifyContext()) + return std::wstring(); + + return xmlCharToWString(xmlTextReaderConstXmlLang(reader_), false); +} + +bool CefXmlReaderImpl::IsEmptyElement() +{ + if (!VerifyContext()) + return false; + + return xmlTextReaderIsEmptyElement(reader_) == 1 ? true : false; +} + +bool CefXmlReaderImpl::HasValue() +{ + if (!VerifyContext()) + return false; + + if (xmlTextReaderNodeType(reader_) == XML_READER_TYPE_ENTITY_REFERENCE) { + // Provide special handling to return entity reference values. + return true; + } else { + return xmlTextReaderHasValue(reader_) == 1 ? true : false; + } +} + +std::wstring CefXmlReaderImpl::GetValue() +{ + if (!VerifyContext()) + return std::wstring(); + + if (xmlTextReaderNodeType(reader_) == XML_READER_TYPE_ENTITY_REFERENCE) { + // Provide special handling to return entity reference values. + xmlNodePtr node = xmlTextReaderCurrentNode(reader_); + if (node->content != NULL) + return xmlCharToWString(node->content, false); + return NULL; + } else { + return xmlCharToWString(xmlTextReaderConstValue(reader_), false); + } +} + +bool CefXmlReaderImpl::HasAttributes() +{ + if (!VerifyContext()) + return false; + + return xmlTextReaderHasAttributes(reader_) == 1 ? true : false; +} + +size_t CefXmlReaderImpl::GetAttributeCount() +{ + if (!VerifyContext()) + return 0; + + return xmlTextReaderAttributeCount(reader_); +} + +std::wstring CefXmlReaderImpl::GetAttribute(int index) +{ + if (!VerifyContext()) + return std::wstring(); + + return xmlCharToWString(xmlTextReaderGetAttributeNo(reader_, index), true); +} + +std::wstring CefXmlReaderImpl::GetAttribute(const std::wstring& qualifiedName) +{ + if (!VerifyContext()) + return std::wstring(); + + std::string qualifiedNameStr = WideToUTF8(qualifiedName); + return xmlCharToWString(xmlTextReaderGetAttribute(reader_, + BAD_CAST qualifiedNameStr.c_str()), true); +} + +std::wstring CefXmlReaderImpl::GetAttribute(const std::wstring& localName, + const std::wstring& namespaceURI) +{ + if (!VerifyContext()) + return std::wstring(); + + std::string localNameStr = WideToUTF8(localName); + std::string namespaceURIStr = WideToUTF8(namespaceURI); + return xmlCharToWString(xmlTextReaderGetAttributeNs(reader_, + BAD_CAST localNameStr.c_str(), BAD_CAST namespaceURIStr.c_str()), true); +} + +std::wstring CefXmlReaderImpl::GetInnerXml() +{ + if (!VerifyContext()) + return std::wstring(); + + return xmlCharToWString(xmlTextReaderReadInnerXml(reader_), true); +} + +std::wstring CefXmlReaderImpl::GetOuterXml() +{ + if (!VerifyContext()) + return std::wstring(); + + return xmlCharToWString(xmlTextReaderReadOuterXml(reader_), true); +} + +int CefXmlReaderImpl::GetLineNumber() +{ + if (!VerifyContext()) + return -1; + + return xmlTextReaderGetParserLineNumber(reader_); +} + +bool CefXmlReaderImpl::MoveToAttribute(int index) +{ + if (!VerifyContext()) + return false; + + return xmlTextReaderMoveToAttributeNo(reader_, index) == 1 ? true : false; +} + +bool CefXmlReaderImpl::MoveToAttribute(const std::wstring& qualifiedName) +{ + if (!VerifyContext()) + return false; + + std::string qualifiedNameStr = WideToUTF8(qualifiedName); + return xmlTextReaderMoveToAttribute(reader_, + BAD_CAST qualifiedNameStr.c_str()) == 1 ? true : false; +} + +bool CefXmlReaderImpl::MoveToAttribute(const std::wstring& localName, + const std::wstring& namespaceURI) +{ + if (!VerifyContext()) + return false; + + std::string localNameStr = WideToUTF8(localName); + std::string namespaceURIStr = WideToUTF8(namespaceURI); + return xmlTextReaderMoveToAttributeNs(reader_, + BAD_CAST localNameStr.c_str(), BAD_CAST namespaceURIStr.c_str()) == 1 ? + true : false; +} + +bool CefXmlReaderImpl::MoveToFirstAttribute() +{ + if (!VerifyContext()) + return false; + + return xmlTextReaderMoveToFirstAttribute(reader_) == 1 ? true : false; +} + +bool CefXmlReaderImpl::MoveToNextAttribute() +{ + if (!VerifyContext()) + return false; + + return xmlTextReaderMoveToNextAttribute(reader_) == 1 ? true : false; +} + +bool CefXmlReaderImpl::MoveToCarryingElement() +{ + if (!VerifyContext()) + return false; + + return xmlTextReaderMoveToElement(reader_) == 1 ? true : false; +} + +void CefXmlReaderImpl::AppendError(const std::wstring& error_str) +{ + if (!error_buf_.str().empty()) + error_buf_ << L"\n"; + error_buf_ << error_str; +} + +bool CefXmlReaderImpl::VerifyContext() +{ + if (PlatformThread::CurrentId() != supported_thread_id_) { + // This object should only be accessed from the thread that created it. + NOTREACHED(); + return false; + } + + return (reader_ != NULL); +} diff --git a/libcef/xml_reader_impl.h b/libcef/xml_reader_impl.h new file mode 100644 index 000000000..e0e11aa90 --- /dev/null +++ b/libcef/xml_reader_impl.h @@ -0,0 +1,69 @@ +// Copyright (c) 20010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#ifndef _XML_READER_IMPL_H +#define _XML_READER_IMPL_H + +#include "../include/cef.h" +#include "base/platform_thread.h" +#include +#include + +// Implementation of CefXmlReader +class CefXmlReaderImpl : public CefThreadSafeBase +{ +public: + CefXmlReaderImpl(); + ~CefXmlReaderImpl(); + + // Initialize the reader context. + bool Initialize(CefRefPtr stream, + EncodingType encodingType, const std::wstring& URI); + + virtual bool MoveToNextElement(); + virtual bool Close(); + virtual bool HasError(); + virtual std::wstring GetError(); + virtual NodeType GetType(); + virtual int GetDepth(); + virtual std::wstring GetLocalName(); + virtual std::wstring GetPrefix(); + virtual std::wstring GetQualifiedName(); + virtual std::wstring GetNamespaceURI(); + virtual std::wstring GetBaseURI(); + virtual std::wstring GetXmlLang(); + virtual bool IsEmptyElement(); + virtual bool HasValue(); + virtual std::wstring GetValue(); + virtual bool HasAttributes(); + virtual size_t GetAttributeCount(); + virtual std::wstring GetAttribute(int index); + virtual std::wstring GetAttribute(const std::wstring& qualifiedName); + virtual std::wstring GetAttribute(const std::wstring& localName, + const std::wstring& namespaceURI); + virtual std::wstring GetInnerXml(); + virtual std::wstring GetOuterXml(); + virtual int GetLineNumber(); + virtual bool MoveToAttribute(int index); + virtual bool MoveToAttribute(const std::wstring& qualifiedName); + virtual bool MoveToAttribute(const std::wstring& localName, + const std::wstring& namespaceURI); + virtual bool MoveToFirstAttribute(); + virtual bool MoveToNextAttribute(); + virtual bool MoveToCarryingElement(); + + // Add another line to the error string. + void AppendError(const std::wstring& error_str); + + // Verify that the reader exists and is being accessed from the correct + // thread. + bool VerifyContext(); + +protected: + PlatformThreadId supported_thread_id_; + xmlTextReaderPtr reader_; + std::wstringstream error_buf_; +}; + +#endif // _XML_READER_IMPL_H diff --git a/libcef_dll/cpptoc/xml_reader_cpptoc.cc b/libcef_dll/cpptoc/xml_reader_cpptoc.cc new file mode 100644 index 000000000..658d21307 --- /dev/null +++ b/libcef_dll/cpptoc/xml_reader_cpptoc.cc @@ -0,0 +1,409 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// A portion of this file was generated by the CEF translator tool. When +// making changes by hand only do so within the body of existing function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/stream_reader_cpptoc.h" +#include "libcef_dll/cpptoc/xml_reader_cpptoc.h" + + +// GLOBAL FUNCTIONS - Body may be edited by hand. + +CEF_EXPORT cef_xml_reader_t* cef_xml_reader_create(cef_stream_reader_t* stream, + enum cef_xml_encoding_type_t encodingType, const wchar_t* URI) +{ + std::wstring encodingTypeStr; + if(encodingType) + encodingTypeStr = encodingType; + CefRefPtr impl = CefXmlReader::Create( + CefStreamReaderCppToC::Unwrap(stream), encodingType, encodingTypeStr); + if(impl.get()) + return CefXmlReaderCppToC::Wrap(impl); + return NULL; +} + + +// MEMBER FUNCTIONS - Body may be edited by hand. + +int CEF_CALLBACK xml_reader_move_to_next_element(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->MoveToNextElement(); +} + +int CEF_CALLBACK xml_reader_close(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->Close(); +} + +int CEF_CALLBACK xml_reader_has_error(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->HasError(); +} + +cef_string_t CEF_CALLBACK xml_reader_get_error(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetError(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +enum cef_xml_node_type_t CEF_CALLBACK xml_reader_get_type( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return XML_NODE_UNSUPPORTED; + + return CefXmlReaderCppToC::Get(self)->GetType(); +} + +int CEF_CALLBACK xml_reader_get_depth(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return -1; + + return CefXmlReaderCppToC::Get(self)->GetDepth(); +} + +cef_string_t CEF_CALLBACK xml_reader_get_local_name( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetLocalName(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +cef_string_t CEF_CALLBACK xml_reader_get_prefix(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetPrefix(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +cef_string_t CEF_CALLBACK xml_reader_get_qualified_name( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetQualifiedName(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +cef_string_t CEF_CALLBACK xml_reader_get_namespace_uri( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetNamespaceURI(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +cef_string_t CEF_CALLBACK xml_reader_get_base_uri( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetBaseURI(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +cef_string_t CEF_CALLBACK xml_reader_get_xml_lang( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetXmlLang(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +int CEF_CALLBACK xml_reader_is_empty_element(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->IsEmptyElement(); +} + +int CEF_CALLBACK xml_reader_has_value(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->HasValue(); +} + +cef_string_t CEF_CALLBACK xml_reader_get_value(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetValue(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +int CEF_CALLBACK xml_reader_has_attributes(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->HasAttributes(); +} + +size_t CEF_CALLBACK xml_reader_get_attribute_count( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->GetAttributeCount(); +} + +cef_string_t CEF_CALLBACK xml_reader_get_attribute_byindex( + struct _cef_xml_reader_t* self, int index) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetAttribute(index); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +cef_string_t CEF_CALLBACK xml_reader_get_attribute_byqname( + struct _cef_xml_reader_t* self, const wchar_t* qualifiedName) +{ + DCHECK(self); + DCHECK(qualifiedName); + if(!self || !qualifiedName) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetAttribute( + qualifiedName); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +cef_string_t CEF_CALLBACK xml_reader_get_attribute_bylname( + struct _cef_xml_reader_t* self, const wchar_t* localName, + const wchar_t* namespaceURI) +{ + DCHECK(self); + DCHECK(localName); + DCHECK(namespaceURI); + if(!self || !localName || !namespaceURI) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetAttribute( + localName, namespaceURI); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +cef_string_t CEF_CALLBACK xml_reader_get_inner_xml( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetInnerXml(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +cef_string_t CEF_CALLBACK xml_reader_get_outer_xml( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + std::wstring retStr = CefXmlReaderCppToC::Get(self)->GetOuterXml(); + if(!retStr.empty()) + return cef_string_alloc(retStr.c_str()); + return NULL; +} + +int CEF_CALLBACK xml_reader_get_line_number(struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->GetLineNumber(); +} + +int CEF_CALLBACK xml_reader_move_to_attribute_byindex( + struct _cef_xml_reader_t* self, int index) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->MoveToAttribute(index); +} + +int CEF_CALLBACK xml_reader_move_to_attribute_byqname( + struct _cef_xml_reader_t* self, const wchar_t* qualifiedName) +{ + DCHECK(self); + DCHECK(qualifiedName); + if(!self || !qualifiedName) + return 0; + + return CefXmlReaderCppToC::Get(self)->MoveToAttribute(qualifiedName); +} + +int CEF_CALLBACK xml_reader_move_to_attribute_bylname( + struct _cef_xml_reader_t* self, const wchar_t* localName, + const wchar_t* namespaceURI) +{ + DCHECK(self); + DCHECK(localName); + DCHECK(namespaceURI); + if(!self || !localName || !namespaceURI) + return 0; + + return CefXmlReaderCppToC::Get(self)->MoveToAttribute(localName, + namespaceURI); +} + +int CEF_CALLBACK xml_reader_move_to_first_attribute( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->MoveToFirstAttribute(); +} + +int CEF_CALLBACK xml_reader_move_to_next_attribute( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->MoveToNextAttribute(); +} + +int CEF_CALLBACK xml_reader_move_to_carrying_element( + struct _cef_xml_reader_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefXmlReaderCppToC::Get(self)->MoveToCarryingElement(); +} + + +// CONSTRUCTOR - Do not edit by hand. + +CefXmlReaderCppToC::CefXmlReaderCppToC(CefXmlReader* cls) + : CefCppToC(cls) +{ + struct_.struct_.move_to_next_element = xml_reader_move_to_next_element; + struct_.struct_.close = xml_reader_close; + struct_.struct_.has_error = xml_reader_has_error; + struct_.struct_.get_error = xml_reader_get_error; + struct_.struct_.get_type = xml_reader_get_type; + struct_.struct_.get_depth = xml_reader_get_depth; + struct_.struct_.get_local_name = xml_reader_get_local_name; + struct_.struct_.get_prefix = xml_reader_get_prefix; + struct_.struct_.get_qualified_name = xml_reader_get_qualified_name; + struct_.struct_.get_namespace_uri = xml_reader_get_namespace_uri; + struct_.struct_.get_base_uri = xml_reader_get_base_uri; + struct_.struct_.get_xml_lang = xml_reader_get_xml_lang; + struct_.struct_.is_empty_element = xml_reader_is_empty_element; + struct_.struct_.has_value = xml_reader_has_value; + struct_.struct_.get_value = xml_reader_get_value; + struct_.struct_.has_attributes = xml_reader_has_attributes; + struct_.struct_.get_attribute_count = xml_reader_get_attribute_count; + struct_.struct_.get_attribute_byindex = xml_reader_get_attribute_byindex; + struct_.struct_.get_attribute_byqname = xml_reader_get_attribute_byqname; + struct_.struct_.get_attribute_bylname = xml_reader_get_attribute_bylname; + struct_.struct_.get_inner_xml = xml_reader_get_inner_xml; + struct_.struct_.get_outer_xml = xml_reader_get_outer_xml; + struct_.struct_.get_line_number = xml_reader_get_line_number; + struct_.struct_.move_to_attribute_byindex = + xml_reader_move_to_attribute_byindex; + struct_.struct_.move_to_attribute_byqname = + xml_reader_move_to_attribute_byqname; + struct_.struct_.move_to_attribute_bylname = + xml_reader_move_to_attribute_bylname; + struct_.struct_.move_to_first_attribute = xml_reader_move_to_first_attribute; + struct_.struct_.move_to_next_attribute = xml_reader_move_to_next_attribute; + struct_.struct_.move_to_carrying_element = + xml_reader_move_to_carrying_element; +} + +#ifdef _DEBUG +long CefCppToC::DebugObjCt = + 0; +#endif + diff --git a/libcef_dll/cpptoc/xml_reader_cpptoc.h b/libcef_dll/cpptoc/xml_reader_cpptoc.h new file mode 100644 index 000000000..3f34d911d --- /dev/null +++ b/libcef_dll/cpptoc/xml_reader_cpptoc.h @@ -0,0 +1,34 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool and should not edited +// by hand. See the translator.README.txt file in the tools directory for +// more information. +// +#ifndef _XMLREADER_CPPTOC_H +#define _XMLREADER_CPPTOC_H + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef.h" +#include "include/cef_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed DLL-side only. +class CefXmlReaderCppToC + : public CefCppToC +{ +public: + CefXmlReaderCppToC(CefXmlReader* cls); + virtual ~CefXmlReaderCppToC() {} +}; + +#endif // BUILDING_CEF_SHARED +#endif // _XMLREADER_CPPTOC_H + diff --git a/libcef_dll/ctocpp/xml_reader_ctocpp.cc b/libcef_dll/ctocpp/xml_reader_ctocpp.cc new file mode 100644 index 000000000..6c026584b --- /dev/null +++ b/libcef_dll/ctocpp/xml_reader_ctocpp.cc @@ -0,0 +1,366 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// A portion of this file was generated by the CEF translator tool. When +// making changes by hand only do so within the body of existing static and +// virtual method implementations. See the translator.README.txt file in the +// tools directory for more information. +// + +#include "libcef_dll/ctocpp/stream_reader_ctocpp.h" +#include "libcef_dll/ctocpp/xml_reader_ctocpp.h" + + +// STATIC METHODS - Body may be edited by hand. + +CefRefPtr CefXmlReader::Create(CefRefPtr stream, + EncodingType encodingType, const std::wstring& URI) +{ + cef_xml_reader_t* impl = cef_xml_reader_create( + CefStreamReaderCToCpp::Unwrap(stream), encodingType, URI.c_str()); + if(impl) + return CefXmlReaderCToCpp::Wrap(impl); + return NULL; +} + + +// VIRTUAL METHODS - Body may be edited by hand. + +bool CefXmlReaderCToCpp::MoveToNextElement() +{ + if(CEF_MEMBER_MISSING(struct_, move_to_next_element)) + return false; + + return struct_->move_to_next_element(struct_) ? true : false; +} + +bool CefXmlReaderCToCpp::Close() +{ + if(CEF_MEMBER_MISSING(struct_, close)) + return false; + + return struct_->close(struct_) ? true : false; +} + +bool CefXmlReaderCToCpp::HasError() +{ + if(CEF_MEMBER_MISSING(struct_, has_error)) + return false; + + return struct_->has_error(struct_) ? true : false; +} + +std::wstring CefXmlReaderCToCpp::GetError() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_error)) + return str; + + cef_string_t cef_str = struct_->get_error(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +CefXmlReader::NodeType CefXmlReaderCToCpp::GetType() +{ + if(CEF_MEMBER_MISSING(struct_, get_type)) + return XML_NODE_UNSUPPORTED; + + return struct_->get_type(struct_); +} + +int CefXmlReaderCToCpp::GetDepth() +{ + if(CEF_MEMBER_MISSING(struct_, get_depth)) + return -1; + + return struct_->get_depth(struct_); +} + +std::wstring CefXmlReaderCToCpp::GetLocalName() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_local_name)) + return str; + + cef_string_t cef_str = struct_->get_local_name(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +std::wstring CefXmlReaderCToCpp::GetPrefix() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_prefix)) + return str; + + cef_string_t cef_str = struct_->get_prefix(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +std::wstring CefXmlReaderCToCpp::GetQualifiedName() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_qualified_name)) + return str; + + cef_string_t cef_str = struct_->get_qualified_name(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +std::wstring CefXmlReaderCToCpp::GetNamespaceURI() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_namespace_uri)) + return str; + + cef_string_t cef_str = struct_->get_namespace_uri(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +std::wstring CefXmlReaderCToCpp::GetBaseURI() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_base_uri)) + return str; + + cef_string_t cef_str = struct_->get_base_uri(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +std::wstring CefXmlReaderCToCpp::GetXmlLang() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_xml_lang)) + return str; + + cef_string_t cef_str = struct_->get_xml_lang(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +bool CefXmlReaderCToCpp::IsEmptyElement() +{ + if(CEF_MEMBER_MISSING(struct_, is_empty_element)) + return false; + + return struct_->is_empty_element(struct_) ? true : false; +} + +bool CefXmlReaderCToCpp::HasValue() +{ + if(CEF_MEMBER_MISSING(struct_, has_value)) + return false; + + return struct_->has_value(struct_) ? true : false; +} + +std::wstring CefXmlReaderCToCpp::GetValue() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_value)) + return str; + + cef_string_t cef_str = struct_->get_value(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +bool CefXmlReaderCToCpp::HasAttributes() +{ + if(CEF_MEMBER_MISSING(struct_, has_attributes)) + return false; + + return struct_->has_attributes(struct_) ? true : false; +} + +size_t CefXmlReaderCToCpp::GetAttributeCount() +{ + if(CEF_MEMBER_MISSING(struct_, get_attribute_count)) + return 0; + + return struct_->get_attribute_count(struct_); +} + +std::wstring CefXmlReaderCToCpp::GetAttribute(int index) +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_attribute_byindex)) + return str; + + cef_string_t cef_str = struct_->get_attribute_byindex(struct_, index); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +std::wstring CefXmlReaderCToCpp::GetAttribute(const std::wstring& qualifiedName) +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_attribute_byqname)) + return str; + + cef_string_t cef_str = struct_->get_attribute_byqname(struct_, + qualifiedName.c_str()); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +std::wstring CefXmlReaderCToCpp::GetAttribute(const std::wstring& localName, + const std::wstring& namespaceURI) +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_attribute_bylname)) + return str; + + cef_string_t cef_str = struct_->get_attribute_bylname(struct_, + localName.c_str(), namespaceURI.c_str()); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +std::wstring CefXmlReaderCToCpp::GetInnerXml() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_inner_xml)) + return str; + + cef_string_t cef_str = struct_->get_inner_xml(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +std::wstring CefXmlReaderCToCpp::GetOuterXml() +{ + std::wstring str; + if(CEF_MEMBER_MISSING(struct_, get_outer_xml)) + return str; + + cef_string_t cef_str = struct_->get_outer_xml(struct_); + if(cef_str) { + str = cef_str; + cef_string_free(cef_str); + } + + return str; +} + +int CefXmlReaderCToCpp::GetLineNumber() +{ + if(CEF_MEMBER_MISSING(struct_, get_line_number)) + return false; + + return struct_->get_line_number(struct_); +} + +bool CefXmlReaderCToCpp::MoveToAttribute(int index) +{ + if(CEF_MEMBER_MISSING(struct_, move_to_attribute_byindex)) + return false; + + return struct_->move_to_attribute_byindex(struct_, index) ? true : false; +} + +bool CefXmlReaderCToCpp::MoveToAttribute(const std::wstring& qualifiedName) +{ + if(CEF_MEMBER_MISSING(struct_, move_to_attribute_byqname)) + return false; + + return struct_->move_to_attribute_byqname(struct_, qualifiedName.c_str()) ? + true : false; +} + +bool CefXmlReaderCToCpp::MoveToAttribute(const std::wstring& localName, + const std::wstring& namespaceURI) +{ + if(CEF_MEMBER_MISSING(struct_, move_to_attribute_bylname)) + return false; + + return struct_->move_to_attribute_bylname(struct_, localName.c_str(), + namespaceURI.c_str()) ? true : false; +} + +bool CefXmlReaderCToCpp::MoveToFirstAttribute() +{ + if(CEF_MEMBER_MISSING(struct_, move_to_first_attribute)) + return false; + + return struct_->move_to_first_attribute(struct_) ? true : false; +} + +bool CefXmlReaderCToCpp::MoveToNextAttribute() +{ + if(CEF_MEMBER_MISSING(struct_, move_to_next_attribute)) + return false; + + return struct_->move_to_next_attribute(struct_) ? true : false; +} + +bool CefXmlReaderCToCpp::MoveToCarryingElement() +{ + if(CEF_MEMBER_MISSING(struct_, move_to_carrying_element)) + return false; + + return struct_->move_to_carrying_element(struct_) ? true : false; +} + + +#ifdef _DEBUG +long CefCToCpp::DebugObjCt = + 0; +#endif + diff --git a/libcef_dll/ctocpp/xml_reader_ctocpp.h b/libcef_dll/ctocpp/xml_reader_ctocpp.h new file mode 100644 index 000000000..7a5d77731 --- /dev/null +++ b/libcef_dll/ctocpp/xml_reader_ctocpp.h @@ -0,0 +1,69 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// ------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool and should not edited +// by hand. See the translator.README.txt file in the tools directory for +// more information. +// + +#ifndef _XMLREADER_CTOCPP_H +#define _XMLREADER_CTOCPP_H + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef.h" +#include "include/cef_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed wrapper-side only. +class CefXmlReaderCToCpp + : public CefCToCpp +{ +public: + CefXmlReaderCToCpp(cef_xml_reader_t* str) + : CefCToCpp(str) {} + virtual ~CefXmlReaderCToCpp() {} + + // CefXmlReader methods + virtual bool MoveToNextElement(); + virtual bool Close(); + virtual bool HasError(); + virtual std::wstring GetError(); + virtual NodeType GetType(); + virtual int GetDepth(); + virtual std::wstring GetLocalName(); + virtual std::wstring GetPrefix(); + virtual std::wstring GetQualifiedName(); + virtual std::wstring GetNamespaceURI(); + virtual std::wstring GetBaseURI(); + virtual std::wstring GetXmlLang(); + virtual bool IsEmptyElement(); + virtual bool HasValue(); + virtual std::wstring GetValue(); + virtual bool HasAttributes(); + virtual size_t GetAttributeCount(); + virtual std::wstring GetAttribute(int index); + virtual std::wstring GetAttribute(const std::wstring& qualifiedName); + virtual std::wstring GetAttribute(const std::wstring& localName, + const std::wstring& namespaceURI); + virtual std::wstring GetInnerXml(); + virtual std::wstring GetOuterXml(); + virtual int GetLineNumber(); + virtual bool MoveToAttribute(int index); + virtual bool MoveToAttribute(const std::wstring& qualifiedName); + virtual bool MoveToAttribute(const std::wstring& localName, + const std::wstring& namespaceURI); + virtual bool MoveToFirstAttribute(); + virtual bool MoveToNextAttribute(); + virtual bool MoveToCarryingElement(); +}; + +#endif // USING_CEF_SHARED +#endif // _XMLREADER_CTOCPP_H + diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index 3f4e8cf4a..f4a5b2bc2 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -14,6 +14,7 @@ #include "cpptoc/stream_reader_cpptoc.h" #include "cpptoc/stream_writer_cpptoc.h" #include "cpptoc/v8value_cpptoc.h" +#include "cpptoc/xml_reader_cpptoc.h" #include "ctocpp/download_handler_ctocpp.h" #include "ctocpp/handler_ctocpp.h" #include "ctocpp/read_handler_ctocpp.h" @@ -47,6 +48,7 @@ CEF_EXPORT void cef_shutdown() DCHECK(CefStreamReaderCppToC::DebugObjCt == 0); DCHECK(CefStreamWriterCppToC::DebugObjCt == 0); DCHECK(CefV8ValueCppToC::DebugObjCt == 0); + DCHECK(CefXmlReaderCppToC::DebugObjCt == 0); DCHECK(CefDownloadHandlerCToCpp::DebugObjCt == 0); DCHECK(CefHandlerCToCpp::DebugObjCt == 0); DCHECK(CefReadHandlerCToCpp::DebugObjCt == 0); diff --git a/libcef_dll/wrapper/cef_xml_object.cc b/libcef_dll/wrapper/cef_xml_object.cc new file mode 100644 index 000000000..0f6c55696 --- /dev/null +++ b/libcef_dll/wrapper/cef_xml_object.cc @@ -0,0 +1,488 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "include/cef_wrapper.h" +#include "base/logging.h" + +namespace { + +class CefXmlObjectLoader +{ +public: + CefXmlObjectLoader(CefRefPtr root_object) + : root_object_(root_object) + { + } + + bool Load(CefRefPtr stream, + CefXmlReader::EncodingType encodingType, + const std::wstring& URI) + { + CefRefPtr reader( + CefXmlReader::Create(stream, encodingType, URI)); + if (!reader.get()) + return false; + + bool ret = reader->MoveToNextElement(); + if (ret) { + CefRefPtr cur_object(root_object_), new_object; + CefXmlObject::ObjectVector queue; + int cur_depth, value_depth = -1; + CefXmlReader::NodeType cur_type; + std::wstringstream cur_value; + bool last_has_ns = false; + + queue.push_back(root_object_); + + do { + cur_depth = reader->GetDepth(); + if (value_depth >= 0 && cur_depth > value_depth) { + // The current node has already been parsed as part of a value. + continue; + } + + cur_type = reader->GetType(); + if (cur_type == XML_NODE_ELEMENT_START) { + if (cur_depth == value_depth) { + // Add to the current value. + cur_value << reader->GetOuterXml(); + continue; + } else if(last_has_ns && reader->GetPrefix().empty()) { + if (!cur_object->HasChildren()) { + // Start a new value because the last element has a namespace and + // this element does not. + value_depth = cur_depth; + cur_value << reader->GetOuterXml(); + } else { + // Value following a child element is not allowed. + std::wstringstream ss; + ss << L"Value following child element, line " << + reader->GetLineNumber(); + load_error_ = ss.str(); + ret = false; + break; + } + } else { + // Start a new element. + new_object = new CefXmlObject(reader->GetQualifiedName()); + cur_object->AddChild(new_object); + last_has_ns = !reader->GetPrefix().empty(); + + if (!reader->IsEmptyElement()) { + // The new element potentially has a value and/or children, so + // set the current object and add the object to the queue. + cur_object = new_object; + queue.push_back(cur_object); + } + + if (reader->HasAttributes() && reader->MoveToFirstAttribute()) { + // Read all object attributes. + do { + new_object->SetAttributeValue(reader->GetQualifiedName(), + reader->GetValue()); + } while(reader->MoveToNextAttribute()); + reader->MoveToCarryingElement(); + } + } + } else if(cur_type == XML_NODE_ELEMENT_END) { + if (cur_depth == value_depth) { + // Ending an element that is already in the value. + continue; + } else if (cur_depth < value_depth) { + // Done with parsing the value portion of the current element. + cur_object->SetValue(cur_value.str()); + cur_value.str(L""); + value_depth = -1; + } + + // Pop the current element from the queue. + queue.pop_back(); + + if (queue.empty() || + cur_object->GetName() != reader->GetQualifiedName()) { + // Open tag without close tag or close tag without open tag should + // never occur (the parser catches this error). + NOTREACHED(); + std::wstringstream ss; + ss << L"Mismatched end tag for " << cur_object->GetName() << + L", line " << reader->GetLineNumber(); + load_error_ = ss.str(); + ret = false; + break; + } + + // Set the current object to the previous object in the queue. + cur_object = queue.back().get(); + } else if(cur_type == XML_NODE_TEXT || cur_type == XML_NODE_CDATA || + cur_type == XML_NODE_ENTITY_REFERENCE) { + if (cur_depth == value_depth) { + // Add to the current value. + cur_value << reader->GetValue(); + } else if (!cur_object->HasChildren()) { + // Start a new value. + value_depth = cur_depth; + cur_value << reader->GetValue(); + } else { + // Value following a child element is not allowed. + std::wstringstream ss; + ss << L"Value following child element, line " << + reader->GetLineNumber(); + load_error_ = ss.str(); + ret = false; + break; + } + } + } while(reader->MoveToNextElement()); + } + + if (reader->HasError()) { + load_error_ = reader->GetError(); + return false; + } + + return ret; + } + + std::wstring GetLoadError() { return load_error_; } + +private: + std::wstring load_error_; + CefRefPtr root_object_; +}; + +} // namespace + +CefXmlObject::CefXmlObject(const std::wstring& name) + : name_(name), parent_(NULL) +{ +} + +CefXmlObject::~CefXmlObject() +{ +} + +bool CefXmlObject::Load(CefRefPtr stream, + CefXmlReader::EncodingType encodingType, + const std::wstring& URI, std::wstring* loadError) +{ + AutoLock lock_scope(this); + Clear(); + + CefXmlObjectLoader loader(this); + if (!loader.Load(stream, encodingType, URI)) { + if (loadError) + *loadError = loader.GetLoadError(); + return false; + } + return true; +} + +void CefXmlObject::Set(CefRefPtr object) +{ + DCHECK(object.get()); + + AutoLock lock_scope1(this); + AutoLock lock_scope2(object); + + Clear(); + name_ = object->GetName(); + Append(object, true); +} + +void CefXmlObject::Append(CefRefPtr object, + bool overwriteAttributes) +{ + DCHECK(object.get()); + + AutoLock lock_scope1(this); + AutoLock lock_scope2(object); + + if (object->HasChildren()) { + ObjectVector children; + object->GetChildren(children); + ObjectVector::const_iterator it = children.begin(); + for (; it != children.end(); ++it) + AddChild((*it)->Duplicate()); + } + + if (object->HasAttributes()) { + AttributeMap attributes; + object->GetAttributes(attributes); + AttributeMap::const_iterator it = attributes.begin(); + for (; it != attributes.end(); ++it) { + if (overwriteAttributes || !HasAttribute(it->first)) + SetAttributeValue(it->first, it->second); + } + } +} + +CefRefPtr CefXmlObject::Duplicate() +{ + CefRefPtr new_obj; + { + AutoLock lock_scope(this); + new_obj = new CefXmlObject(name_); + new_obj->Append(this, true); + } + return new_obj; +} + +void CefXmlObject::Clear() +{ + AutoLock lock_scope(this); + ClearChildren(); + ClearAttributes(); +} + +std::wstring CefXmlObject::GetName() +{ + std::wstring name; + { + AutoLock lock_scope(this); + name = name_; + } + return name; +} + +bool CefXmlObject::SetName(const std::wstring& name) +{ + DCHECK(!name.empty()); + if (name.empty()) + return false; + + AutoLock lock_scope(this); + name_ = name; + return true; +} + +bool CefXmlObject::HasParent() +{ + AutoLock lock_scope(this); + return (parent_ != NULL); +} + +CefRefPtr CefXmlObject::GetParent() +{ + CefRefPtr parent; + { + AutoLock lock_scope(this); + parent = parent_; + } + return parent; +} + +bool CefXmlObject::HasValue() +{ + AutoLock lock_scope(this); + return !value_.empty(); +} + +std::wstring CefXmlObject::GetValue() +{ + std::wstring value; + { + AutoLock lock_scope(this); + value = value_; + } + return value; +} + +bool CefXmlObject::SetValue(const std::wstring& value) +{ + AutoLock lock_scope(this); + DCHECK(children_.empty()); + if (!children_.empty()) + return false; + value_ = value; + return true; +} + +bool CefXmlObject::HasAttributes() +{ + AutoLock lock_scope(this); + return !attributes_.empty(); +} + +size_t CefXmlObject::GetAttributeCount() +{ + AutoLock lock_scope(this); + return attributes_.size(); +} + +bool CefXmlObject::HasAttribute(const std::wstring& name) +{ + if (name.empty()) + return false; + + AutoLock lock_scope(this); + AttributeMap::const_iterator it = attributes_.find(name); + return (it != attributes_.end()); +} + +std::wstring CefXmlObject::GetAttributeValue(const std::wstring& name) +{ + DCHECK(!name.empty()); + std::wstring value; + if (!name.empty()) { + AutoLock lock_scope(this); + AttributeMap::const_iterator it = attributes_.find(name); + if (it != attributes_.end()) + value = it->second; + } + return value; +} + +bool CefXmlObject::SetAttributeValue(const std::wstring& name, + const std::wstring& value) +{ + DCHECK(!name.empty()); + if (name.empty()) + return false; + + AutoLock lock_scope(this); + AttributeMap::iterator it = attributes_.find(name); + if (it != attributes_.end()) { + it->second = value; + } else { + attributes_.insert( + std::make_pair(name, value)); + } + return true; +} + +size_t CefXmlObject::GetAttributes(AttributeMap& attributes) +{ + AutoLock lock_scope(this); + attributes = attributes_; + return attributes_.size(); +} + +void CefXmlObject::ClearAttributes() +{ + AutoLock lock_scope(this); + attributes_.clear(); +} + +bool CefXmlObject::HasChildren() +{ + AutoLock lock_scope(this); + return !children_.empty(); +} + +size_t CefXmlObject::GetChildCount() +{ + AutoLock lock_scope(this); + return children_.size(); +} + +bool CefXmlObject::HasChild(CefRefPtr child) +{ + DCHECK(child.get()); + + AutoLock lock_scope(this); + ObjectVector::const_iterator it = children_.begin(); + for (; it != children_.end(); ++it) { + if ((*it).get() == child.get()) + return true; + } + return false; +} + +bool CefXmlObject::AddChild(CefRefPtr child) +{ + DCHECK(child.get()); + if (!child.get()) + return false; + + AutoLock lock_scope1(child); + + DCHECK(child->GetParent() == NULL); + if (child->GetParent() != NULL) + return false; + + AutoLock lock_scope2(this); + + children_.push_back(child); + child->SetParent(this); + return true; +} + +bool CefXmlObject::RemoveChild(CefRefPtr child) +{ + DCHECK(child.get()); + + AutoLock lock_scope(this); + ObjectVector::iterator it = children_.begin(); + for (; it != children_.end(); ++it) { + if ((*it).get() == child.get()) { + children_.erase(it); + child->SetParent(NULL); + return true; + } + } + return false; +} + +size_t CefXmlObject::GetChildren(ObjectVector& children) +{ + AutoLock lock_scope(this); + children = children_; + return children_.size(); +} + +void CefXmlObject::ClearChildren() +{ + AutoLock lock_scope(this); + ObjectVector::iterator it = children_.begin(); + for (; it != children_.end(); ++it) + (*it)->SetParent(NULL); + children_.clear(); +} + +CefRefPtr CefXmlObject::FindChild(const std::wstring& name) +{ + DCHECK(!name.empty()); + if (name.empty()) + return NULL; + + AutoLock lock_scope(this); + ObjectVector::const_iterator it = children_.begin(); + for (; it != children_.end(); ++it) { + if((*it)->GetName() == name) + return (*it); + } + return NULL; +} + +size_t CefXmlObject::FindChildren(const std::wstring& name, + ObjectVector& children) +{ + DCHECK(!name.empty()); + if (name.empty()) + return 0; + + size_t ct = 0; + + AutoLock lock_scope(this); + ObjectVector::const_iterator it = children_.begin(); + for (; it != children_.end(); ++it) { + if((*it)->GetName() == name) { + children.push_back(*it); + ct++; + } + } + return ct; +} + +void CefXmlObject::SetParent(CefXmlObject* parent) +{ + AutoLock lock_scope(this); + if (parent) { + DCHECK(parent_ == NULL); + parent_ = parent; + } else { + DCHECK(parent_ != NULL); + parent_ = NULL; + } +} diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index 0078503d0..b11e786e4 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. @@ -21,6 +21,7 @@ #include "libcef_dll/ctocpp/stream_reader_ctocpp.h" #include "libcef_dll/ctocpp/stream_writer_ctocpp.h" #include "libcef_dll/ctocpp/v8value_ctocpp.h" +#include "libcef_dll/ctocpp/xml_reader_ctocpp.h" bool CefInitialize(bool multi_threaded_message_loop, @@ -50,6 +51,7 @@ void CefShutdown() DCHECK(CefStreamReaderCToCpp::DebugObjCt == 0); DCHECK(CefStreamWriterCToCpp::DebugObjCt == 0); DCHECK(CefV8ValueCToCpp::DebugObjCt == 0); + DCHECK(CefXmlReaderCToCpp::DebugObjCt == 0); #endif // _DEBUG } diff --git a/tests/unittests/xml_reader_unittest.cc b/tests/unittests/xml_reader_unittest.cc new file mode 100644 index 000000000..98abfa1d8 --- /dev/null +++ b/tests/unittests/xml_reader_unittest.cc @@ -0,0 +1,644 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "include/cef.h" +#include "include/cef_wrapper.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +char g_test_xml[] = + "\n" + "\n" + "\n" + " \n" + "]>\n" + "\n" + " value A\n" + " \n" + " \n" + " value B1\n" + " data]]>\n" + " &EB;\n" + " this is mixed content &EA;\n" + " \n" + " \n" + "\n"; + +} // namespace + +// Test XML reading +TEST(XmlReaderTest, Read) +{ + // Create the stream reader. + CefRefPtr stream( + CefStreamReader::CreateForData(g_test_xml, sizeof(g_test_xml) - 1)); + ASSERT_TRUE(stream.get() != NULL); + + // Create the XML reader. + CefRefPtr reader( + CefXmlReader::Create(stream, XML_ENCODING_NONE, + L"http://www.example.org/example.xml")); + ASSERT_TRUE(reader.get() != NULL); + + // Move to the processing instruction node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 0); + ASSERT_EQ(reader->GetType(), XML_NODE_PROCESSING_INSTRUCTION); + ASSERT_EQ(reader->GetLocalName(), L"my_instruction"); + ASSERT_EQ(reader->GetQualifiedName(), L"my_instruction"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_EQ(reader->GetValue(), L"my_value"); + + // Move to the DOCTYPE node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 0); + ASSERT_EQ(reader->GetType(), XML_NODE_DOCUMENT_TYPE); + ASSERT_EQ(reader->GetLocalName(), L"my_document"); + ASSERT_EQ(reader->GetQualifiedName(), L"my_document"); + ASSERT_FALSE(reader->HasValue()); + + // Move to ns:obj element start node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 0); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"obj"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:obj"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_TRUE(reader->HasAttributes()); + ASSERT_EQ(reader->GetAttributeCount(), 1); + ASSERT_EQ(reader->GetAttribute(0), L"http://www.example.org/ns"); + ASSERT_EQ(reader->GetAttribute(L"xmlns:ns"), L"http://www.example.org/ns"); + ASSERT_EQ(reader->GetAttribute(L"ns", L"http://www.w3.org/2000/xmlns/"), + L"http://www.example.org/ns"); + + // Move to the whitespace node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to the ns:objA element start node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"objA"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objA"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the ns:objA value node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_TEXT); + ASSERT_EQ(reader->GetLocalName(), L"#text"); + ASSERT_EQ(reader->GetQualifiedName(), L"#text"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_EQ(reader->GetValue(), L"value A"); + + // Move to the ns:objA element ending node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END); + ASSERT_EQ(reader->GetLocalName(), L"objA"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objA"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the whitespace node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to the comment node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_COMMENT); + ASSERT_EQ(reader->GetLocalName(), L"#comment"); + ASSERT_EQ(reader->GetQualifiedName(), L"#comment"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_EQ(reader->GetValue(), L" my comment "); + + // Move to the whitespace node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to the ns:objB element start node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"objB"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the whitespace node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to the ns:objB_1 element start node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"objB_1"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB_1"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the ns:objB_1 value node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 3); + ASSERT_EQ(reader->GetType(), XML_NODE_TEXT); + ASSERT_TRUE(reader->HasValue()); + ASSERT_EQ(reader->GetValue(), L"value B1"); + + // Move to the ns:objB_1 element ending node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END); + ASSERT_EQ(reader->GetLocalName(), L"objB_1"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB_1"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the whitespace node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to the ns:objB_2 element start node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"objB_2"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB_2"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the ns:objB_2 value node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 3); + ASSERT_EQ(reader->GetType(), XML_NODE_CDATA); + ASSERT_TRUE(reader->HasValue()); + ASSERT_EQ(reader->GetValue(), L"some
data"); + + // Move to the ns:objB_2 element ending node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END); + ASSERT_EQ(reader->GetLocalName(), L"objB_2"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB_2"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the whitespace node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to the ns:objB_3 element start node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"objB_3"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB_3"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the EB entity reference node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 3); + ASSERT_EQ(reader->GetType(), XML_NODE_ENTITY_REFERENCE); + ASSERT_EQ(reader->GetLocalName(), L"EB"); + ASSERT_EQ(reader->GetQualifiedName(), L"EB"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_EQ(reader->GetValue(), L"EB Value"); + + // Move to the ns:objB_3 element ending node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END); + ASSERT_EQ(reader->GetLocalName(), L"objB_3"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB_3"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the whitespace node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to the ns:objB_4 element start node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"objB_4"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB_4"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + ASSERT_EQ(reader->GetInnerXml(), L"this is mixed content &EA;"); + ASSERT_EQ(reader->GetOuterXml(), + L"" + L"this is mixed content &EA;"); + + // Move to the element node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 3); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"b"); + ASSERT_EQ(reader->GetQualifiedName(), L"b"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the text node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 4); + ASSERT_EQ(reader->GetType(), XML_NODE_TEXT); + ASSERT_EQ(reader->GetLocalName(), L"#text"); + ASSERT_EQ(reader->GetQualifiedName(), L"#text"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_EQ(reader->GetValue(), L"this is"); + + // Move to the element node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 3); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END); + ASSERT_EQ(reader->GetLocalName(), L"b"); + ASSERT_EQ(reader->GetQualifiedName(), L"b"); + + // Move to the text node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 3); + ASSERT_EQ(reader->GetType(), XML_NODE_TEXT); + ASSERT_EQ(reader->GetLocalName(), L"#text"); + ASSERT_EQ(reader->GetQualifiedName(), L"#text"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_EQ(reader->GetValue(), L" mixed content "); + + // Move to the EA entity reference node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 3); + ASSERT_EQ(reader->GetType(), XML_NODE_ENTITY_REFERENCE); + ASSERT_EQ(reader->GetLocalName(), L"EA"); + ASSERT_EQ(reader->GetQualifiedName(), L"EA"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_EQ(reader->GetValue(), L"EA Value"); + + // Move to the ns:objB_4 element ending node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END); + ASSERT_EQ(reader->GetLocalName(), L"objB_4"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB_4"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the whitespace node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to the ns:objB element ending node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END); + ASSERT_EQ(reader->GetLocalName(), L"objB"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objB"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the whitespace node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to the ns:objC element start node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"objC"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objC"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_TRUE(reader->IsEmptyElement()); + ASSERT_TRUE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + ASSERT_EQ(reader->GetAttributeCount(), 2); + ASSERT_EQ(reader->GetAttribute(0), L"value C1"); + ASSERT_EQ(reader->GetAttribute(L"ns:attr1"), L"value C1"); + ASSERT_EQ(reader->GetAttribute(L"attr1", L"http://www.example.org/ns"), + L"value C1"); + ASSERT_EQ(reader->GetAttribute(1), L"value C2"); + ASSERT_EQ(reader->GetAttribute(L"ns:attr2"), L"value C2"); + ASSERT_EQ(reader->GetAttribute(L"attr2", L"http://www.example.org/ns"), + L"value C2"); + + // Move to the ns:attr1 attribute. + ASSERT_TRUE(reader->MoveToFirstAttribute()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE); + ASSERT_EQ(reader->GetLocalName(), L"attr1"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:attr1"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_EQ(reader->GetValue(), L"value C1"); + + // Move to the ns:attr2 attribute. + ASSERT_TRUE(reader->MoveToNextAttribute()); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE); + ASSERT_EQ(reader->GetLocalName(), L"attr2"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:attr2"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_EQ(reader->GetValue(), L"value C2"); + + // No more attributes. + ASSERT_FALSE(reader->MoveToNextAttribute()); + + // Return to the ns:objC element start node. + ASSERT_TRUE(reader->MoveToCarryingElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objC"); + + // Move to the ns:attr1 attribute. + ASSERT_TRUE(reader->MoveToAttribute(0)); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE); + ASSERT_EQ(reader->GetLocalName(), L"attr1"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:attr1"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_EQ(reader->GetValue(), L"value C1"); + + // Return to the ns:objC element start node. + ASSERT_TRUE(reader->MoveToCarryingElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objC"); + + // Move to the ns:attr2 attribute. + ASSERT_TRUE(reader->MoveToAttribute(L"ns:attr2")); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE); + ASSERT_EQ(reader->GetLocalName(), L"attr2"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:attr2"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_EQ(reader->GetValue(), L"value C2"); + + // Move to the ns:attr1 attribute without returning to the ns:objC element. + ASSERT_TRUE(reader->MoveToAttribute(L"attr1", L"http://www.example.org/ns")); + ASSERT_EQ(reader->GetDepth(), 2); + ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE); + ASSERT_EQ(reader->GetLocalName(), L"attr1"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:attr1"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_TRUE(reader->HasValue()); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_EQ(reader->GetValue(), L"value C1"); + + // Move to the ns:objD element start node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START); + ASSERT_EQ(reader->GetLocalName(), L"objD"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objD"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the ns:objD element end node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 1); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END); + ASSERT_EQ(reader->GetLocalName(), L"objD"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:objD"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_FALSE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + + // Move to the whitespace node without returning to the ns:objC element. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE); + + // Move to ns:obj element ending node. + ASSERT_TRUE(reader->MoveToNextElement()); + ASSERT_EQ(reader->GetDepth(), 0); + ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END); + ASSERT_EQ(reader->GetLocalName(), L"obj"); + ASSERT_EQ(reader->GetPrefix(), L"ns"); + ASSERT_EQ(reader->GetQualifiedName(), L"ns:obj"); + ASSERT_EQ(reader->GetNamespaceURI(), L"http://www.example.org/ns"); + ASSERT_FALSE(reader->IsEmptyElement()); + ASSERT_TRUE(reader->HasAttributes()); + ASSERT_FALSE(reader->HasValue()); + // Strangely, the end node will report if the starting node has attributes + // but will not provide access to them. + ASSERT_TRUE(reader->HasAttributes()); + ASSERT_EQ(reader->GetAttributeCount(), 0); + + // And we're done. + ASSERT_FALSE(reader->MoveToNextElement()); + + ASSERT_TRUE(reader->Close()); +} + +// Test XML read error handling. +TEST(XmlReaderTest, ReadError) +{ + char test_str[] = + "\n" + "\n"; + + // Create the stream reader. + CefRefPtr stream( + CefStreamReader::CreateForData(test_str, sizeof(test_str) - 1)); + ASSERT_TRUE(stream.get() != NULL); + + // Create the XML reader. + CefRefPtr reader( + CefXmlReader::Create(stream, XML_ENCODING_NONE, + L"http://www.example.org/example.xml")); + ASSERT_TRUE(reader.get() != NULL); + + // Move to the processing instruction node and generate parser error. + ASSERT_FALSE(reader->MoveToNextElement()); + ASSERT_TRUE(reader->HasError()); +} + +// Test XmlObject load behavior. +TEST(XmlReaderTest, ObjectLoad) +{ + // Create the stream reader. + CefRefPtr stream( + CefStreamReader::CreateForData(g_test_xml, sizeof(g_test_xml) - 1)); + ASSERT_TRUE(stream.get() != NULL); + + // Create the XML reader. + CefRefPtr object(new CefXmlObject(L"object")); + ASSERT_TRUE(object->Load(stream, XML_ENCODING_NONE, + L"http://www.example.org/example.xml", NULL)); + + ASSERT_FALSE(object->HasAttributes()); + ASSERT_TRUE(object->HasChildren()); + ASSERT_EQ(object->GetChildCount(), 1); + + CefRefPtr obj(object->FindChild(L"ns:obj")); + ASSERT_TRUE(obj.get()); + ASSERT_TRUE(obj->HasChildren()); + ASSERT_EQ(obj->GetChildCount(), 4); + + CefRefPtr obj_child(obj->FindChild(L"ns:objC")); + ASSERT_TRUE(obj_child.get()); + ASSERT_EQ(obj_child->GetName(), L"ns:objC"); + ASSERT_FALSE(obj_child->HasChildren()); + ASSERT_FALSE(obj_child->HasValue()); + ASSERT_TRUE(obj_child->HasAttributes()); + + CefXmlObject::ObjectVector obj_children; + ASSERT_EQ(obj->GetChildren(obj_children), 4); + ASSERT_EQ(obj_children.size(), 4); + + CefXmlObject::ObjectVector::const_iterator it = obj_children.begin(); + for (int ct = 0; it != obj_children.end(); ++it, ++ct) { + obj_child = *it; + ASSERT_TRUE(obj_child.get()); + if (ct == 0) { + // ns:objA + ASSERT_EQ(obj_child->GetName(), L"ns:objA"); + ASSERT_FALSE(obj_child->HasChildren()); + ASSERT_TRUE(obj_child->HasValue()); + ASSERT_FALSE(obj_child->HasAttributes()); + ASSERT_EQ(obj_child->GetValue(), L"value A"); + } else if (ct == 1) { + // ns:objB + ASSERT_EQ(obj_child->GetName(), L"ns:objB"); + ASSERT_TRUE(obj_child->HasChildren()); + ASSERT_FALSE(obj_child->HasValue()); + ASSERT_FALSE(obj_child->HasAttributes()); + ASSERT_EQ(obj_child->GetChildCount(), 4); + obj_child = obj_child->FindChild(L"ns:objB_4"); + ASSERT_TRUE(obj_child.get()); + ASSERT_TRUE(obj_child->HasValue()); + ASSERT_EQ(obj_child->GetValue(), + L"this is mixed content EA Value"); + } else if (ct == 2) { + // ns:objC + ASSERT_EQ(obj_child->GetName(), L"ns:objC"); + ASSERT_FALSE(obj_child->HasChildren()); + ASSERT_FALSE(obj_child->HasValue()); + ASSERT_TRUE(obj_child->HasAttributes()); + + CefXmlObject::AttributeMap attribs; + ASSERT_EQ(obj_child->GetAttributes(attribs), 2); + ASSERT_EQ(attribs.size(), 2); + ASSERT_EQ(attribs[L"ns:attr1"], L"value C1"); + ASSERT_EQ(attribs[L"ns:attr2"], L"value C2"); + + ASSERT_EQ(obj_child->GetAttributeCount(), 2); + ASSERT_TRUE(obj_child->HasAttribute(L"ns:attr1")); + ASSERT_EQ(obj_child->GetAttributeValue(L"ns:attr1"), L"value C1"); + ASSERT_TRUE(obj_child->HasAttribute(L"ns:attr2")); + ASSERT_EQ(obj_child->GetAttributeValue(L"ns:attr2"), L"value C2"); + } else if (ct == 3) { + // ns:objD + ASSERT_EQ(obj_child->GetName(), L"ns:objD"); + ASSERT_FALSE(obj_child->HasChildren()); + ASSERT_FALSE(obj_child->HasValue()); + ASSERT_FALSE(obj_child->HasAttributes()); + } + } +} + +// Test XmlObject load error handling behavior. +TEST(XmlReaderTest, ObjectLoadError) +{ + // Test start/end tag mismatch error. + { + char error_xml[] = "\n\n\n"; + + // Create the stream reader. + CefRefPtr stream( + CefStreamReader::CreateForData(error_xml, sizeof(error_xml) - 1)); + ASSERT_TRUE(stream.get() != NULL); + + std::wstring error_str; + + // Create the XML reader. + CefRefPtr object(new CefXmlObject(L"object")); + ASSERT_FALSE(object->Load(stream, XML_ENCODING_NONE, + L"http://www.example.org/example.xml", &error_str)); + ASSERT_EQ(error_str, + L"Opening and ending tag mismatch: foo line 2 and obj, line 3"); + } + + // Test value following child error. + { + char error_xml[] = "\n\ndisallowed value\n"; + + // Create the stream reader. + CefRefPtr stream( + CefStreamReader::CreateForData(error_xml, sizeof(error_xml) - 1)); + ASSERT_TRUE(stream.get() != NULL); + + std::wstring error_str; + + // Create the XML reader. + CefRefPtr object(new CefXmlObject(L"object")); + ASSERT_FALSE(object->Load(stream, XML_ENCODING_NONE, + L"http://www.example.org/example.xml", &error_str)); + ASSERT_EQ(error_str, + L"Value following child element, line 4"); + } +}