OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/utility/importer/favicon_reencode.h" |
| 6 #include "chrome/utility/importer/firefox_places_factory.h" |
| 7 #include "firefox_places_factory.h" |
| 8 |
| 9 FirefoxPlaces::FirefoxPlaces(const base::FilePath& places_path) |
| 10 : places_path_(places_path) { |
| 11 db_.Open(places_path); |
| 12 } |
| 13 |
| 14 bool FirefoxPlaces::LoadBookmarks(BookmarkList* bookmarks) { |
| 15 // Get the bookmark folders that we are interested in. |
| 16 int toolbar_folder_id = GetFolderId(FolderType::TOOLBAR); |
| 17 int menu_folder_id = GetFolderId(FolderType::MENU); |
| 18 int unsorted_folder_id = GetFolderId(FolderType::UNSORTED); |
| 19 |
| 20 GetTopBookmarkFolder(toolbar_folder_id, bookmarks); |
| 21 GetTopBookmarkFolder(menu_folder_id, bookmarks); |
| 22 GetTopBookmarkFolder(unsorted_folder_id, bookmarks); |
| 23 auto num_folders = bookmarks->size(); |
| 24 for (size_t i = 0; i < num_folders; ++i) |
| 25 GetWholeBookmarkFolder(bookmarks, i, NULL); |
| 26 return true; |
| 27 } |
| 28 |
| 29 bool FirefoxPlaces::LoadHistory(std::vector<ImporterURLRow>* rows) { |
| 30 // |visit_type| represent the transition type of URLs (typed, click, |
| 31 // redirect, bookmark, etc.) We eliminate some URLs like sub-frames and |
| 32 // redirects, since we don't want them to appear in history. |
| 33 // Firefox transition types are defined in: |
| 34 // toolkit/components/places/public/nsINavHistoryService.idl |
| 35 const char query[] = |
| 36 "SELECT h.url, h.title, h.visit_count, " |
| 37 "h.hidden, h.typed, v.visit_date " |
| 38 "FROM moz_places h JOIN moz_historyvisits v " |
| 39 "ON h.id = v.place_id " |
| 40 "WHERE v.visit_type <= 3"; |
| 41 |
| 42 sql::Statement s(db_.GetUniqueStatement(query)); |
| 43 |
| 44 while (s.Step()) { |
| 45 GURL url(s.ColumnString(0)); |
| 46 |
| 47 ImporterURLRow row(url); |
| 48 row.title = s.ColumnString16(1); |
| 49 row.visit_count = s.ColumnInt(2); |
| 50 row.hidden = s.ColumnInt(3) == 1; |
| 51 row.typed_count = s.ColumnInt(4); |
| 52 row.last_visit = base::Time::FromTimeT(s.ColumnInt64(5) / 1000000); |
| 53 |
| 54 rows->push_back(row); |
| 55 } |
| 56 return true; |
| 57 } |
| 58 |
| 59 bool FirefoxPlaces::LoadPostKeywordIds(PostKeywordIds* post_keyword_ids) { |
| 60 const char query[] = |
| 61 "SELECT b.id FROM moz_bookmarks b " |
| 62 "INNER JOIN moz_items_annos ia ON ia.item_id = b.id " |
| 63 "INNER JOIN moz_anno_attributes aa ON ia.anno_attribute_id = aa.id " |
| 64 "WHERE aa.name = 'bookmarkProperties/POSTData'"; |
| 65 sql::Statement s(db_.GetUniqueStatement(query)); |
| 66 |
| 67 if (!s.is_valid()) |
| 68 return false; |
| 69 |
| 70 while (s.Step()) |
| 71 post_keyword_ids->insert(s.ColumnInt(0)); |
| 72 return true; |
| 73 } |
| 74 |
| 75 bool FirefoxPlaces::LoadLivemarkIds(LivemarkIds* livemark_ids) { |
| 76 static const char kFeedAnnotation[] = "livemark/feedURI"; |
| 77 livemark_ids->clear(); |
| 78 |
| 79 const char query[] = |
| 80 "SELECT b.item_id " |
| 81 "FROM moz_anno_attributes a " |
| 82 "JOIN moz_items_annos b ON a.id = b.anno_attribute_id " |
| 83 "WHERE a.name = ? "; |
| 84 sql::Statement s(db_.GetUniqueStatement(query)); |
| 85 s.BindString(0, kFeedAnnotation); |
| 86 |
| 87 while (s.Step()) |
| 88 livemark_ids->insert(s.ColumnInt(0)); |
| 89 return true; |
| 90 } |
| 91 |
| 92 int FirefoxPlaces::GetFolderId(FolderType folder_type) { |
| 93 return -1; |
| 94 } |
| 95 |
| 96 bool FirefoxPlaces::LoadFavicons(const FaviconMap& favicon_map, |
| 97 favicon_base::FaviconUsageDataList* favicons) { |
| 98 const char query[] = "SELECT url, data FROM moz_favicons WHERE id=?"; |
| 99 sql::Statement s(db_.GetUniqueStatement(query)); |
| 100 |
| 101 if (!s.is_valid()) |
| 102 return false; |
| 103 |
| 104 for (FaviconMap::const_iterator i = favicon_map.begin(); |
| 105 i != favicon_map.end(); ++i) { |
| 106 s.BindInt64(0, i->first); |
| 107 if (s.Step()) { |
| 108 favicon_base::FaviconUsageData usage; |
| 109 |
| 110 usage.favicon_url = GURL(s.ColumnString(0)); |
| 111 if (!usage.favicon_url.is_valid()) |
| 112 continue; // Don't bother importing favicons with invalid URLs. |
| 113 |
| 114 std::vector<unsigned char> data; |
| 115 s.ColumnBlobAsVector(1, &data); |
| 116 if (data.empty()) |
| 117 continue; // Data definitely invalid. |
| 118 |
| 119 if (!importer::ReencodeFavicon(&data[0], data.size(), &usage.png_data)) |
| 120 continue; // Unable to decode. |
| 121 |
| 122 usage.urls = i->second; |
| 123 favicons->push_back(usage); |
| 124 } |
| 125 s.Reset(true); |
| 126 } |
| 127 return true; |
| 128 } |
| 129 |
| 130 void FirefoxPlaces::GetTopBookmarkFolder(int folder_id, BookmarkList* list) { |
| 131 const char query[] = |
| 132 "SELECT b.title " |
| 133 "FROM moz_bookmarks b " |
| 134 "WHERE b.type = 2 AND b.id = ? " |
| 135 "ORDER BY b.position"; |
| 136 sql::Statement s(db_.GetUniqueStatement(query)); |
| 137 s.BindInt(0, folder_id); |
| 138 |
| 139 if (s.Step()) { |
| 140 BookmarkItem* item = new BookmarkItem; |
| 141 item->parent = -1; // The top level folder has no parent. |
| 142 item->id = folder_id; |
| 143 item->title = s.ColumnString16(0); |
| 144 item->type = TYPE_FOLDER; |
| 145 item->favicon = 0; |
| 146 item->empty_folder = true; |
| 147 list->push_back(item); |
| 148 } |
| 149 } |
| 150 |
| 151 void FirefoxPlaces::GetWholeBookmarkFolder(BookmarkList* list, |
| 152 size_t position, |
| 153 bool* empty_folder) { |
| 154 if (position >= list->size()) { |
| 155 NOTREACHED(); |
| 156 return; |
| 157 } |
| 158 |
| 159 const char query[] = |
| 160 "SELECT b.id, h.url, COALESCE(b.title, h.title), " |
| 161 "b.type, k.keyword, b.dateAdded, h.favicon_id " |
| 162 "FROM moz_bookmarks b " |
| 163 "LEFT JOIN moz_places h ON b.fk = h.id " |
| 164 "LEFT JOIN moz_keywords k ON k.id = b.keyword_id " |
| 165 "WHERE b.type IN (1,2) AND b.parent = ? " |
| 166 "ORDER BY b.position"; |
| 167 sql::Statement s(db_.GetUniqueStatement(query)); |
| 168 s.BindInt(0, (*list)[position]->id); |
| 169 |
| 170 BookmarkList temp_list; |
| 171 while (s.Step()) { |
| 172 BookmarkItem* item = new BookmarkItem; |
| 173 item->parent = static_cast<int>(position); |
| 174 item->id = s.ColumnInt(0); |
| 175 item->url = GURL(s.ColumnString(1)); |
| 176 item->title = s.ColumnString16(2); |
| 177 item->type = static_cast<BookmarkItemType>(s.ColumnInt(3)); |
| 178 item->keyword = s.ColumnString(4); |
| 179 item->date_added = base::Time::FromTimeT(s.ColumnInt64(5) / 1000000); |
| 180 item->favicon = s.ColumnInt64(6); |
| 181 item->empty_folder = true; |
| 182 |
| 183 temp_list.push_back(item); |
| 184 if (empty_folder != NULL) |
| 185 *empty_folder = false; |
| 186 } |
| 187 |
| 188 // Appends all items to the list. |
| 189 for (BookmarkList::iterator i = temp_list.begin(); i != temp_list.end(); |
| 190 ++i) { |
| 191 list->push_back(*i); |
| 192 // Recursive add bookmarks in sub-folders. |
| 193 if ((*i)->type == TYPE_FOLDER) |
| 194 GetWholeBookmarkFolder(list, list->size() - 1, &(*i)->empty_folder); |
| 195 } |
| 196 } |
| 197 |
| 198 // FirefoxPlacesV11 |
| 199 FirefoxPlacesV11::FirefoxPlacesV11(const base::FilePath& places_path) |
| 200 : FirefoxPlaces(places_path) {} |
| 201 |
| 202 int FirefoxPlacesV11::GetFolderId(FolderType folder_type) { |
| 203 int folder_id = -1; |
| 204 switch (folder_type) { |
| 205 case FolderType::ROOT: |
| 206 folder_id = LoadNodeIDByName("root"); |
| 207 break; |
| 208 case FolderType::MENU: |
| 209 folder_id = LoadNodeIDByName("menu"); |
| 210 break; |
| 211 case FolderType::TOOLBAR: |
| 212 folder_id = LoadNodeIDByName("toolbar"); |
| 213 break; |
| 214 case FolderType::TAGS: |
| 215 folder_id = LoadNodeIDByName("tags"); |
| 216 break; |
| 217 case FolderType::UNSORTED: |
| 218 folder_id = LoadNodeIDByName("unfiled"); |
| 219 break; |
| 220 default: |
| 221 folder_id = -1; |
| 222 break; |
| 223 } |
| 224 return folder_id; |
| 225 } |
| 226 |
| 227 int FirefoxPlacesV11::LoadNodeIDByName(const std::string& name) { |
| 228 const char query[] = |
| 229 "SELECT folder_id " |
| 230 "FROM moz_bookmarks_roots " |
| 231 "WHERE root_name = ?"; |
| 232 sql::Statement s(db_.GetUniqueStatement(query)); |
| 233 s.BindString(0, name); |
| 234 if (!s.Step()) |
| 235 return -1; |
| 236 return s.ColumnInt(0); |
| 237 } |
| 238 |
| 239 // FirefoxPlacesV25 |
| 240 FirefoxPlacesV25::FirefoxPlacesV25(const base::FilePath& places_path) |
| 241 : FirefoxPlaces(places_path) {} |
| 242 |
| 243 int FirefoxPlacesV25::LoadNodeIDByGUID(const std::string& GUID) { |
| 244 const char query[] = |
| 245 "SELECT id " |
| 246 "FROM moz_bookmarks " |
| 247 "WHERE guid = ?"; |
| 248 sql::Statement s(db_.GetUniqueStatement(query)); |
| 249 s.BindString(0, GUID); |
| 250 |
| 251 if (!s.Step()) |
| 252 return -1; |
| 253 return s.ColumnInt(0); |
| 254 } |
| 255 |
| 256 int FirefoxPlacesV25::GetFolderId(FolderType folder_type) { |
| 257 int folder_id = -1; |
| 258 switch (folder_type) { |
| 259 case FolderType::ROOT: |
| 260 folder_id = LoadNodeIDByGUID("root________"); |
| 261 break; |
| 262 case FolderType::MENU: |
| 263 folder_id = LoadNodeIDByGUID("menu________"); |
| 264 break; |
| 265 case FolderType::TOOLBAR: |
| 266 folder_id = LoadNodeIDByGUID("toolbar_____"); |
| 267 break; |
| 268 case FolderType::TAGS: |
| 269 folder_id = LoadNodeIDByGUID("tags________"); |
| 270 break; |
| 271 case FolderType::UNSORTED: |
| 272 folder_id = LoadNodeIDByGUID("unfiled_____"); |
| 273 break; |
| 274 default: |
| 275 folder_id = -1; |
| 276 break; |
| 277 } |
| 278 return folder_id; |
| 279 } |
| 280 |
| 281 std::unique_ptr<FirefoxPlaces> FirefoxPlacesFactory::GetForProfile( |
| 282 const base::FilePath& profile_path) { |
| 283 base::FilePath places_path = profile_path.AppendASCII("places.sqlite"); |
| 284 if (!base::PathExists(places_path)) |
| 285 return std::unique_ptr<FirefoxPlaces>(); |
| 286 |
| 287 sql::Connection db; |
| 288 if (!db.Open(places_path)) |
| 289 return std::unique_ptr<FirefoxPlaces>(); |
| 290 |
| 291 const std::string schema_version_query{"PRAGMA user_version"}; |
| 292 sql::Statement s(db.GetUniqueStatement(schema_version_query.c_str())); |
| 293 if (!s.is_valid()) |
| 294 return std::unique_ptr<FirefoxPlaces>(); |
| 295 |
| 296 s.Step(); |
| 297 int schema_version = s.ColumnInt(0); |
| 298 s.Clear(); |
| 299 db.Close(); |
| 300 |
| 301 if (schema_version >= 25) { |
| 302 return std::unique_ptr<FirefoxPlaces>(new FirefoxPlacesV25(places_path)); |
| 303 } else if (schema_version >= 11) { |
| 304 return std::unique_ptr<FirefoxPlaces>(new FirefoxPlacesV11(places_path)); |
| 305 } else { |
| 306 return std::unique_ptr<FirefoxPlaces>(); // Same as Firefox, we don't |
| 307 // support schemas earlier than |
| 308 // 11. |
| 309 } |
| 310 } |
OLD | NEW |