• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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