• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 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 "include/wrapper/cef_xml_object.h"
6 
7 #include <sstream>
8 
9 #include "include/base/cef_logging.h"
10 #include "include/cef_stream.h"
11 
12 namespace {
13 
14 class CefXmlObjectLoader {
15  public:
CefXmlObjectLoader(CefRefPtr<CefXmlObject> root_object)16   explicit CefXmlObjectLoader(CefRefPtr<CefXmlObject> root_object)
17       : root_object_(root_object) {}
18 
19   CefXmlObjectLoader(const CefXmlObjectLoader&) = delete;
20   CefXmlObjectLoader& operator=(const CefXmlObjectLoader&) = delete;
21 
Load(CefRefPtr<CefStreamReader> stream,CefXmlReader::EncodingType encodingType,const CefString & URI)22   bool Load(CefRefPtr<CefStreamReader> stream,
23             CefXmlReader::EncodingType encodingType,
24             const CefString& URI) {
25     CefRefPtr<CefXmlReader> reader(
26         CefXmlReader::Create(stream, encodingType, URI));
27     if (!reader.get())
28       return false;
29 
30     bool ret = reader->MoveToNextNode();
31     if (ret) {
32       CefRefPtr<CefXmlObject> cur_object(root_object_), new_object;
33       CefXmlObject::ObjectVector queue;
34       int cur_depth, value_depth = -1;
35       CefXmlReader::NodeType cur_type;
36       std::stringstream cur_value;
37       bool last_has_ns = false;
38 
39       queue.push_back(root_object_);
40 
41       do {
42         cur_depth = reader->GetDepth();
43         if (value_depth >= 0 && cur_depth > value_depth) {
44           // The current node has already been parsed as part of a value.
45           continue;
46         }
47 
48         cur_type = reader->GetType();
49         if (cur_type == XML_NODE_ELEMENT_START) {
50           if (cur_depth == value_depth) {
51             // Add to the current value.
52             cur_value << std::string(reader->GetOuterXml());
53             continue;
54           } else if (last_has_ns && reader->GetPrefix().empty()) {
55             if (!cur_object->HasChildren()) {
56               // Start a new value because the last element has a namespace and
57               // this element does not.
58               value_depth = cur_depth;
59               cur_value << std::string(reader->GetOuterXml());
60             } else {
61               // Value following a child element is not allowed.
62               std::stringstream ss;
63               ss << "Value following child element, line "
64                  << reader->GetLineNumber();
65               load_error_ = ss.str();
66               ret = false;
67               break;
68             }
69           } else {
70             // Start a new element.
71             new_object = new CefXmlObject(reader->GetQualifiedName());
72             cur_object->AddChild(new_object);
73             last_has_ns = !reader->GetPrefix().empty();
74 
75             if (!reader->IsEmptyElement()) {
76               // The new element potentially has a value and/or children, so
77               // set the current object and add the object to the queue.
78               cur_object = new_object;
79               queue.push_back(cur_object);
80             }
81 
82             if (reader->HasAttributes() && reader->MoveToFirstAttribute()) {
83               // Read all object attributes.
84               do {
85                 new_object->SetAttributeValue(reader->GetQualifiedName(),
86                                               reader->GetValue());
87               } while (reader->MoveToNextAttribute());
88               reader->MoveToCarryingElement();
89             }
90           }
91         } else if (cur_type == XML_NODE_ELEMENT_END) {
92           if (cur_depth == value_depth) {
93             // Ending an element that is already in the value.
94             continue;
95           } else if (cur_depth < value_depth) {
96             // Done with parsing the value portion of the current element.
97             cur_object->SetValue(cur_value.str());
98             cur_value.str("");
99             value_depth = -1;
100           }
101 
102           // Pop the current element from the queue.
103           queue.pop_back();
104 
105           if (queue.empty() ||
106               cur_object->GetName() != reader->GetQualifiedName()) {
107             // Open tag without close tag or close tag without open tag should
108             // never occur (the parser catches this error).
109             NOTREACHED();
110             std::stringstream ss;
111             ss << "Mismatched end tag for "
112                << std::string(cur_object->GetName()) << ", line "
113                << reader->GetLineNumber();
114             load_error_ = ss.str();
115             ret = false;
116             break;
117           }
118 
119           // Set the current object to the previous object in the queue.
120           cur_object = queue.back().get();
121         } else if (cur_type == XML_NODE_TEXT || cur_type == XML_NODE_CDATA ||
122                    cur_type == XML_NODE_ENTITY_REFERENCE) {
123           if (cur_depth == value_depth) {
124             // Add to the current value.
125             cur_value << std::string(reader->GetValue());
126           } else if (!cur_object->HasChildren()) {
127             // Start a new value.
128             value_depth = cur_depth;
129             cur_value << std::string(reader->GetValue());
130           } else {
131             // Value following a child element is not allowed.
132             std::stringstream ss;
133             ss << "Value following child element, line "
134                << reader->GetLineNumber();
135             load_error_ = ss.str();
136             ret = false;
137             break;
138           }
139         }
140       } while (reader->MoveToNextNode());
141     }
142 
143     if (reader->HasError()) {
144       load_error_ = reader->GetError();
145       return false;
146     }
147 
148     return ret;
149   }
150 
GetLoadError()151   CefString GetLoadError() { return load_error_; }
152 
153  private:
154   CefString load_error_;
155   CefRefPtr<CefXmlObject> root_object_;
156 };
157 
158 }  // namespace
159 
CefXmlObject(const CefString & name)160 CefXmlObject::CefXmlObject(const CefString& name)
161     : name_(name), parent_(nullptr) {}
162 
~CefXmlObject()163 CefXmlObject::~CefXmlObject() {}
164 
Load(CefRefPtr<CefStreamReader> stream,CefXmlReader::EncodingType encodingType,const CefString & URI,CefString * loadError)165 bool CefXmlObject::Load(CefRefPtr<CefStreamReader> stream,
166                         CefXmlReader::EncodingType encodingType,
167                         const CefString& URI,
168                         CefString* loadError) {
169   Clear();
170 
171   CefXmlObjectLoader loader(this);
172   if (!loader.Load(stream, encodingType, URI)) {
173     if (loadError)
174       *loadError = loader.GetLoadError();
175     return false;
176   }
177   return true;
178 }
179 
Set(CefRefPtr<CefXmlObject> object)180 void CefXmlObject::Set(CefRefPtr<CefXmlObject> object) {
181   DCHECK(object.get());
182 
183   Clear();
184 
185   name_ = object->GetName();
186   Append(object, true);
187 }
188 
Append(CefRefPtr<CefXmlObject> object,bool overwriteAttributes)189 void CefXmlObject::Append(CefRefPtr<CefXmlObject> object,
190                           bool overwriteAttributes) {
191   DCHECK(object.get());
192 
193   if (object->HasChildren()) {
194     ObjectVector children;
195     object->GetChildren(children);
196     ObjectVector::const_iterator it = children.begin();
197     for (; it != children.end(); ++it)
198       AddChild((*it)->Duplicate());
199   }
200 
201   if (object->HasAttributes()) {
202     AttributeMap attributes;
203     object->GetAttributes(attributes);
204     AttributeMap::const_iterator it = attributes.begin();
205     for (; it != attributes.end(); ++it) {
206       if (overwriteAttributes || !HasAttribute(it->first))
207         SetAttributeValue(it->first, it->second);
208     }
209   }
210 }
211 
Duplicate()212 CefRefPtr<CefXmlObject> CefXmlObject::Duplicate() {
213   CefRefPtr<CefXmlObject> new_obj;
214   {
215     base::AutoLock lock_scope(lock_);
216     new_obj = new CefXmlObject(name_);
217     new_obj->Append(this, true);
218   }
219   return new_obj;
220 }
221 
Clear()222 void CefXmlObject::Clear() {
223   ClearChildren();
224   ClearAttributes();
225 }
226 
GetName()227 CefString CefXmlObject::GetName() {
228   CefString name;
229   {
230     base::AutoLock lock_scope(lock_);
231     name = name_;
232   }
233   return name;
234 }
235 
SetName(const CefString & name)236 bool CefXmlObject::SetName(const CefString& name) {
237   DCHECK(!name.empty());
238   if (name.empty())
239     return false;
240 
241   base::AutoLock lock_scope(lock_);
242   name_ = name;
243   return true;
244 }
245 
HasParent()246 bool CefXmlObject::HasParent() {
247   base::AutoLock lock_scope(lock_);
248   return (parent_ != nullptr);
249 }
250 
GetParent()251 CefRefPtr<CefXmlObject> CefXmlObject::GetParent() {
252   CefRefPtr<CefXmlObject> parent;
253   {
254     base::AutoLock lock_scope(lock_);
255     parent = parent_;
256   }
257   return parent;
258 }
259 
HasValue()260 bool CefXmlObject::HasValue() {
261   base::AutoLock lock_scope(lock_);
262   return !value_.empty();
263 }
264 
GetValue()265 CefString CefXmlObject::GetValue() {
266   CefString value;
267   {
268     base::AutoLock lock_scope(lock_);
269     value = value_;
270   }
271   return value;
272 }
273 
SetValue(const CefString & value)274 bool CefXmlObject::SetValue(const CefString& value) {
275   base::AutoLock lock_scope(lock_);
276   DCHECK(children_.empty());
277   if (!children_.empty())
278     return false;
279   value_ = value;
280   return true;
281 }
282 
HasAttributes()283 bool CefXmlObject::HasAttributes() {
284   base::AutoLock lock_scope(lock_);
285   return !attributes_.empty();
286 }
287 
GetAttributeCount()288 size_t CefXmlObject::GetAttributeCount() {
289   base::AutoLock lock_scope(lock_);
290   return attributes_.size();
291 }
292 
HasAttribute(const CefString & name)293 bool CefXmlObject::HasAttribute(const CefString& name) {
294   if (name.empty())
295     return false;
296 
297   base::AutoLock lock_scope(lock_);
298   AttributeMap::const_iterator it = attributes_.find(name);
299   return (it != attributes_.end());
300 }
301 
GetAttributeValue(const CefString & name)302 CefString CefXmlObject::GetAttributeValue(const CefString& name) {
303   DCHECK(!name.empty());
304   CefString value;
305   if (!name.empty()) {
306     base::AutoLock lock_scope(lock_);
307     AttributeMap::const_iterator it = attributes_.find(name);
308     if (it != attributes_.end())
309       value = it->second;
310   }
311   return value;
312 }
313 
SetAttributeValue(const CefString & name,const CefString & value)314 bool CefXmlObject::SetAttributeValue(const CefString& name,
315                                      const CefString& value) {
316   DCHECK(!name.empty());
317   if (name.empty())
318     return false;
319 
320   base::AutoLock lock_scope(lock_);
321   AttributeMap::iterator it = attributes_.find(name);
322   if (it != attributes_.end()) {
323     it->second = value;
324   } else {
325     attributes_.insert(std::make_pair(name, value));
326   }
327   return true;
328 }
329 
GetAttributes(AttributeMap & attributes)330 size_t CefXmlObject::GetAttributes(AttributeMap& attributes) {
331   base::AutoLock lock_scope(lock_);
332   attributes = attributes_;
333   return attributes_.size();
334 }
335 
ClearAttributes()336 void CefXmlObject::ClearAttributes() {
337   base::AutoLock lock_scope(lock_);
338   attributes_.clear();
339 }
340 
HasChildren()341 bool CefXmlObject::HasChildren() {
342   base::AutoLock lock_scope(lock_);
343   return !children_.empty();
344 }
345 
GetChildCount()346 size_t CefXmlObject::GetChildCount() {
347   base::AutoLock lock_scope(lock_);
348   return children_.size();
349 }
350 
HasChild(CefRefPtr<CefXmlObject> child)351 bool CefXmlObject::HasChild(CefRefPtr<CefXmlObject> child) {
352   DCHECK(child.get());
353 
354   base::AutoLock lock_scope(lock_);
355   ObjectVector::const_iterator it = children_.begin();
356   for (; it != children_.end(); ++it) {
357     if ((*it).get() == child.get())
358       return true;
359   }
360   return false;
361 }
362 
AddChild(CefRefPtr<CefXmlObject> child)363 bool CefXmlObject::AddChild(CefRefPtr<CefXmlObject> child) {
364   DCHECK(child.get());
365   if (!child.get())
366     return false;
367 
368   CefRefPtr<CefXmlObject> parent = child->GetParent();
369   DCHECK(!parent);
370   if (parent)
371     return false;
372 
373   base::AutoLock lock_scope(lock_);
374 
375   children_.push_back(child);
376   child->SetParent(this);
377   return true;
378 }
379 
RemoveChild(CefRefPtr<CefXmlObject> child)380 bool CefXmlObject::RemoveChild(CefRefPtr<CefXmlObject> child) {
381   DCHECK(child.get());
382 
383   base::AutoLock lock_scope(lock_);
384   ObjectVector::iterator it = children_.begin();
385   for (; it != children_.end(); ++it) {
386     if ((*it).get() == child.get()) {
387       children_.erase(it);
388       child->SetParent(nullptr);
389       return true;
390     }
391   }
392   return false;
393 }
394 
GetChildren(ObjectVector & children)395 size_t CefXmlObject::GetChildren(ObjectVector& children) {
396   base::AutoLock lock_scope(lock_);
397   children = children_;
398   return children_.size();
399 }
400 
ClearChildren()401 void CefXmlObject::ClearChildren() {
402   base::AutoLock lock_scope(lock_);
403   ObjectVector::iterator it = children_.begin();
404   for (; it != children_.end(); ++it)
405     (*it)->SetParent(nullptr);
406   children_.clear();
407 }
408 
FindChild(const CefString & name)409 CefRefPtr<CefXmlObject> CefXmlObject::FindChild(const CefString& name) {
410   DCHECK(!name.empty());
411   if (name.empty())
412     return nullptr;
413 
414   base::AutoLock lock_scope(lock_);
415   ObjectVector::const_iterator it = children_.begin();
416   for (; it != children_.end(); ++it) {
417     if ((*it)->GetName() == name)
418       return (*it);
419   }
420   return nullptr;
421 }
422 
FindChildren(const CefString & name,ObjectVector & children)423 size_t CefXmlObject::FindChildren(const CefString& name,
424                                   ObjectVector& children) {
425   DCHECK(!name.empty());
426   if (name.empty())
427     return 0;
428 
429   size_t ct = 0;
430 
431   base::AutoLock lock_scope(lock_);
432   ObjectVector::const_iterator it = children_.begin();
433   for (; it != children_.end(); ++it) {
434     if ((*it)->GetName() == name) {
435       children.push_back(*it);
436       ct++;
437     }
438   }
439   return ct;
440 }
441 
SetParent(CefXmlObject * parent)442 void CefXmlObject::SetParent(CefXmlObject* parent) {
443   base::AutoLock lock_scope(lock_);
444   if (parent) {
445     DCHECK(parent_ == nullptr);
446     parent_ = parent;
447   } else {
448     DCHECK(parent_ != nullptr);
449     parent_ = nullptr;
450   }
451 }
452