1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/utility/media_galleries/iapps_xml_utils.h" 6 7 #include "base/logging.h" 8 #include "base/stl_util.h" 9 #include "base/strings/string_number_conversions.h" 10 #include "third_party/libxml/chromium/libxml_utils.h" 11 12 namespace iapps { 13 14 bool SkipToNextElement(XmlReader* reader) { 15 if (!reader->SkipToElement()) { 16 // SkipToElement returns false if the current node is an end element, 17 // try to advance to the next element and then try again. 18 if (!reader->Read() || !reader->SkipToElement()) 19 return false; 20 } 21 return true; 22 } 23 24 bool SeekToNodeAtCurrentDepth(XmlReader* reader, const std::string& name) { 25 int depth = reader->Depth(); 26 do { 27 if (!SkipToNextElement(reader) || reader->Depth() < depth) 28 return false; 29 DCHECK_EQ(depth, reader->Depth()); 30 if (reader->NodeName() == name) 31 return true; 32 } while (reader->Next()); 33 34 return false; 35 } 36 37 bool SeekInDict(XmlReader* reader, const std::string& key) { 38 DCHECK_EQ("dict", reader->NodeName()); 39 40 int dict_content_depth = reader->Depth() + 1; 41 // Advance past the dict node and into the body of the dictionary. 42 if (!reader->Read()) 43 return false; 44 45 while (reader->Depth() >= dict_content_depth) { 46 if (!SeekToNodeAtCurrentDepth(reader, "key")) 47 return false; 48 std::string found_key; 49 if (!reader->ReadElementContent(&found_key)) 50 return false; 51 DCHECK_EQ(dict_content_depth, reader->Depth()); 52 if (found_key == key) 53 return true; 54 } 55 return false; 56 } 57 58 // Seek to the start of a tag and read the value into |result| if the node's 59 // name is |node_name|. 60 bool ReadSimpleValue(XmlReader* reader, const std::string& node_name, 61 std::string* result) { 62 if (!iapps::SkipToNextElement(reader)) 63 return false; 64 if (reader->NodeName() != node_name) 65 return false; 66 return reader->ReadElementContent(result); 67 } 68 69 bool ReadString(XmlReader* reader, std::string* result) { 70 return ReadSimpleValue(reader, "string", result); 71 } 72 73 bool ReadInteger(XmlReader* reader, uint64* result) { 74 std::string value; 75 if (!ReadSimpleValue(reader, "integer", &value)) 76 return false; 77 return base::StringToUint64(value, result); 78 } 79 80 std::string ReadFileAsString(base::File file) { 81 std::string result; 82 if (!file.IsValid()) 83 return result; 84 85 // A "reasonable" artificial limit. 86 // TODO(vandebo): Add a UMA to figure out what common values are. 87 const int64 kMaxLibraryFileSize = 150 * 1024 * 1024; 88 base::File::Info file_info; 89 if (!file.GetInfo(&file_info) || file_info.size > kMaxLibraryFileSize) 90 return result; 91 92 result.resize(file_info.size); 93 int bytes_read = file.Read(0, string_as_array(&result), file_info.size); 94 if (bytes_read != file_info.size) 95 result.clear(); 96 97 return result; 98 } 99 100 XmlDictReader::XmlDictReader(XmlReader* reader) : reader_(reader) {} 101 102 XmlDictReader::~XmlDictReader() {} 103 104 bool XmlDictReader::Read() { 105 if (reader_->NodeName() != "dict") 106 return false; 107 108 int dict_content_depth = reader_->Depth() + 1; 109 // Advance past the dict node and into the body of the dictionary. 110 if (!reader_->Read()) 111 return false; 112 113 while (reader_->Depth() >= dict_content_depth && ShouldLoop()) { 114 if (!iapps::SeekToNodeAtCurrentDepth(reader_, "key")) 115 break; 116 std::string found_key; 117 if (!reader_->ReadElementContent(&found_key)) 118 break; 119 DCHECK_EQ(dict_content_depth, reader_->Depth()); 120 121 if (!HandleKey(found_key)) 122 break; 123 } 124 // Seek to the end of the dictionary. Bail on end or error. 125 while (reader_->Depth() >= dict_content_depth && reader_->Next()) { 126 } 127 return FinishedOk(); 128 } 129 130 bool XmlDictReader::ShouldLoop() { 131 return true; 132 } 133 134 bool XmlDictReader::HandleKey(const std::string& key) { 135 if (Found(key)) 136 return AllowRepeats(); 137 if (HandleKeyImpl(key)) { 138 found_.insert(key); 139 return true; 140 } 141 return false; 142 } 143 144 bool XmlDictReader::AllowRepeats() { 145 return false; 146 } 147 148 bool XmlDictReader::FinishedOk() { 149 return true; 150 } 151 152 bool XmlDictReader::SkipToNext() { 153 return SkipToNextElement(reader_) && reader_->Next(); 154 } 155 156 bool XmlDictReader::Found(const std::string& key) const { 157 return ContainsKey(found_, key); 158 } 159 160 } // namespace iapps 161