OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/utility/importer/firefox_importer.h" | 5 #include "chrome/utility/importer/firefox_importer.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <set> | 8 #include <set> |
9 | 9 |
10 #include "base/files/file_enumerator.h" | 10 #include "base/files/file_enumerator.h" |
11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
12 #include "base/json/json_file_value_serializer.h" | 12 #include "base/json/json_file_value_serializer.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
16 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
17 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
18 #include "build/build_config.h" | 18 #include "build/build_config.h" |
19 #include "chrome/common/importer/firefox_importer_utils.h" | 19 #include "chrome/common/importer/firefox_importer_utils.h" |
20 #include "chrome/common/importer/imported_bookmark_entry.h" | 20 #include "chrome/common/importer/imported_bookmark_entry.h" |
21 #include "chrome/common/importer/importer_autofill_form_data_entry.h" | 21 #include "chrome/common/importer/importer_autofill_form_data_entry.h" |
22 #include "chrome/common/importer/importer_bridge.h" | 22 #include "chrome/common/importer/importer_bridge.h" |
23 #include "chrome/common/importer/importer_url_row.h" | 23 #include "chrome/common/importer/importer_url_row.h" |
24 #include "chrome/grit/generated_resources.h" | 24 #include "chrome/grit/generated_resources.h" |
25 #include "chrome/utility/importer/bookmark_html_reader.h" | 25 #include "chrome/utility/importer/bookmark_html_reader.h" |
26 #include "chrome/utility/importer/favicon_reencode.h" | 26 #include "chrome/utility/importer/firefox_places_factory.h" |
27 #include "chrome/utility/importer/nss_decryptor.h" | 27 #include "chrome/utility/importer/nss_decryptor.h" |
28 #include "components/autofill/core/common/password_form.h" | 28 #include "components/autofill/core/common/password_form.h" |
29 #include "sql/connection.h" | 29 #include "sql/connection.h" |
30 #include "sql/statement.h" | 30 #include "sql/statement.h" |
31 #include "url/gurl.h" | 31 #include "url/gurl.h" |
32 | 32 |
33 namespace { | 33 namespace { |
34 | 34 |
35 // Original definition is in http://mxr.mozilla.org/firefox/source/toolkit/ | |
36 // components/places/public/nsINavBookmarksService.idl | |
37 enum BookmarkItemType { | |
38 TYPE_BOOKMARK = 1, | |
39 TYPE_FOLDER = 2, | |
40 TYPE_SEPARATOR = 3, | |
41 TYPE_DYNAMIC_CONTAINER = 4 | |
42 }; | |
43 | |
44 // Loads the default bookmarks in the Firefox installed at |app_path|, | 35 // Loads the default bookmarks in the Firefox installed at |app_path|, |
45 // and stores their locations in |urls|. | 36 // and stores their locations in |urls|. |
46 void LoadDefaultBookmarks(const base::FilePath& app_path, | 37 void LoadDefaultBookmarks(const base::FilePath& app_path, |
47 std::set<GURL>* urls) { | 38 std::set<GURL>* urls) { |
48 base::FilePath file = app_path.AppendASCII("defaults") | 39 base::FilePath file = app_path.AppendASCII("defaults") |
49 .AppendASCII("profile") | 40 .AppendASCII("profile") |
50 .AppendASCII("bookmarks.html"); | 41 .AppendASCII("bookmarks.html"); |
51 urls->clear(); | 42 urls->clear(); |
52 | 43 |
53 std::vector<ImportedBookmarkEntry> bookmarks; | 44 std::vector<ImportedBookmarkEntry> bookmarks; |
(...skipping 20 matching lines...) Expand all Loading... |
74 for (size_t i = 0; i < arraysize(kInvalidSchemes); ++i) { | 65 for (size_t i = 0; i < arraysize(kInvalidSchemes); ++i) { |
75 if (url.SchemeIs(kInvalidSchemes[i])) | 66 if (url.SchemeIs(kInvalidSchemes[i])) |
76 return false; | 67 return false; |
77 } | 68 } |
78 | 69 |
79 return true; | 70 return true; |
80 } | 71 } |
81 | 72 |
82 } // namespace | 73 } // namespace |
83 | 74 |
84 struct FirefoxImporter::BookmarkItem { | |
85 int parent; | |
86 int id; | |
87 GURL url; | |
88 base::string16 title; | |
89 BookmarkItemType type; | |
90 std::string keyword; | |
91 base::Time date_added; | |
92 int64_t favicon; | |
93 bool empty_folder; | |
94 }; | |
95 | |
96 FirefoxImporter::FirefoxImporter() { | 75 FirefoxImporter::FirefoxImporter() { |
97 } | 76 } |
98 | 77 |
99 FirefoxImporter::~FirefoxImporter() { | 78 FirefoxImporter::~FirefoxImporter() { |
100 } | 79 } |
101 | 80 |
102 void FirefoxImporter::StartImport(const importer::SourceProfile& source_profile, | 81 void FirefoxImporter::StartImport(const importer::SourceProfile& source_profile, |
103 uint16_t items, | 82 uint16_t items, |
104 ImporterBridge* bridge) { | 83 ImporterBridge* bridge) { |
105 bridge_ = bridge; | 84 bridge_ = bridge; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 } | 123 } |
145 if ((items & importer::AUTOFILL_FORM_DATA) && !cancelled()) { | 124 if ((items & importer::AUTOFILL_FORM_DATA) && !cancelled()) { |
146 bridge_->NotifyItemStarted(importer::AUTOFILL_FORM_DATA); | 125 bridge_->NotifyItemStarted(importer::AUTOFILL_FORM_DATA); |
147 ImportAutofillFormData(); | 126 ImportAutofillFormData(); |
148 bridge_->NotifyItemEnded(importer::AUTOFILL_FORM_DATA); | 127 bridge_->NotifyItemEnded(importer::AUTOFILL_FORM_DATA); |
149 } | 128 } |
150 bridge_->NotifyEnded(); | 129 bridge_->NotifyEnded(); |
151 } | 130 } |
152 | 131 |
153 void FirefoxImporter::ImportHistory() { | 132 void FirefoxImporter::ImportHistory() { |
154 base::FilePath file = source_path_.AppendASCII("places.sqlite"); | 133 auto places = FirefoxPlacesFactory::GetForProfile(source_path_); |
155 if (!base::PathExists(file)) | 134 if (!places) |
156 return; | 135 return; |
157 | 136 |
158 sql::Connection db; | |
159 if (!db.Open(file)) | |
160 return; | |
161 | |
162 // |visit_type| represent the transition type of URLs (typed, click, | |
163 // redirect, bookmark, etc.) We eliminate some URLs like sub-frames and | |
164 // redirects, since we don't want them to appear in history. | |
165 // Firefox transition types are defined in: | |
166 // toolkit/components/places/public/nsINavHistoryService.idl | |
167 const char query[] = | |
168 "SELECT h.url, h.title, h.visit_count, " | |
169 "h.hidden, h.typed, v.visit_date " | |
170 "FROM moz_places h JOIN moz_historyvisits v " | |
171 "ON h.id = v.place_id " | |
172 "WHERE v.visit_type <= 3"; | |
173 | |
174 sql::Statement s(db.GetUniqueStatement(query)); | |
175 | |
176 std::vector<ImporterURLRow> rows; | 137 std::vector<ImporterURLRow> rows; |
177 while (s.Step() && !cancelled()) { | 138 places->LoadHistory(&rows); |
178 GURL url(s.ColumnString(0)); | 139 rows.erase(begin(rows), |
179 | 140 std::remove_if(begin(rows), end(rows), [](const ImporterURLRow& row
) { |
180 // Filter out unwanted URLs. | 141 return CanImportURL(row.url); |
181 if (!CanImportURL(url)) | 142 })); |
182 continue; | |
183 | |
184 ImporterURLRow row(url); | |
185 row.title = s.ColumnString16(1); | |
186 row.visit_count = s.ColumnInt(2); | |
187 row.hidden = s.ColumnInt(3) == 1; | |
188 row.typed_count = s.ColumnInt(4); | |
189 row.last_visit = base::Time::FromTimeT(s.ColumnInt64(5)/1000000); | |
190 | |
191 rows.push_back(row); | |
192 } | |
193 | |
194 if (!rows.empty() && !cancelled()) | 143 if (!rows.empty() && !cancelled()) |
195 bridge_->SetHistoryItems(rows, importer::VISIT_SOURCE_FIREFOX_IMPORTED); | 144 bridge_->SetHistoryItems(rows, importer::VISIT_SOURCE_FIREFOX_IMPORTED); |
196 } | 145 } |
197 | 146 |
198 void FirefoxImporter::ImportBookmarks() { | 147 void FirefoxImporter::ImportBookmarks() { |
199 base::FilePath file = source_path_.AppendASCII("places.sqlite"); | 148 auto places = FirefoxPlacesFactory::GetForProfile(source_path_); |
200 if (!base::PathExists(file)) | 149 if (!places) |
| 150 return; |
| 151 BookmarkList list; |
| 152 if (!places->LoadBookmarks(&list)) |
| 153 return; |
| 154 // TODO(jcampan): http://b/issue?id=1196285 we do not support POST based |
| 155 // keywords yet. We won't include them in the list. |
| 156 PostKeywordIds post_keyword_ids; |
| 157 if (!places->LoadPostKeywordIds(&post_keyword_ids)) |
201 return; | 158 return; |
202 | 159 |
203 sql::Connection db; | 160 // Load livemark IDs. |
204 if (!db.Open(file)) | 161 LivemarkIds livemark_ids; |
| 162 if (!places->LoadLivemarkIds(&livemark_ids)) |
205 return; | 163 return; |
206 | 164 |
207 // Get the bookmark folders that we are interested in. | |
208 int toolbar_folder_id = -1; | |
209 int menu_folder_id = -1; | |
210 int unsorted_folder_id = -1; | |
211 LoadRootNodeID(&db, &toolbar_folder_id, &menu_folder_id, &unsorted_folder_id); | |
212 | |
213 // Load livemark IDs. | |
214 std::set<int> livemark_id; | |
215 LoadLivemarkIDs(&db, &livemark_id); | |
216 | |
217 // Load the default bookmarks. | 165 // Load the default bookmarks. |
218 std::set<GURL> default_urls; | 166 std::set<GURL> default_urls; |
219 LoadDefaultBookmarks(app_path_, &default_urls); | 167 LoadDefaultBookmarks(app_path_, &default_urls); |
220 | 168 |
221 BookmarkList list; | 169 auto toolbar_folder_id = places->GetFolderId(FirefoxPlaces::FolderType::TOOLBA
R); |
222 GetTopBookmarkFolder(&db, toolbar_folder_id, &list); | 170 auto menu_folder_id = places->GetFolderId(FirefoxPlaces::FolderType::MENU); |
223 GetTopBookmarkFolder(&db, menu_folder_id, &list); | 171 auto unsorted_folder_id = places->GetFolderId(FirefoxPlaces::FolderType::UNSOR
TED); |
224 GetTopBookmarkFolder(&db, unsorted_folder_id, &list); | |
225 size_t count = list.size(); | |
226 for (size_t i = 0; i < count; ++i) | |
227 GetWholeBookmarkFolder(&db, &list, i, NULL); | |
228 | 172 |
229 std::vector<ImportedBookmarkEntry> bookmarks; | 173 std::vector<ImportedBookmarkEntry> bookmarks; |
230 std::vector<importer::SearchEngineInfo> search_engines; | 174 std::vector<importer::SearchEngineInfo> search_engines; |
231 FaviconMap favicon_map; | 175 FaviconMap favicon_map; |
232 | 176 |
233 // TODO(jcampan): http://b/issue?id=1196285 we do not support POST based | |
234 // keywords yet. We won't include them in the list. | |
235 std::set<int> post_keyword_ids; | |
236 const char query[] = | |
237 "SELECT b.id FROM moz_bookmarks b " | |
238 "INNER JOIN moz_items_annos ia ON ia.item_id = b.id " | |
239 "INNER JOIN moz_anno_attributes aa ON ia.anno_attribute_id = aa.id " | |
240 "WHERE aa.name = 'bookmarkProperties/POSTData'"; | |
241 sql::Statement s(db.GetUniqueStatement(query)); | |
242 | |
243 if (!s.is_valid()) | |
244 return; | |
245 | |
246 while (s.Step() && !cancelled()) | |
247 post_keyword_ids.insert(s.ColumnInt(0)); | |
248 | |
249 for (size_t i = 0; i < list.size(); ++i) { | 177 for (size_t i = 0; i < list.size(); ++i) { |
250 BookmarkItem* item = list[i]; | 178 BookmarkItem* item = list[i]; |
251 | |
252 // Folders are added implicitly on adding children, so we only explicitly | 179 // Folders are added implicitly on adding children, so we only explicitly |
253 // add empty folders. | 180 // add empty folders. |
254 if (item->type != TYPE_BOOKMARK && | 181 if (item->type != TYPE_BOOKMARK && |
255 ((item->type != TYPE_FOLDER) || !item->empty_folder)) | 182 ((item->type != TYPE_FOLDER) || !item->empty_folder)) |
256 continue; | 183 continue; |
257 | 184 |
258 if (CanImportURL(item->url)) { | 185 if (CanImportURL(item->url)) { |
259 // Skip the default bookmarks and unwanted URLs. | 186 // Skip the default bookmarks and unwanted URLs. |
260 if (default_urls.find(item->url) != default_urls.end() || | 187 if (default_urls.find(item->url) != default_urls.end() || |
261 post_keyword_ids.find(item->id) != post_keyword_ids.end()) | 188 post_keyword_ids.find(item->id) != post_keyword_ids.end()) |
262 continue; | 189 continue; |
263 | 190 |
264 // Find the bookmark path by tracing their links to parent folders. | 191 // Find the bookmark path by tracing their links to parent folders. |
265 std::vector<base::string16> path; | 192 std::vector<base::string16> path; |
266 BookmarkItem* child = item; | 193 BookmarkItem* child = item; |
267 bool found_path = false; | 194 bool found_path = false; |
268 bool is_in_toolbar = false; | 195 bool is_in_toolbar = false; |
269 while (child->parent >= 0) { | 196 while (child->parent >= 0) { |
270 BookmarkItem* parent = list[child->parent]; | 197 BookmarkItem* parent = list[child->parent]; |
271 if (livemark_id.find(parent->id) != livemark_id.end()) { | 198 if (livemark_ids.find(parent->id) != livemark_ids.end()) { |
272 // Don't import live bookmarks. | 199 // Don't import live bookmarks. |
273 break; | 200 break; |
274 } | 201 } |
275 | 202 |
276 if (parent->id != menu_folder_id) { | 203 if (parent->id != menu_folder_id) { |
277 // To avoid excessive nesting, omit the name for the bookmarks menu | 204 // To avoid excessive nesting, omit the name for the bookmarks menu |
278 // folder. | 205 // folder. |
279 path.insert(path.begin(), parent->title); | 206 path.insert(path.begin(), parent->title); |
280 } | 207 } |
281 | 208 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 if (!bookmarks.empty() && !cancelled()) { | 266 if (!bookmarks.empty() && !cancelled()) { |
340 const base::string16& first_folder_name = | 267 const base::string16& first_folder_name = |
341 bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_FIREFOX); | 268 bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_FIREFOX); |
342 bridge_->AddBookmarks(bookmarks, first_folder_name); | 269 bridge_->AddBookmarks(bookmarks, first_folder_name); |
343 } | 270 } |
344 if (!search_engines.empty() && !cancelled()) { | 271 if (!search_engines.empty() && !cancelled()) { |
345 bridge_->SetKeywords(search_engines, false); | 272 bridge_->SetKeywords(search_engines, false); |
346 } | 273 } |
347 if (!favicon_map.empty() && !cancelled()) { | 274 if (!favicon_map.empty() && !cancelled()) { |
348 favicon_base::FaviconUsageDataList favicons; | 275 favicon_base::FaviconUsageDataList favicons; |
349 LoadFavicons(&db, favicon_map, &favicons); | 276 if (places->LoadFavicons(favicon_map, &favicons)) |
350 bridge_->SetFavicons(favicons); | 277 bridge_->SetFavicons(favicons); |
351 } | 278 } |
352 } | 279 } |
353 | 280 |
354 void FirefoxImporter::ImportPasswords() { | 281 void FirefoxImporter::ImportPasswords() { |
355 // Initializes NSS3. | 282 // Initializes NSS3. |
356 NSSDecryptor decryptor; | 283 NSSDecryptor decryptor; |
357 if (!decryptor.Init(source_path_, source_path_) && | 284 if (!decryptor.Init(source_path_, source_path_) && |
358 !decryptor.Init(app_path_, source_path_)) { | 285 !decryptor.Init(app_path_, source_path_)) { |
359 return; | 286 return; |
360 } | 287 } |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
639 // Add <Alias> element as the last child element. | 566 // Add <Alias> element as the last child element. |
640 size_t end_of_parent = file_data.find("</SearchPlugin>"); | 567 size_t end_of_parent = file_data.find("</SearchPlugin>"); |
641 if (end_of_parent != std::string::npos && !alias.empty()) | 568 if (end_of_parent != std::string::npos && !alias.empty()) |
642 file_data.insert(end_of_parent, "<Alias>" + alias + "</Alias> \n"); | 569 file_data.insert(end_of_parent, "<Alias>" + alias + "</Alias> \n"); |
643 } | 570 } |
644 search_engine_data->push_back(file_data); | 571 search_engine_data->push_back(file_data); |
645 } | 572 } |
646 } | 573 } |
647 } | 574 } |
648 } | 575 } |
649 | |
650 void FirefoxImporter::LoadRootNodeID(sql::Connection* db, | |
651 int* toolbar_folder_id, | |
652 int* menu_folder_id, | |
653 int* unsorted_folder_id) { | |
654 static const char kToolbarFolderName[] = "toolbar"; | |
655 static const char kMenuFolderName[] = "menu"; | |
656 static const char kUnsortedFolderName[] = "unfiled"; | |
657 | |
658 const char query[] = "SELECT root_name, folder_id FROM moz_bookmarks_roots"; | |
659 sql::Statement s(db->GetUniqueStatement(query)); | |
660 | |
661 while (s.Step()) { | |
662 std::string folder = s.ColumnString(0); | |
663 int id = s.ColumnInt(1); | |
664 if (folder == kToolbarFolderName) | |
665 *toolbar_folder_id = id; | |
666 else if (folder == kMenuFolderName) | |
667 *menu_folder_id = id; | |
668 else if (folder == kUnsortedFolderName) | |
669 *unsorted_folder_id = id; | |
670 } | |
671 } | |
672 | |
673 void FirefoxImporter::LoadLivemarkIDs(sql::Connection* db, | |
674 std::set<int>* livemark) { | |
675 static const char kFeedAnnotation[] = "livemark/feedURI"; | |
676 livemark->clear(); | |
677 | |
678 const char query[] = | |
679 "SELECT b.item_id " | |
680 "FROM moz_anno_attributes a " | |
681 "JOIN moz_items_annos b ON a.id = b.anno_attribute_id " | |
682 "WHERE a.name = ? "; | |
683 sql::Statement s(db->GetUniqueStatement(query)); | |
684 s.BindString(0, kFeedAnnotation); | |
685 | |
686 while (s.Step() && !cancelled()) | |
687 livemark->insert(s.ColumnInt(0)); | |
688 } | |
689 | |
690 void FirefoxImporter::GetTopBookmarkFolder(sql::Connection* db, | |
691 int folder_id, | |
692 BookmarkList* list) { | |
693 const char query[] = | |
694 "SELECT b.title " | |
695 "FROM moz_bookmarks b " | |
696 "WHERE b.type = 2 AND b.id = ? " | |
697 "ORDER BY b.position"; | |
698 sql::Statement s(db->GetUniqueStatement(query)); | |
699 s.BindInt(0, folder_id); | |
700 | |
701 if (s.Step()) { | |
702 BookmarkItem* item = new BookmarkItem; | |
703 item->parent = -1; // The top level folder has no parent. | |
704 item->id = folder_id; | |
705 item->title = s.ColumnString16(0); | |
706 item->type = TYPE_FOLDER; | |
707 item->favicon = 0; | |
708 item->empty_folder = true; | |
709 list->push_back(item); | |
710 } | |
711 } | |
712 | |
713 void FirefoxImporter::GetWholeBookmarkFolder(sql::Connection* db, | |
714 BookmarkList* list, | |
715 size_t position, | |
716 bool* empty_folder) { | |
717 if (position >= list->size()) { | |
718 NOTREACHED(); | |
719 return; | |
720 } | |
721 | |
722 const char query[] = | |
723 "SELECT b.id, h.url, COALESCE(b.title, h.title), " | |
724 "b.type, k.keyword, b.dateAdded, h.favicon_id " | |
725 "FROM moz_bookmarks b " | |
726 "LEFT JOIN moz_places h ON b.fk = h.id " | |
727 "LEFT JOIN moz_keywords k ON k.id = b.keyword_id " | |
728 "WHERE b.type IN (1,2) AND b.parent = ? " | |
729 "ORDER BY b.position"; | |
730 sql::Statement s(db->GetUniqueStatement(query)); | |
731 s.BindInt(0, (*list)[position]->id); | |
732 | |
733 BookmarkList temp_list; | |
734 while (s.Step()) { | |
735 BookmarkItem* item = new BookmarkItem; | |
736 item->parent = static_cast<int>(position); | |
737 item->id = s.ColumnInt(0); | |
738 item->url = GURL(s.ColumnString(1)); | |
739 item->title = s.ColumnString16(2); | |
740 item->type = static_cast<BookmarkItemType>(s.ColumnInt(3)); | |
741 item->keyword = s.ColumnString(4); | |
742 item->date_added = base::Time::FromTimeT(s.ColumnInt64(5)/1000000); | |
743 item->favicon = s.ColumnInt64(6); | |
744 item->empty_folder = true; | |
745 | |
746 temp_list.push_back(item); | |
747 if (empty_folder != NULL) | |
748 *empty_folder = false; | |
749 } | |
750 | |
751 // Appends all items to the list. | |
752 for (BookmarkList::iterator i = temp_list.begin(); | |
753 i != temp_list.end(); ++i) { | |
754 list->push_back(*i); | |
755 // Recursive add bookmarks in sub-folders. | |
756 if ((*i)->type == TYPE_FOLDER) | |
757 GetWholeBookmarkFolder(db, list, list->size() - 1, &(*i)->empty_folder); | |
758 } | |
759 } | |
760 | |
761 void FirefoxImporter::LoadFavicons( | |
762 sql::Connection* db, | |
763 const FaviconMap& favicon_map, | |
764 favicon_base::FaviconUsageDataList* favicons) { | |
765 const char query[] = "SELECT url, data FROM moz_favicons WHERE id=?"; | |
766 sql::Statement s(db->GetUniqueStatement(query)); | |
767 | |
768 if (!s.is_valid()) | |
769 return; | |
770 | |
771 for (FaviconMap::const_iterator i = favicon_map.begin(); | |
772 i != favicon_map.end(); ++i) { | |
773 s.BindInt64(0, i->first); | |
774 if (s.Step()) { | |
775 favicon_base::FaviconUsageData usage; | |
776 | |
777 usage.favicon_url = GURL(s.ColumnString(0)); | |
778 if (!usage.favicon_url.is_valid()) | |
779 continue; // Don't bother importing favicons with invalid URLs. | |
780 | |
781 std::vector<unsigned char> data; | |
782 s.ColumnBlobAsVector(1, &data); | |
783 if (data.empty()) | |
784 continue; // Data definitely invalid. | |
785 | |
786 if (!importer::ReencodeFavicon(&data[0], data.size(), &usage.png_data)) | |
787 continue; // Unable to decode. | |
788 | |
789 usage.urls = i->second; | |
790 favicons->push_back(usage); | |
791 } | |
792 s.Reset(true); | |
793 } | |
794 } | |
OLD | NEW |