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 |