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