18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// found in the LICENSE file.
48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/utility/media_galleries/iapps_xml_utils.h"
68bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/logging.h"
88bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/stl_util.h"
98bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "third_party/libxml/chromium/libxml_utils.h"
118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace iapps {
138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool SkipToNextElement(XmlReader* reader) {
158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!reader->SkipToElement()) {
168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // SkipToElement returns false if the current node is an end element,
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // try to advance to the next element and then try again.
188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!reader->Read() || !reader->SkipToElement())
198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return false;
208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return true;
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool SeekToNodeAtCurrentDepth(XmlReader* reader, const std::string& name) {
258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int depth = reader->Depth();
268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  do {
278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!SkipToNextElement(reader) || reader->Depth() < depth)
288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return false;
298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DCHECK_EQ(depth, reader->Depth());
308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (reader->NodeName() == name)
318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return true;
328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  } while (reader->Next());
338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return false;
358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool SeekInDict(XmlReader* reader, const std::string& key) {
388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK_EQ("dict", reader->NodeName());
398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int dict_content_depth = reader->Depth() + 1;
418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Advance past the dict node and into the body of the dictionary.
428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!reader->Read())
438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  while (reader->Depth() >= dict_content_depth) {
468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!SeekToNodeAtCurrentDepth(reader, "key"))
478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return false;
488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    std::string found_key;
498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!reader->ReadElementContent(&found_key))
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return false;
518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DCHECK_EQ(dict_content_depth, reader->Depth());
528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (found_key == key)
538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return true;
548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return false;
568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Seek to the start of a tag and read the value into |result| if the node's
598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// name is |node_name|.
608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ReadSimpleValue(XmlReader* reader, const std::string& node_name,
618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                     std::string* result) {
628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!iapps::SkipToNextElement(reader))
638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return false;
648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (reader->NodeName() != node_name)
658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return reader->ReadElementContent(result);
678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ReadString(XmlReader* reader, std::string* result) {
708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return ReadSimpleValue(reader, "string", result);
718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ReadInteger(XmlReader* reader, uint64* result) {
748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::string value;
758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!ReadSimpleValue(reader, "integer", &value))
768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return base::StringToUint64(value, result);
788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liustd::string ReadFileAsString(base::File file) {
818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::string result;
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!file.IsValid())
838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return result;
848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // A "reasonable" artificial limit.
868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // TODO(vandebo): Add a UMA to figure out what common values are.
878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const int64 kMaxLibraryFileSize = 150 * 1024 * 1024;
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::File::Info file_info;
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!file.GetInfo(&file_info) || file_info.size > kMaxLibraryFileSize)
908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return result;
918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  result.resize(file_info.size);
935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  int bytes_read = file.Read(0, string_as_array(&result), file_info.size);
948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (bytes_read != file_info.size)
958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    result.clear();
968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return result;
988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)XmlDictReader::XmlDictReader(XmlReader* reader) : reader_(reader) {}
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)XmlDictReader::~XmlDictReader() {}
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool XmlDictReader::Read() {
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (reader_->NodeName() != "dict")
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int dict_content_depth = reader_->Depth() + 1;
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Advance past the dict node and into the body of the dictionary.
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!reader_->Read())
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (reader_->Depth() >= dict_content_depth && ShouldLoop()) {
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!iapps::SeekToNodeAtCurrentDepth(reader_, "key"))
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    std::string found_key;
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!reader_->ReadElementContent(&found_key))
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DCHECK_EQ(dict_content_depth, reader_->Depth());
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!HandleKey(found_key))
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Seek to the end of the dictionary. Bail on end or error.
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (reader_->Depth() >= dict_content_depth && reader_->Next()) {
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return FinishedOk();
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool XmlDictReader::ShouldLoop() {
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool XmlDictReader::HandleKey(const std::string& key) {
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (Found(key))
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return AllowRepeats();
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (HandleKeyImpl(key)) {
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    found_.insert(key);
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return true;
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return false;
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool XmlDictReader::AllowRepeats() {
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return false;
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool XmlDictReader::FinishedOk() {
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool XmlDictReader::SkipToNext() {
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return SkipToNextElement(reader_) && reader_->Next();
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool XmlDictReader::Found(const std::string& key) const {
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return ContainsKey(found_, key);
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}  // namespace iapps
161