// Copyright (c) 2012 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 "libcef/browser/xml_reader_impl.h" #include "include/cef_stream.h" #include "base/logging.h" #include "base/notreached.h" // Static functions // static CefRefPtr CefXmlReader::Create(CefRefPtr stream, EncodingType encodingType, const CefString& URI) { CefRefPtr impl(new CefXmlReaderImpl()); if (!impl->Initialize(stream, encodingType, URI)) { return nullptr; } 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); } /** * 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::string error_str(msg); if (!error_str.empty() && error_str[error_str.length() - 1] == '\n') { error_str.resize(error_str.length() - 1); } std::stringstream ss; ss << error_str << ", 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::string error_str(error->message); if (!error_str.empty() && error_str[error_str.length() - 1] == '\n') { error_str.resize(error_str.length() - 1); } std::stringstream ss; ss << error_str << ", line " << error->line; LOG(INFO) << ss.str(); CefRefPtr impl(static_cast(userData)); impl->AppendError(ss.str()); } CefString xmlCharToString(const xmlChar* xmlStr, bool free) { if (!xmlStr) { return CefString(); } const char* str = reinterpret_cast(xmlStr); CefString wstr = std::string(str); if (free) { xmlFree(const_cast(xmlStr)); } return wstr; } } // namespace CefXmlReaderImpl::CefXmlReaderImpl() : supported_thread_id_(base::PlatformThread::CurrentId()), reader_(nullptr) {} CefXmlReaderImpl::~CefXmlReaderImpl() { if (reader_ != nullptr) { 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 CefString& 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; } input_buffer->context = stream.get(); input_buffer->readcallback = xml_read_callback; // Create the text reader. std::string uriStr = URI; reader_ = xmlNewTextReader(input_buffer, uriStr.c_str()); if (!reader_) { // Free the input buffer. xmlFreeParserInputBuffer(input_buffer); return false; } // Keep a reference to the stream. stream_ = stream; // Register the error callbacks. xmlTextReaderSetErrorHandler(reader_, xml_error_callback, this); xmlTextReaderSetStructuredErrorHandler(reader_, xml_structured_error_callback, this); return true; } bool CefXmlReaderImpl::MoveToNextNode() { 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_ = nullptr; return true; } bool CefXmlReaderImpl::HasError() { if (!VerifyContext()) { return false; } return !error_buf_.str().empty(); } CefString CefXmlReaderImpl::GetError() { if (!VerifyContext()) { return CefString(); } 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_); } CefString CefXmlReaderImpl::GetLocalName() { if (!VerifyContext()) { return CefString(); } return xmlCharToString(xmlTextReaderConstLocalName(reader_), false); } CefString CefXmlReaderImpl::GetPrefix() { if (!VerifyContext()) { return CefString(); } return xmlCharToString(xmlTextReaderConstPrefix(reader_), false); } CefString CefXmlReaderImpl::GetQualifiedName() { if (!VerifyContext()) { return CefString(); } return xmlCharToString(xmlTextReaderConstName(reader_), false); } CefString CefXmlReaderImpl::GetNamespaceURI() { if (!VerifyContext()) { return CefString(); } return xmlCharToString(xmlTextReaderConstNamespaceUri(reader_), false); } CefString CefXmlReaderImpl::GetBaseURI() { if (!VerifyContext()) { return CefString(); } return xmlCharToString(xmlTextReaderConstBaseUri(reader_), false); } CefString CefXmlReaderImpl::GetXmlLang() { if (!VerifyContext()) { return CefString(); } return xmlCharToString(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; } } CefString CefXmlReaderImpl::GetValue() { if (!VerifyContext()) { return CefString(); } if (xmlTextReaderNodeType(reader_) == XML_READER_TYPE_ENTITY_REFERENCE) { // Provide special handling to return entity reference values. xmlNodePtr node = xmlTextReaderCurrentNode(reader_); if (node->content != nullptr) { return xmlCharToString(node->content, false); } return CefString(); } else { return xmlCharToString(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_); } CefString CefXmlReaderImpl::GetAttribute(int index) { if (!VerifyContext()) { return CefString(); } return xmlCharToString(xmlTextReaderGetAttributeNo(reader_, index), true); } CefString CefXmlReaderImpl::GetAttribute(const CefString& qualifiedName) { if (!VerifyContext()) { return CefString(); } std::string qualifiedNameStr = qualifiedName; return xmlCharToString( xmlTextReaderGetAttribute(reader_, BAD_CAST qualifiedNameStr.c_str()), true); } CefString CefXmlReaderImpl::GetAttribute(const CefString& localName, const CefString& namespaceURI) { if (!VerifyContext()) { return CefString(); } std::string localNameStr = localName; std::string namespaceURIStr = namespaceURI; return xmlCharToString( xmlTextReaderGetAttributeNs(reader_, BAD_CAST localNameStr.c_str(), BAD_CAST namespaceURIStr.c_str()), true); } CefString CefXmlReaderImpl::GetInnerXml() { if (!VerifyContext()) { return CefString(); } return xmlCharToString(xmlTextReaderReadInnerXml(reader_), true); } CefString CefXmlReaderImpl::GetOuterXml() { if (!VerifyContext()) { return CefString(); } return xmlCharToString(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 CefString& qualifiedName) { if (!VerifyContext()) { return false; } std::string qualifiedNameStr = qualifiedName; return xmlTextReaderMoveToAttribute(reader_, BAD_CAST qualifiedNameStr.c_str()) == 1 ? true : false; } bool CefXmlReaderImpl::MoveToAttribute(const CefString& localName, const CefString& namespaceURI) { if (!VerifyContext()) { return false; } std::string localNameStr = localName; std::string namespaceURIStr = 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 CefString& error_str) { if (!error_buf_.str().empty()) { error_buf_ << L"\n"; } error_buf_ << error_str.ToString(); } bool CefXmlReaderImpl::VerifyContext() { if (base::PlatformThread::CurrentId() != supported_thread_id_) { // This object should only be accessed from the thread that created it. DCHECK(false); return false; } return (reader_ != nullptr); }