| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/bookmarks/bookmark_codec.h" | 5 #include "chrome/browser/bookmarks/bookmark_codec.h" |
| 6 | 6 |
| 7 #include "base/string_util.h" | 7 #include "base/string_util.h" |
| 8 #include "base/values.h" | 8 #include "base/values.h" |
| 9 #include "chrome/browser/bookmarks/bookmark_model.h" | 9 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 10 #include "chrome/common/l10n_util.h" | 10 #include "chrome/common/l10n_util.h" |
| 11 #include "googleurl/src/gurl.h" | 11 #include "googleurl/src/gurl.h" |
| 12 #include "grit/generated_resources.h" | 12 #include "grit/generated_resources.h" |
| 13 | 13 |
| 14 using base::Time; | 14 using base::Time; |
| 15 | 15 |
| 16 UniqueIDGenerator::UniqueIDGenerator() { |
| 17 Reset(); |
| 18 } |
| 19 |
| 20 int UniqueIDGenerator::GetUniqueID(int id) { |
| 21 if (assigned_ids_.find(id) != assigned_ids_.end()) |
| 22 id = current_max_ + 1; |
| 23 |
| 24 if (id > current_max_) |
| 25 current_max_ = id; |
| 26 |
| 27 assigned_ids_.insert(id); |
| 28 return id; |
| 29 } |
| 30 |
| 31 void UniqueIDGenerator::Reset() { |
| 32 current_max_ = 0; |
| 33 assigned_ids_.clear(); |
| 34 // 0 should always be considered as an ID that's already generated. |
| 35 assigned_ids_.insert(0); |
| 36 } |
| 37 |
| 16 const wchar_t* BookmarkCodec::kRootsKey = L"roots"; | 38 const wchar_t* BookmarkCodec::kRootsKey = L"roots"; |
| 17 const wchar_t* BookmarkCodec::kRootFolderNameKey = L"bookmark_bar"; | 39 const wchar_t* BookmarkCodec::kRootFolderNameKey = L"bookmark_bar"; |
| 18 const wchar_t* BookmarkCodec::kOtherBookmarFolderNameKey = L"other"; | 40 const wchar_t* BookmarkCodec::kOtherBookmarFolderNameKey = L"other"; |
| 19 const wchar_t* BookmarkCodec::kVersionKey = L"version"; | 41 const wchar_t* BookmarkCodec::kVersionKey = L"version"; |
| 20 const wchar_t* BookmarkCodec::kChecksumKey = L"checksum"; | 42 const wchar_t* BookmarkCodec::kChecksumKey = L"checksum"; |
| 43 const wchar_t* BookmarkCodec::kIdKey = L"id"; |
| 21 const wchar_t* BookmarkCodec::kTypeKey = L"type"; | 44 const wchar_t* BookmarkCodec::kTypeKey = L"type"; |
| 22 const wchar_t* BookmarkCodec::kNameKey = L"name"; | 45 const wchar_t* BookmarkCodec::kNameKey = L"name"; |
| 23 const wchar_t* BookmarkCodec::kDateAddedKey = L"date_added"; | 46 const wchar_t* BookmarkCodec::kDateAddedKey = L"date_added"; |
| 24 const wchar_t* BookmarkCodec::kURLKey = L"url"; | 47 const wchar_t* BookmarkCodec::kURLKey = L"url"; |
| 25 const wchar_t* BookmarkCodec::kDateModifiedKey = L"date_modified"; | 48 const wchar_t* BookmarkCodec::kDateModifiedKey = L"date_modified"; |
| 26 const wchar_t* BookmarkCodec::kChildrenKey = L"children"; | 49 const wchar_t* BookmarkCodec::kChildrenKey = L"children"; |
| 27 const wchar_t* BookmarkCodec::kTypeURL = L"url"; | 50 const wchar_t* BookmarkCodec::kTypeURL = L"url"; |
| 28 const wchar_t* BookmarkCodec::kTypeFolder = L"folder"; | 51 const wchar_t* BookmarkCodec::kTypeFolder = L"folder"; |
| 29 | 52 |
| 30 // Current version of the file. | 53 // Current version of the file. |
| 31 static const int kCurrentVersion = 1; | 54 static const int kCurrentVersion = 1; |
| 32 | 55 |
| 56 BookmarkCodec::BookmarkCodec() |
| 57 : persist_ids_(false) { |
| 58 } |
| 59 |
| 60 BookmarkCodec::BookmarkCodec(bool persist_ids) |
| 61 : persist_ids_(persist_ids) { |
| 62 } |
| 63 |
| 33 Value* BookmarkCodec::Encode(BookmarkModel* model) { | 64 Value* BookmarkCodec::Encode(BookmarkModel* model) { |
| 34 return Encode(model->GetBookmarkBarNode(), model->other_node()); | 65 return Encode(model->GetBookmarkBarNode(), model->other_node()); |
| 35 } | 66 } |
| 36 | 67 |
| 37 Value* BookmarkCodec::Encode(BookmarkNode* bookmark_bar_node, | 68 Value* BookmarkCodec::Encode(BookmarkNode* bookmark_bar_node, |
| 38 BookmarkNode* other_folder_node) { | 69 BookmarkNode* other_folder_node) { |
| 39 InitializeChecksum(); | 70 InitializeChecksum(); |
| 40 DictionaryValue* roots = new DictionaryValue(); | 71 DictionaryValue* roots = new DictionaryValue(); |
| 41 roots->Set(kRootFolderNameKey, EncodeNode(bookmark_bar_node)); | 72 roots->Set(kRootFolderNameKey, EncodeNode(bookmark_bar_node)); |
| 42 roots->Set(kOtherBookmarFolderNameKey, EncodeNode(other_folder_node)); | 73 roots->Set(kOtherBookmarFolderNameKey, EncodeNode(other_folder_node)); |
| 43 | 74 |
| 44 DictionaryValue* main = new DictionaryValue(); | 75 DictionaryValue* main = new DictionaryValue(); |
| 45 main->SetInteger(kVersionKey, kCurrentVersion); | 76 main->SetInteger(kVersionKey, kCurrentVersion); |
| 46 FinalizeChecksum(); | 77 FinalizeChecksum(); |
| 47 // We are going to store the computed checksum. So set stored checksum to be | 78 // We are going to store the computed checksum. So set stored checksum to be |
| 48 // the same as computed checksum. | 79 // the same as computed checksum. |
| 49 stored_checksum_ = computed_checksum_; | 80 stored_checksum_ = computed_checksum_; |
| 50 main->Set(kChecksumKey, Value::CreateStringValue(computed_checksum_)); | 81 main->Set(kChecksumKey, Value::CreateStringValue(computed_checksum_)); |
| 51 main->Set(kRootsKey, roots); | 82 main->Set(kRootsKey, roots); |
| 52 return main; | 83 return main; |
| 53 } | 84 } |
| 54 | 85 |
| 55 bool BookmarkCodec::Decode(BookmarkModel* model, const Value& value) { | 86 bool BookmarkCodec::Decode(BookmarkModel* model, const Value& value) { |
| 87 id_generator_.Reset(); |
| 56 stored_checksum_.clear(); | 88 stored_checksum_.clear(); |
| 57 InitializeChecksum(); | 89 InitializeChecksum(); |
| 58 bool success = DecodeHelper(model, value); | 90 bool success = DecodeHelper(model, value); |
| 59 FinalizeChecksum(); | 91 FinalizeChecksum(); |
| 92 BookmarkNode::SetNextId(id_generator_.current_max() + 1); |
| 60 return success; | 93 return success; |
| 61 } | 94 } |
| 62 | 95 |
| 63 Value* BookmarkCodec::EncodeNode(BookmarkNode* node) { | 96 Value* BookmarkCodec::EncodeNode(BookmarkNode* node) { |
| 64 DictionaryValue* value = new DictionaryValue(); | 97 DictionaryValue* value = new DictionaryValue(); |
| 98 std::string id; |
| 99 if (persist_ids_) { |
| 100 id = IntToString(node->id()); |
| 101 value->SetString(kIdKey, id); |
| 102 } |
| 65 const std::wstring& title = node->GetTitle(); | 103 const std::wstring& title = node->GetTitle(); |
| 66 value->SetString(kNameKey, title); | 104 value->SetString(kNameKey, title); |
| 67 value->SetString(kDateAddedKey, | 105 value->SetString(kDateAddedKey, |
| 68 Int64ToWString(node->date_added().ToInternalValue())); | 106 Int64ToWString(node->date_added().ToInternalValue())); |
| 69 if (node->GetType() == history::StarredEntry::URL) { | 107 if (node->GetType() == history::StarredEntry::URL) { |
| 70 value->SetString(kTypeKey, kTypeURL); | 108 value->SetString(kTypeKey, kTypeURL); |
| 71 std::wstring url = UTF8ToWide(node->GetURL().possibly_invalid_spec()); | 109 std::wstring url = UTF8ToWide(node->GetURL().possibly_invalid_spec()); |
| 72 value->SetString(kURLKey, url); | 110 value->SetString(kURLKey, url); |
| 73 UpdateChecksumWithUrlNode(title, url); | 111 UpdateChecksumWithUrlNode(id, title, url); |
| 74 } else { | 112 } else { |
| 75 value->SetString(kTypeKey, kTypeFolder); | 113 value->SetString(kTypeKey, kTypeFolder); |
| 76 value->SetString(kDateModifiedKey, | 114 value->SetString(kDateModifiedKey, |
| 77 Int64ToWString(node->date_group_modified(). | 115 Int64ToWString(node->date_group_modified(). |
| 78 ToInternalValue())); | 116 ToInternalValue())); |
| 79 UpdateChecksumWithFolderNode(title); | 117 UpdateChecksumWithFolderNode(id, title); |
| 80 | 118 |
| 81 ListValue* child_values = new ListValue(); | 119 ListValue* child_values = new ListValue(); |
| 82 value->Set(kChildrenKey, child_values); | 120 value->Set(kChildrenKey, child_values); |
| 83 for (int i = 0; i < node->GetChildCount(); ++i) | 121 for (int i = 0; i < node->GetChildCount(); ++i) |
| 84 child_values->Append(EncodeNode(node->GetChild(i))); | 122 child_values->Append(EncodeNode(node->GetChild(i))); |
| 85 } | 123 } |
| 86 return value; | 124 return value; |
| 87 } | 125 } |
| 88 | 126 |
| 89 bool BookmarkCodec::DecodeHelper(BookmarkModel* model, const Value& value) { | 127 bool BookmarkCodec::DecodeHelper(BookmarkModel* model, const Value& value) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 return false; | 193 return false; |
| 156 } | 194 } |
| 157 } | 195 } |
| 158 return true; | 196 return true; |
| 159 } | 197 } |
| 160 | 198 |
| 161 bool BookmarkCodec::DecodeNode(BookmarkModel* model, | 199 bool BookmarkCodec::DecodeNode(BookmarkModel* model, |
| 162 const DictionaryValue& value, | 200 const DictionaryValue& value, |
| 163 BookmarkNode* parent, | 201 BookmarkNode* parent, |
| 164 BookmarkNode* node) { | 202 BookmarkNode* node) { |
| 203 std::string id_string; |
| 204 int id = 0; |
| 205 if (persist_ids_) { |
| 206 if (value.GetString(kIdKey, &id_string)) |
| 207 if (!StringToInt(id_string, &id)) |
| 208 return false; |
| 209 id = id_generator_.GetUniqueID(id); |
| 210 } |
| 211 |
| 165 std::wstring title; | 212 std::wstring title; |
| 166 if (!value.GetString(kNameKey, &title)) | 213 if (!value.GetString(kNameKey, &title)) |
| 167 return false; | 214 return false; |
| 168 | 215 |
| 169 // TODO(sky): this should be more flexible. Don't hoark if we can't parse it | 216 // TODO(sky): this should be more flexible. Don't hoark if we can't parse it |
| 170 // all. | 217 // all. |
| 171 std::wstring date_added_string; | 218 std::wstring date_added_string; |
| 172 if (!value.GetString(kDateAddedKey, &date_added_string)) | 219 if (!value.GetString(kDateAddedKey, &date_added_string)) |
| 173 return false; | 220 return false; |
| 174 | 221 |
| 175 std::wstring type_string; | 222 std::wstring type_string; |
| 176 if (!value.GetString(kTypeKey, &type_string)) | 223 if (!value.GetString(kTypeKey, &type_string)) |
| 177 return false; | 224 return false; |
| 178 | 225 |
| 179 if (type_string != kTypeURL && type_string != kTypeFolder) | 226 if (type_string != kTypeURL && type_string != kTypeFolder) |
| 180 return false; // Unknown type. | 227 return false; // Unknown type. |
| 181 | 228 |
| 182 if (type_string == kTypeURL) { | 229 if (type_string == kTypeURL) { |
| 183 std::wstring url_string; | 230 std::wstring url_string; |
| 184 if (!value.GetString(kURLKey, &url_string)) | 231 if (!value.GetString(kURLKey, &url_string)) |
| 185 return false; | 232 return false; |
| 186 // TODO(sky): this should ignore the node if not a valid URL. | 233 // TODO(sky): this should ignore the node if not a valid URL. |
| 187 if (!node) | 234 if (!node) |
| 188 node = new BookmarkNode(model, GURL(WideToUTF8(url_string))); | 235 node = new BookmarkNode(model, id, GURL(WideToUTF8(url_string))); |
| 236 else |
| 237 NOTREACHED(); // In case of a URL type node should always be NULL. |
| 238 |
| 239 |
| 189 if (parent) | 240 if (parent) |
| 190 parent->Add(parent->GetChildCount(), node); | 241 parent->Add(parent->GetChildCount(), node); |
| 191 node->type_ = history::StarredEntry::URL; | 242 node->type_ = history::StarredEntry::URL; |
| 192 UpdateChecksumWithUrlNode(title, url_string); | 243 UpdateChecksumWithUrlNode(id_string, title, url_string); |
| 193 } else { | 244 } else { |
| 194 std::wstring last_modified_date; | 245 std::wstring last_modified_date; |
| 195 if (!value.GetString(kDateModifiedKey, &last_modified_date)) | 246 if (!value.GetString(kDateModifiedKey, &last_modified_date)) |
| 196 return false; | 247 return false; |
| 197 | 248 |
| 198 Value* child_values; | 249 Value* child_values; |
| 199 if (!value.Get(kChildrenKey, &child_values)) | 250 if (!value.Get(kChildrenKey, &child_values)) |
| 200 return false; | 251 return false; |
| 201 | 252 |
| 202 if (child_values->GetType() != Value::TYPE_LIST) | 253 if (child_values->GetType() != Value::TYPE_LIST) |
| 203 return false; | 254 return false; |
| 204 | 255 |
| 205 if (!node) | 256 if (!node) { |
| 206 node = new BookmarkNode(model, GURL()); | 257 node = new BookmarkNode(model, id, GURL()); |
| 258 } else if (persist_ids_) { |
| 259 // If a new node is not created, explicitly assign persisted ID to the |
| 260 // existing node. |
| 261 DCHECK(id != 0); |
| 262 node->set_id(id); |
| 263 } |
| 264 |
| 207 node->type_ = history::StarredEntry::USER_GROUP; | 265 node->type_ = history::StarredEntry::USER_GROUP; |
| 208 node->date_group_modified_ = Time::FromInternalValue( | 266 node->date_group_modified_ = Time::FromInternalValue( |
| 209 StringToInt64(WideToUTF16Hack(last_modified_date))); | 267 StringToInt64(WideToUTF16Hack(last_modified_date))); |
| 210 | 268 |
| 211 if (parent) | 269 if (parent) |
| 212 parent->Add(parent->GetChildCount(), node); | 270 parent->Add(parent->GetChildCount(), node); |
| 213 | 271 |
| 214 UpdateChecksumWithFolderNode(title); | 272 UpdateChecksumWithFolderNode(id_string, title); |
| 215 if (!DecodeChildren(model, *static_cast<ListValue*>(child_values), node)) | 273 if (!DecodeChildren(model, *static_cast<ListValue*>(child_values), node)) |
| 216 return false; | 274 return false; |
| 217 } | 275 } |
| 218 | 276 |
| 219 node->SetTitle(title); | 277 node->SetTitle(title); |
| 220 node->date_added_ = Time::FromInternalValue( | 278 node->date_added_ = Time::FromInternalValue( |
| 221 StringToInt64(WideToUTF16Hack(date_added_string))); | 279 StringToInt64(WideToUTF16Hack(date_added_string))); |
| 222 return true; | 280 return true; |
| 223 } | 281 } |
| 224 | 282 |
| 225 void BookmarkCodec::UpdateChecksum(const std::string& str) { | 283 void BookmarkCodec::UpdateChecksum(const std::string& str) { |
| 226 MD5Update(&md5_context_, str.data(), str.length() * sizeof(char)); | 284 MD5Update(&md5_context_, str.data(), str.length() * sizeof(char)); |
| 227 } | 285 } |
| 228 | 286 |
| 229 void BookmarkCodec::UpdateChecksum(const std::wstring& str) { | 287 void BookmarkCodec::UpdateChecksum(const std::wstring& str) { |
| 230 MD5Update(&md5_context_, str.data(), str.length() * sizeof(wchar_t)); | 288 MD5Update(&md5_context_, str.data(), str.length() * sizeof(wchar_t)); |
| 231 } | 289 } |
| 232 | 290 |
| 233 void BookmarkCodec::UpdateChecksumWithUrlNode(const std::wstring& title, | 291 void BookmarkCodec::UpdateChecksumWithUrlNode(const std::string& id, |
| 292 const std::wstring& title, |
| 234 const std::wstring& url) { | 293 const std::wstring& url) { |
| 294 UpdateChecksum(id); |
| 235 UpdateChecksum(title); | 295 UpdateChecksum(title); |
| 236 UpdateChecksum(kTypeURL); | 296 UpdateChecksum(kTypeURL); |
| 237 UpdateChecksum(url); | 297 UpdateChecksum(url); |
| 238 } | 298 } |
| 239 | 299 |
| 240 void BookmarkCodec::UpdateChecksumWithFolderNode(const std::wstring& title) { | 300 void BookmarkCodec::UpdateChecksumWithFolderNode(const std::string& id, |
| 301 const std::wstring& title) { |
| 302 UpdateChecksum(id); |
| 241 UpdateChecksum(title); | 303 UpdateChecksum(title); |
| 242 UpdateChecksum(kTypeFolder); | 304 UpdateChecksum(kTypeFolder); |
| 243 } | 305 } |
| 244 | 306 |
| 245 void BookmarkCodec::InitializeChecksum() { | 307 void BookmarkCodec::InitializeChecksum() { |
| 246 MD5Init(&md5_context_); | 308 MD5Init(&md5_context_); |
| 247 } | 309 } |
| 248 | 310 |
| 249 void BookmarkCodec::FinalizeChecksum() { | 311 void BookmarkCodec::FinalizeChecksum() { |
| 250 MD5Digest digest; | 312 MD5Digest digest; |
| 251 MD5Final(&digest, &md5_context_); | 313 MD5Final(&digest, &md5_context_); |
| 252 computed_checksum_ = MD5DigestToBase16(digest); | 314 computed_checksum_ = MD5DigestToBase16(digest); |
| 253 } | 315 } |
| 254 | 316 |
| OLD | NEW |