bookmark_codec.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_codec.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "googleurl/src/gurl.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kRootsKey = "roots";
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kRootFolderNameKey = "bookmark_bar";
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kOtherBookmarkFolderNameKey = "other";
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The value is left as 'synced' for historical reasons.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kMobileBookmarkFolderNameKey = "synced";
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kVersionKey = "version";
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kChecksumKey = "checksum";
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kIdKey = "id";
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kTypeKey = "type";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kNameKey = "name";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kDateAddedKey = "date_added";
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kURLKey = "url";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kDateModifiedKey = "date_modified";
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kChildrenKey = "children";
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kMetaInfo = "meta_info";
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kTypeURL = "url";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kTypeFolder = "folder";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Current version of the file.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kCurrentVersion = 1;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkCodec::BookmarkCodec()
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : ids_reassigned_(false),
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ids_valid_(true),
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      maximum_id_(0) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkCodec::~BookmarkCodec() {}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Value* BookmarkCodec::Encode(BookmarkModel* model) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Encode(model->bookmark_bar_node(),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                model->other_node(),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                model->mobile_node(),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                model->root_node()->meta_info_str());
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Value* BookmarkCodec::Encode(const BookmarkNode* bookmark_bar_node,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const BookmarkNode* other_folder_node,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const BookmarkNode* mobile_folder_node,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const std::string& model_meta_info) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_reassigned_ = false;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitializeChecksum();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* roots = new DictionaryValue();
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  roots->Set(kRootFolderNameKey, EncodeNode(bookmark_bar_node));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  roots->Set(kOtherBookmarkFolderNameKey, EncodeNode(other_folder_node));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  roots->Set(kMobileBookmarkFolderNameKey, EncodeNode(mobile_folder_node));
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_meta_info.empty())
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    roots->SetString(kMetaInfo, model_meta_info);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* main = new DictionaryValue();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  main->SetInteger(kVersionKey, kCurrentVersion);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FinalizeChecksum();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We are going to store the computed checksum. So set stored checksum to be
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the same as computed checksum.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stored_checksum_ = computed_checksum_;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  main->Set(kChecksumKey, new base::StringValue(computed_checksum_));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  main->Set(kRootsKey, roots);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return main;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkCodec::Decode(BookmarkNode* bb_node,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           BookmarkNode* other_folder_node,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           BookmarkNode* mobile_folder_node,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           int64* max_id,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const Value& value) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_.clear();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_reassigned_ = false;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_valid_ = true;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  maximum_id_ = 0;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stored_checksum_.clear();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitializeChecksum();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = DecodeHelper(bb_node, other_folder_node, mobile_folder_node,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              value);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FinalizeChecksum();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If either the checksums differ or some IDs were missing/not unique,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reassign IDs.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ids_valid_ || computed_checksum() != stored_checksum())
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReassignIDs(bb_node, other_folder_node, mobile_folder_node);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *max_id = maximum_id_ + 1;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Value* BookmarkCodec::EncodeNode(const BookmarkNode* node) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* value = new DictionaryValue();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string id = base::Int64ToString(node->id());
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->SetString(kIdKey, id);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const string16& title = node->GetTitle();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->SetString(kNameKey, title);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->SetString(kDateAddedKey,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   base::Int64ToString(node->date_added().ToInternalValue()));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_url()) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->SetString(kTypeKey, kTypeURL);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url = node->url().possibly_invalid_spec();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->SetString(kURLKey, url);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateChecksumWithUrlNode(id, title, url);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->SetString(kTypeKey, kTypeFolder);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->SetString(kDateModifiedKey,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     base::Int64ToString(node->date_folder_modified().
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   ToInternalValue()));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateChecksumWithFolderNode(id, title);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ListValue* child_values = new ListValue();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->Set(kChildrenKey, child_values);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < node->child_count(); ++i)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      child_values->Append(EncodeNode(node->GetChild(i)));
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node->meta_info_str().empty())
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->SetString(kMetaInfo, node->meta_info_str());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkCodec::DecodeHelper(BookmarkNode* bb_node,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 BookmarkNode* other_folder_node,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 BookmarkNode* mobile_folder_node,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const Value& value) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (value.GetType() != Value::TYPE_DICTIONARY)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Unexpected type.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DictionaryValue& d_value = static_cast<const DictionaryValue&>(value);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int version;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!d_value.GetInteger(kVersionKey, &version) || version != kCurrentVersion)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Unknown version.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Value* checksum_value;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (d_value.Get(kChecksumKey, &checksum_value)) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (checksum_value->GetType() != Value::TYPE_STRING)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!checksum_value->GetAsString(&stored_checksum_))
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Value* roots;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!d_value.Get(kRootsKey, &roots))
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No roots.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (roots->GetType() != Value::TYPE_DICTIONARY)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Invalid type for roots.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DictionaryValue* roots_d_value =
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<const DictionaryValue*>(roots);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Value* root_folder_value;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Value* other_folder_value = NULL;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!roots_d_value->Get(kRootFolderNameKey, &root_folder_value) ||
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      root_folder_value->GetType() != Value::TYPE_DICTIONARY ||
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !roots_d_value->Get(kOtherBookmarkFolderNameKey, &other_folder_value) ||
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      other_folder_value->GetType() != Value::TYPE_DICTIONARY) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Invalid type for root folder and/or other
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   // folder.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DecodeNode(*static_cast<const DictionaryValue*>(root_folder_value), NULL,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             bb_node);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DecodeNode(*static_cast<const DictionaryValue*>(other_folder_value), NULL,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             other_folder_node);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fail silently if we can't deserialize mobile bookmarks. We can't require
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them to exist in order to be backwards-compatible with older versions of
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // chrome.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Value* mobile_folder_value;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (roots_d_value->Get(kMobileBookmarkFolderNameKey, &mobile_folder_value) &&
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mobile_folder_value->GetType() == Value::TYPE_DICTIONARY) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DecodeNode(*static_cast<const DictionaryValue*>(mobile_folder_value), NULL,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               mobile_folder_node);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we didn't find the mobile folder, we're almost guaranteed to have a
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // duplicate id when we add the mobile folder. Consequently, if we don't
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // intend to reassign ids in the future (ids_valid_ is still true), then at
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // least reassign the mobile bookmarks to avoid it colliding with anything
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // else.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ids_valid_)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReassignIDsHelper(mobile_folder_node);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  roots_d_value->GetString(kMetaInfo, &model_meta_info_);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need to reset the type as decoding resets the type to FOLDER. Similarly
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we need to reset the title as the title is persisted and restored from
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the file.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bb_node->set_type(BookmarkNode::BOOKMARK_BAR);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_folder_node->set_type(BookmarkNode::OTHER_NODE);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mobile_folder_node->set_type(BookmarkNode::MOBILE);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bb_node->SetTitle(l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_FOLDER_NAME));
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_folder_node->SetTitle(
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME));
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mobile_folder_node->SetTitle(
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME));
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkCodec::DecodeChildren(const ListValue& child_value_list,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   BookmarkNode* parent) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < child_value_list.GetSize(); ++i) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value* child_value;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!child_value_list.Get(i, &child_value))
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (child_value->GetType() != Value::TYPE_DICTIONARY)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DecodeNode(*static_cast<const DictionaryValue*>(child_value), parent, NULL);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkCodec::DecodeNode(const DictionaryValue& value,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               BookmarkNode* parent,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               BookmarkNode* node) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If no |node| is specified, we'll create one and add it to the |parent|.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Therefore, in that case, |parent| must be non-NULL.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node && !parent) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string id_string;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id = 0;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ids_valid_) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.GetString(kIdKey, &id_string) ||
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !base::StringToInt64(id_string, &id) ||
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ids_.count(id) != 0) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ids_valid_ = false;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ids_.insert(id);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  maximum_id_ = std::max(maximum_id_, id);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 title;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value.GetString(kNameKey, &title);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string date_added_string;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value.GetString(kDateAddedKey, &date_added_string))
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    date_added_string = base::Int64ToString(Time::Now().ToInternalValue());
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 internal_time;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StringToInt64(date_added_string, &internal_time);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string type_string;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value.GetString(kTypeKey, &type_string))
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type_string != kTypeURL && type_string != kTypeFolder)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Unknown type.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type_string == kTypeURL) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url_string;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.GetString(kURLKey, &url_string))
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL url = GURL(url_string);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!node && url.is_valid())
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node = new BookmarkNode(id, url);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;  // Node invalid.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent->Add(node, parent->child_count());
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node->set_type(BookmarkNode::URL);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateChecksumWithUrlNode(id_string, title, url_string);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string last_modified_date;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.GetString(kDateModifiedKey, &last_modified_date))
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_modified_date = base::Int64ToString(Time::Now().ToInternalValue());
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value* child_values;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.Get(kChildrenKey, &child_values))
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (child_values->GetType() != Value::TYPE_LIST)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!node) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node = new BookmarkNode(id, GURL());
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If a new node is not created, explicitly assign ID to the existing one.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node->set_id(id);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node->set_type(BookmarkNode::FOLDER);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 internal_time;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::StringToInt64(last_modified_date, &internal_time);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node->set_date_folder_modified(Time::FromInternalValue(internal_time));
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent->Add(node, parent->child_count());
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateChecksumWithFolderNode(id_string, title);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!DecodeChildren(*static_cast<const ListValue*>(child_values), node))
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  node->SetTitle(title);
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  node->set_date_added(base::Time::FromInternalValue(internal_time));
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string meta_info;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (value.GetString(kMetaInfo, &meta_info))
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node->set_meta_info_str(meta_info);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::ReassignIDs(BookmarkNode* bb_node,
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                BookmarkNode* other_node,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                BookmarkNode* mobile_node) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  maximum_id_ = 0;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReassignIDsHelper(bb_node);
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReassignIDsHelper(other_node);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReassignIDsHelper(mobile_node);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_reassigned_ = true;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::ReassignIDsHelper(BookmarkNode* node) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(node);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  node->set_id(++maximum_id_);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < node->child_count(); ++i)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReassignIDsHelper(node->GetChild(i));
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::UpdateChecksum(const std::string& str) {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Update(&md5_context_, str);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::UpdateChecksum(const string16& str) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Update(&md5_context_,
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  base::StringPiece(
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      reinterpret_cast<const char*>(str.data()),
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      str.length() * sizeof(str[0])));
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::UpdateChecksumWithUrlNode(const std::string& id,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              const string16& title,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              const std::string& url) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsStringUTF8(url));
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(id);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(title);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(kTypeURL);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(url);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::UpdateChecksumWithFolderNode(const std::string& id,
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 const string16& title) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(id);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(title);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(kTypeFolder);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::InitializeChecksum() {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Init(&md5_context_);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::FinalizeChecksum() {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Digest digest;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Final(&digest, &md5_context_);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  computed_checksum_ = base::MD5DigestToBase16(digest);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
376