1 // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "libcef/browser/xml_reader_impl.h"
6
7 #include "include/cef_stream.h"
8
9 #include "base/logging.h"
10 #include "base/notreached.h"
11
12 // Static functions
13
14 // static
Create(CefRefPtr<CefStreamReader> stream,EncodingType encodingType,const CefString & URI)15 CefRefPtr<CefXmlReader> CefXmlReader::Create(CefRefPtr<CefStreamReader> stream,
16 EncodingType encodingType,
17 const CefString& URI) {
18 CefRefPtr<CefXmlReaderImpl> impl(new CefXmlReaderImpl());
19 if (!impl->Initialize(stream, encodingType, URI))
20 return nullptr;
21 return impl.get();
22 }
23
24 // CefXmlReaderImpl
25
26 namespace {
27
28 /**
29 * xmlInputReadCallback:
30 * @context: an Input context
31 * @buffer: the buffer to store data read
32 * @len: the length of the buffer in bytes
33 *
34 * Callback used in the I/O Input API to read the resource
35 *
36 * Returns the number of bytes read or -1 in case of error
37 */
xml_read_callback(void * context,char * buffer,int len)38 int XMLCALL xml_read_callback(void* context, char* buffer, int len) {
39 CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(context));
40 return reader->Read(buffer, 1, len);
41 }
42
43 /**
44 * xmlTextReaderErrorFunc:
45 * @arg: the user argument
46 * @msg: the message
47 * @severity: the severity of the error
48 * @locator: a locator indicating where the error occured
49 *
50 * Signature of an error callback from a reader parser
51 */
xml_error_callback(void * arg,const char * msg,xmlParserSeverities severity,xmlTextReaderLocatorPtr locator)52 void XMLCALL xml_error_callback(void* arg,
53 const char* msg,
54 xmlParserSeverities severity,
55 xmlTextReaderLocatorPtr locator) {
56 if (!msg)
57 return;
58
59 std::string error_str(msg);
60 if (!error_str.empty() && error_str[error_str.length() - 1] == '\n')
61 error_str.resize(error_str.length() - 1);
62
63 std::stringstream ss;
64 ss << error_str << ", line " << xmlTextReaderLocatorLineNumber(locator);
65
66 LOG(INFO) << ss.str();
67
68 CefRefPtr<CefXmlReaderImpl> impl(static_cast<CefXmlReaderImpl*>(arg));
69 impl->AppendError(ss.str());
70 }
71
72 /**
73 * xmlStructuredErrorFunc:
74 * @userData: user provided data for the error callback
75 * @error: the error being raised.
76 *
77 * Signature of the function to use when there is an error and
78 * the module handles the new error reporting mechanism.
79 */
xml_structured_error_callback(void * userData,xmlErrorPtr error)80 void XMLCALL xml_structured_error_callback(void* userData, xmlErrorPtr error) {
81 if (!error->message)
82 return;
83
84 std::string error_str(error->message);
85 if (!error_str.empty() && error_str[error_str.length() - 1] == '\n')
86 error_str.resize(error_str.length() - 1);
87
88 std::stringstream ss;
89 ss << error_str << ", line " << error->line;
90
91 LOG(INFO) << ss.str();
92
93 CefRefPtr<CefXmlReaderImpl> impl(static_cast<CefXmlReaderImpl*>(userData));
94 impl->AppendError(ss.str());
95 }
96
xmlCharToString(const xmlChar * xmlStr,bool free)97 CefString xmlCharToString(const xmlChar* xmlStr, bool free) {
98 if (!xmlStr)
99 return CefString();
100
101 const char* str = reinterpret_cast<const char*>(xmlStr);
102 CefString wstr = std::string(str);
103
104 if (free)
105 xmlFree(const_cast<xmlChar*>(xmlStr));
106
107 return wstr;
108 }
109
110 } // namespace
111
CefXmlReaderImpl()112 CefXmlReaderImpl::CefXmlReaderImpl()
113 : supported_thread_id_(base::PlatformThread::CurrentId()),
114 reader_(nullptr) {}
115
~CefXmlReaderImpl()116 CefXmlReaderImpl::~CefXmlReaderImpl() {
117 if (reader_ != nullptr) {
118 if (!VerifyContext()) {
119 // Close() is supposed to be called directly. We'll try to free the reader
120 // now on the wrong thread but there's no guarantee this call won't crash.
121 xmlFreeTextReader(reader_);
122 } else {
123 Close();
124 }
125 }
126 }
127
Initialize(CefRefPtr<CefStreamReader> stream,EncodingType encodingType,const CefString & URI)128 bool CefXmlReaderImpl::Initialize(CefRefPtr<CefStreamReader> stream,
129 EncodingType encodingType,
130 const CefString& URI) {
131 xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
132 switch (encodingType) {
133 case XML_ENCODING_UTF8:
134 enc = XML_CHAR_ENCODING_UTF8;
135 break;
136 case XML_ENCODING_UTF16LE:
137 enc = XML_CHAR_ENCODING_UTF16LE;
138 break;
139 case XML_ENCODING_UTF16BE:
140 enc = XML_CHAR_ENCODING_UTF16BE;
141 break;
142 case XML_ENCODING_ASCII:
143 enc = XML_CHAR_ENCODING_ASCII;
144 break;
145 default:
146 break;
147 }
148
149 // Create the input buffer.
150 xmlParserInputBufferPtr input_buffer = xmlAllocParserInputBuffer(enc);
151 if (!input_buffer)
152 return false;
153
154 input_buffer->context = stream.get();
155 input_buffer->readcallback = xml_read_callback;
156
157 // Create the text reader.
158 std::string uriStr = URI;
159 reader_ = xmlNewTextReader(input_buffer, uriStr.c_str());
160 if (!reader_) {
161 // Free the input buffer.
162 xmlFreeParserInputBuffer(input_buffer);
163 return false;
164 }
165
166 // Keep a reference to the stream.
167 stream_ = stream;
168
169 // Register the error callbacks.
170 xmlTextReaderSetErrorHandler(reader_, xml_error_callback, this);
171 xmlTextReaderSetStructuredErrorHandler(reader_, xml_structured_error_callback,
172 this);
173
174 return true;
175 }
176
MoveToNextNode()177 bool CefXmlReaderImpl::MoveToNextNode() {
178 if (!VerifyContext())
179 return false;
180
181 return xmlTextReaderRead(reader_) == 1 ? true : false;
182 }
183
Close()184 bool CefXmlReaderImpl::Close() {
185 if (!VerifyContext())
186 return false;
187
188 // The input buffer will be freed automatically.
189 xmlFreeTextReader(reader_);
190 reader_ = nullptr;
191 return true;
192 }
193
HasError()194 bool CefXmlReaderImpl::HasError() {
195 if (!VerifyContext())
196 return false;
197
198 return !error_buf_.str().empty();
199 }
200
GetError()201 CefString CefXmlReaderImpl::GetError() {
202 if (!VerifyContext())
203 return CefString();
204
205 return error_buf_.str();
206 }
207
GetType()208 CefXmlReader::NodeType CefXmlReaderImpl::GetType() {
209 if (!VerifyContext())
210 return XML_NODE_UNSUPPORTED;
211
212 switch (xmlTextReaderNodeType(reader_)) {
213 case XML_READER_TYPE_ELEMENT:
214 return XML_NODE_ELEMENT_START;
215 case XML_READER_TYPE_END_ELEMENT:
216 return XML_NODE_ELEMENT_END;
217 case XML_READER_TYPE_ATTRIBUTE:
218 return XML_NODE_ATTRIBUTE;
219 case XML_READER_TYPE_TEXT:
220 return XML_NODE_TEXT;
221 case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
222 case XML_READER_TYPE_WHITESPACE:
223 return XML_NODE_WHITESPACE;
224 case XML_READER_TYPE_CDATA:
225 return XML_NODE_CDATA;
226 case XML_READER_TYPE_ENTITY_REFERENCE:
227 return XML_NODE_ENTITY_REFERENCE;
228 case XML_READER_TYPE_PROCESSING_INSTRUCTION:
229 return XML_NODE_PROCESSING_INSTRUCTION;
230 case XML_READER_TYPE_COMMENT:
231 return XML_NODE_COMMENT;
232 case XML_READER_TYPE_DOCUMENT_TYPE:
233 return XML_NODE_DOCUMENT_TYPE;
234 default:
235 break;
236 }
237
238 return XML_NODE_UNSUPPORTED;
239 }
240
GetDepth()241 int CefXmlReaderImpl::GetDepth() {
242 if (!VerifyContext())
243 return -1;
244
245 return xmlTextReaderDepth(reader_);
246 }
247
GetLocalName()248 CefString CefXmlReaderImpl::GetLocalName() {
249 if (!VerifyContext())
250 return CefString();
251
252 return xmlCharToString(xmlTextReaderConstLocalName(reader_), false);
253 }
254
GetPrefix()255 CefString CefXmlReaderImpl::GetPrefix() {
256 if (!VerifyContext())
257 return CefString();
258
259 return xmlCharToString(xmlTextReaderConstPrefix(reader_), false);
260 }
261
GetQualifiedName()262 CefString CefXmlReaderImpl::GetQualifiedName() {
263 if (!VerifyContext())
264 return CefString();
265
266 return xmlCharToString(xmlTextReaderConstName(reader_), false);
267 }
268
GetNamespaceURI()269 CefString CefXmlReaderImpl::GetNamespaceURI() {
270 if (!VerifyContext())
271 return CefString();
272
273 return xmlCharToString(xmlTextReaderConstNamespaceUri(reader_), false);
274 }
275
GetBaseURI()276 CefString CefXmlReaderImpl::GetBaseURI() {
277 if (!VerifyContext())
278 return CefString();
279
280 return xmlCharToString(xmlTextReaderConstBaseUri(reader_), false);
281 }
282
GetXmlLang()283 CefString CefXmlReaderImpl::GetXmlLang() {
284 if (!VerifyContext())
285 return CefString();
286
287 return xmlCharToString(xmlTextReaderConstXmlLang(reader_), false);
288 }
289
IsEmptyElement()290 bool CefXmlReaderImpl::IsEmptyElement() {
291 if (!VerifyContext())
292 return false;
293
294 return xmlTextReaderIsEmptyElement(reader_) == 1 ? true : false;
295 }
296
HasValue()297 bool CefXmlReaderImpl::HasValue() {
298 if (!VerifyContext())
299 return false;
300
301 if (xmlTextReaderNodeType(reader_) == XML_READER_TYPE_ENTITY_REFERENCE) {
302 // Provide special handling to return entity reference values.
303 return true;
304 } else {
305 return xmlTextReaderHasValue(reader_) == 1 ? true : false;
306 }
307 }
308
GetValue()309 CefString CefXmlReaderImpl::GetValue() {
310 if (!VerifyContext())
311 return CefString();
312
313 if (xmlTextReaderNodeType(reader_) == XML_READER_TYPE_ENTITY_REFERENCE) {
314 // Provide special handling to return entity reference values.
315 xmlNodePtr node = xmlTextReaderCurrentNode(reader_);
316 if (node->content != nullptr)
317 return xmlCharToString(node->content, false);
318 return CefString();
319 } else {
320 return xmlCharToString(xmlTextReaderConstValue(reader_), false);
321 }
322 }
323
HasAttributes()324 bool CefXmlReaderImpl::HasAttributes() {
325 if (!VerifyContext())
326 return false;
327
328 return xmlTextReaderHasAttributes(reader_) == 1 ? true : false;
329 }
330
GetAttributeCount()331 size_t CefXmlReaderImpl::GetAttributeCount() {
332 if (!VerifyContext())
333 return 0;
334
335 return xmlTextReaderAttributeCount(reader_);
336 }
337
GetAttribute(int index)338 CefString CefXmlReaderImpl::GetAttribute(int index) {
339 if (!VerifyContext())
340 return CefString();
341
342 return xmlCharToString(xmlTextReaderGetAttributeNo(reader_, index), true);
343 }
344
GetAttribute(const CefString & qualifiedName)345 CefString CefXmlReaderImpl::GetAttribute(const CefString& qualifiedName) {
346 if (!VerifyContext())
347 return CefString();
348
349 std::string qualifiedNameStr = qualifiedName;
350 return xmlCharToString(
351 xmlTextReaderGetAttribute(reader_, BAD_CAST qualifiedNameStr.c_str()),
352 true);
353 }
354
GetAttribute(const CefString & localName,const CefString & namespaceURI)355 CefString CefXmlReaderImpl::GetAttribute(const CefString& localName,
356 const CefString& namespaceURI) {
357 if (!VerifyContext())
358 return CefString();
359
360 std::string localNameStr = localName;
361 std::string namespaceURIStr = namespaceURI;
362 return xmlCharToString(
363 xmlTextReaderGetAttributeNs(reader_, BAD_CAST localNameStr.c_str(),
364 BAD_CAST namespaceURIStr.c_str()),
365 true);
366 }
367
GetInnerXml()368 CefString CefXmlReaderImpl::GetInnerXml() {
369 if (!VerifyContext())
370 return CefString();
371
372 return xmlCharToString(xmlTextReaderReadInnerXml(reader_), true);
373 }
374
GetOuterXml()375 CefString CefXmlReaderImpl::GetOuterXml() {
376 if (!VerifyContext())
377 return CefString();
378
379 return xmlCharToString(xmlTextReaderReadOuterXml(reader_), true);
380 }
381
GetLineNumber()382 int CefXmlReaderImpl::GetLineNumber() {
383 if (!VerifyContext())
384 return -1;
385
386 return xmlTextReaderGetParserLineNumber(reader_);
387 }
388
MoveToAttribute(int index)389 bool CefXmlReaderImpl::MoveToAttribute(int index) {
390 if (!VerifyContext())
391 return false;
392
393 return xmlTextReaderMoveToAttributeNo(reader_, index) == 1 ? true : false;
394 }
395
MoveToAttribute(const CefString & qualifiedName)396 bool CefXmlReaderImpl::MoveToAttribute(const CefString& qualifiedName) {
397 if (!VerifyContext())
398 return false;
399
400 std::string qualifiedNameStr = qualifiedName;
401 return xmlTextReaderMoveToAttribute(reader_,
402 BAD_CAST qualifiedNameStr.c_str()) == 1
403 ? true
404 : false;
405 }
406
MoveToAttribute(const CefString & localName,const CefString & namespaceURI)407 bool CefXmlReaderImpl::MoveToAttribute(const CefString& localName,
408 const CefString& namespaceURI) {
409 if (!VerifyContext())
410 return false;
411
412 std::string localNameStr = localName;
413 std::string namespaceURIStr = namespaceURI;
414 return xmlTextReaderMoveToAttributeNs(reader_, BAD_CAST localNameStr.c_str(),
415 BAD_CAST namespaceURIStr.c_str()) == 1
416 ? true
417 : false;
418 }
419
MoveToFirstAttribute()420 bool CefXmlReaderImpl::MoveToFirstAttribute() {
421 if (!VerifyContext())
422 return false;
423
424 return xmlTextReaderMoveToFirstAttribute(reader_) == 1 ? true : false;
425 }
426
MoveToNextAttribute()427 bool CefXmlReaderImpl::MoveToNextAttribute() {
428 if (!VerifyContext())
429 return false;
430
431 return xmlTextReaderMoveToNextAttribute(reader_) == 1 ? true : false;
432 }
433
MoveToCarryingElement()434 bool CefXmlReaderImpl::MoveToCarryingElement() {
435 if (!VerifyContext())
436 return false;
437
438 return xmlTextReaderMoveToElement(reader_) == 1 ? true : false;
439 }
440
AppendError(const CefString & error_str)441 void CefXmlReaderImpl::AppendError(const CefString& error_str) {
442 if (!error_buf_.str().empty())
443 error_buf_ << L"\n";
444 error_buf_ << error_str.ToString();
445 }
446
VerifyContext()447 bool CefXmlReaderImpl::VerifyContext() {
448 if (base::PlatformThread::CurrentId() != supported_thread_id_) {
449 // This object should only be accessed from the thread that created it.
450 NOTREACHED();
451 return false;
452 }
453
454 return (reader_ != nullptr);
455 }
456