blob: 5a18a6f3e0b63a8b1044e1ebd34c99a66835b3dc [file] [log] [blame]
// 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 "base/logging.h"
#include "include/cef_stream.h"
// Static functions
// static
CefRefPtr<CefXmlReader> CefXmlReader::Create(CefRefPtr<CefStreamReader> stream,
EncodingType encodingType,
const CefString& URI) {
CefRefPtr<CefXmlReaderImpl> 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<CefStreamReader> reader(static_cast<CefStreamReader*>(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<CefXmlReaderImpl> impl(static_cast<CefXmlReaderImpl*>(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<CefXmlReaderImpl> impl(static_cast<CefXmlReaderImpl*>(userData));
impl->AppendError(ss.str());
}
CefString xmlCharToString(const xmlChar* xmlStr, bool free) {
if (!xmlStr)
return CefString();
const char* str = reinterpret_cast<const char*>(xmlStr);
CefString wstr = std::string(str);
if (free)
xmlFree(const_cast<xmlChar*>(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<CefStreamReader> 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;
}
bool CefXmlReaderImpl::VerifyContext() {
if (base::PlatformThread::CurrentId() != supported_thread_id_) {
// This object should only be accessed from the thread that created it.
NOTREACHED();
return false;
}
return (reader_ != nullptr);
}