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_html_writer.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/platform_file.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_codec.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model_factory.h" 207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/favicon/favicon_service.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h" 239ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/common/favicon/favicon_types.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/file_stream.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/favicon_size.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static BookmarkFaviconFetcher* fetcher = NULL; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// File header. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kHeader[] = 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<!DOCTYPE NETSCAPE-Bookmark-file-1>\r\n" 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<!-- This is an automatically generated file.\r\n" 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " It will be read and overwritten.\r\n" 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " DO NOT EDIT! -->\r\n" 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<META HTTP-EQUIV=\"Content-Type\"" 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " CONTENT=\"text/html; charset=UTF-8\">\r\n" 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<TITLE>Bookmarks</TITLE>\r\n" 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<H1>Bookmarks</H1>\r\n" 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<DL><p>\r\n"; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Newline separator. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNewline[] = "\r\n"; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following are used for bookmarks. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start of a bookmark. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kBookmarkStart[] = "<DT><A HREF=\""; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After kBookmarkStart. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kAddDate[] = "\" ADD_DATE=\""; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After kAddDate. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kIcon[] = "\" ICON=\""; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After kIcon. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kBookmarkAttributeEnd[] = "\">"; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// End of a bookmark. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kBookmarkEnd[] = "</A>"; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following are used when writing folders. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start of a folder. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kFolderStart[] = "<DT><H3 ADD_DATE=\""; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After kFolderStart. 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kLastModified[] = "\" LAST_MODIFIED=\""; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After kLastModified when writing the bookmark bar. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kBookmarkBar[] = "\" PERSONAL_TOOLBAR_FOLDER=\"true\">"; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After kLastModified when writing a user created folder. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kFolderAttributeEnd[] = "\">"; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// End of the folder. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kFolderEnd[] = "</H3>"; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start of the children of a folder. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kFolderChildren[] = "<DL><p>"; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// End of the children for a folder. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kFolderChildrenEnd[] = "</DL><p>"; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Number of characters to indent by. 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kIndentSize = 4; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Class responsible for the actual writing. Takes ownership of favicons_map. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Writer : public base::RefCountedThreadSafe<Writer> { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Writer(base::Value* bookmarks, 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& path, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkFaviconFetcher::URLFaviconMap* favicons_map, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarksExportObserver* observer) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : bookmarks_(bookmarks), 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_(path), 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicons_map_(favicons_map), 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observer_(observer) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Writing bookmarks and favicons data to file. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DoWrite() { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!OpenFile()) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Value* roots = NULL; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Write(kHeader) || 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bookmarks_->GetType() != Value::TYPE_DICTIONARY || 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !static_cast<DictionaryValue*>(bookmarks_.get())->Get( 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkCodec::kRootsKey, &roots) || 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) roots->GetType() != Value::TYPE_DICTIONARY) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryValue* roots_d_value = static_cast<DictionaryValue*>(roots); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Value* root_folder_value; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Value* other_folder_value = NULL; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Value* mobile_folder_value = NULL; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!roots_d_value->Get(BookmarkCodec::kRootFolderNameKey, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &root_folder_value) || 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root_folder_value->GetType() != Value::TYPE_DICTIONARY || 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !roots_d_value->Get(BookmarkCodec::kOtherBookmarkFolderNameKey, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &other_folder_value) || 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other_folder_value->GetType() != Value::TYPE_DICTIONARY || 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !roots_d_value->Get(BookmarkCodec::kMobileBookmarkFolderNameKey, 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &mobile_folder_value) || 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mobile_folder_value->GetType() != Value::TYPE_DICTIONARY) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Invalid type for root folder and/or other folder. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IncrementIndent(); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WriteNode(*static_cast<DictionaryValue*>(root_folder_value), 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode::BOOKMARK_BAR) || 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !WriteNode(*static_cast<DictionaryValue*>(other_folder_value), 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode::OTHER_NODE) || 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !WriteNode(*static_cast<DictionaryValue*>(mobile_folder_value), 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode::MOBILE)) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DecrementIndent(); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Write(kFolderChildrenEnd); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Write(kNewline); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // File stream close is forced so that unit test could read it. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_stream_.reset(); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotifyOnFinish(); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class base::RefCountedThreadSafe<Writer>; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Types of text being written out. The type dictates how the text is 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // escaped. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum TextType { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The text is the value of an html attribute, eg foo in 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // <a href="foo">. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ATTRIBUTE_VALUE, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Actual content, eg foo in <h1>foo</h2>. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CONTENT 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~Writer() {} 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Opens the file, returning true on success. 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool OpenFile() { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_stream_.reset(new net::FileStream(NULL)); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (file_stream_->OpenSync(path_, flags) == net::OK); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Increments the indent. 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void IncrementIndent() { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) indent_.resize(indent_.size() + kIndentSize, ' '); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Decrements the indent. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DecrementIndent() { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!indent_.empty()); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) indent_.resize(indent_.size() - kIndentSize, ' '); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Called at the end of the export process. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void NotifyOnFinish() { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (observer_ != NULL) { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observer_->OnExportFinished(); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Writes raw text out returning true on success. This does not escape 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the text in anyway. 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool Write(const std::string& text) { 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // net::FileStream does not allow 0-byte writes. 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!text.length()) 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t wrote = file_stream_->WriteSync(text.c_str(), text.length()); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = (wrote == text.length()); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(result); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Writes out the text string (as UTF8). The text is escaped based on 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // type. 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool Write(const std::string& text, TextType type) { 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsStringUTF8(text)); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string utf8_string; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type) { 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ATTRIBUTE_VALUE: 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convert " to " 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) utf8_string = text; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReplaceSubstringsAfterOffset(&utf8_string, 0, "\"", """); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CONTENT: 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) utf8_string = net::EscapeForHTML(text); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Write(utf8_string); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Indents the current line. 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool WriteIndent() { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Write(indent_); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Converts a time string written to the JSON codec into a time_t string 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (used by bookmarks.html) and writes it. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool WriteTime(const std::string& time_string) { 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 internal_value; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringToInt64(time_string, &internal_value); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Write(base::Int64ToString( 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time::FromInternalValue(internal_value).ToTimeT())); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Writes the node and all its children, returning true on success. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool WriteNode(const DictionaryValue& value, 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode::Type folder_type) { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string title, date_added_string, type_string; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.GetString(BookmarkCodec::kNameKey, &title) || 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !value.GetString(BookmarkCodec::kDateAddedKey, &date_added_string) || 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !value.GetString(BookmarkCodec::kTypeKey, &type_string) || 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (type_string != BookmarkCodec::kTypeURL && 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_string != BookmarkCodec::kTypeFolder)) { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type_string == BookmarkCodec::kTypeURL) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url_string; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.GetString(BookmarkCodec::kURLKey, &url_string)) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string favicon_string; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkFaviconFetcher::URLFaviconMap::iterator itr = 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicons_map_->find(url_string); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (itr != favicons_map_->end()) { 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::RefCountedMemory> data(itr->second.get()); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string favicon_data; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicon_data.assign(reinterpret_cast<const char*>(data->front()), 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->size()); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string favicon_base64_encoded; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::Base64Encode(favicon_data, &favicon_base64_encoded)) { 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL favicon_url("data:image/png;base64," + favicon_base64_encoded); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicon_string = favicon_url.spec(); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WriteIndent() || 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kBookmarkStart) || 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(url_string, ATTRIBUTE_VALUE) || 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kAddDate) || 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !WriteTime(date_added_string) || 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (!favicon_string.empty() && 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (!Write(kIcon) || 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(favicon_string, ATTRIBUTE_VALUE))) || 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kBookmarkAttributeEnd) || 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(title, CONTENT) || 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kBookmarkEnd) || 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kNewline)) { 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Folder. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string last_modified_date; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Value* child_values = NULL; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.GetString(BookmarkCodec::kDateModifiedKey, 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &last_modified_date) || 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !value.Get(BookmarkCodec::kChildrenKey, &child_values) || 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) child_values->GetType() != Value::TYPE_LIST) { 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (folder_type != BookmarkNode::OTHER_NODE && 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) folder_type != BookmarkNode::MOBILE) { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The other/mobile folder name are not written out. This gives the effect 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of making the contents of the 'other folder' be a sibling to the 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bookmark bar folder. 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WriteIndent() || 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kFolderStart) || 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !WriteTime(date_added_string) || 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kLastModified) || 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !WriteTime(last_modified_date)) { 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (folder_type == BookmarkNode::BOOKMARK_BAR) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Write(kBookmarkBar)) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title = l10n_util::GetStringUTF8(IDS_BOOKMARK_BAR_FOLDER_NAME); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!Write(kFolderAttributeEnd)) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Write(title, CONTENT) || 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kFolderEnd) || 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kNewline) || 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !WriteIndent() || 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kFolderChildren) || 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kNewline)) { 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IncrementIndent(); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write the children. 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ListValue* children = static_cast<const ListValue*>(child_values); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < children->GetSize(); ++i) { 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Value* child_value; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!children->Get(i, &child_value) || 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) child_value->GetType() != Value::TYPE_DICTIONARY) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WriteNode(*static_cast<const DictionaryValue*>(child_value), 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode::FOLDER)) { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (folder_type != BookmarkNode::OTHER_NODE && 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) folder_type != BookmarkNode::MOBILE) { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Close out the folder. 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DecrementIndent(); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!WriteIndent() || 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kFolderChildrenEnd) || 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !Write(kNewline)) { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The BookmarkModel as a Value. This value was generated from the 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BookmarkCodec. 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Value> bookmarks_; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Path we're writing to. 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath path_; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Map that stores favicon per URL. 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<BookmarkFaviconFetcher::URLFaviconMap> favicons_map_; 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Observer to be notified on finish. 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarksExportObserver* observer_; 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // File we're writing to. 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<net::FileStream> file_stream_; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // How much we indent when writing a bookmark/folder. This is modified 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // via IncrementIndent and DecrementIndent. 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string indent_; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Writer); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkFaviconFetcher::BookmarkFaviconFetcher( 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile, 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& path, 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarksExportObserver* observer) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : profile_(profile), 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_(path), 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observer_(observer) { 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicons_map_.reset(new URLFaviconMap()); 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::NOTIFICATION_PROFILE_DESTROYED, 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile_)); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkFaviconFetcher::~BookmarkFaviconFetcher() { 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkFaviconFetcher::ExportBookmarks() { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtractUrls(BookmarkModelFactory::GetForProfile( 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_)->bookmark_bar_node()); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtractUrls(BookmarkModelFactory::GetForProfile(profile_)->other_node()); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtractUrls(BookmarkModelFactory::GetForProfile(profile_)->mobile_node()); 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!bookmark_urls_.empty()) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FetchNextFavicon(); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExecuteWriter(); 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkFaviconFetcher::Observe( 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int type, 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationDetails& details) { 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chrome::NOTIFICATION_PROFILE_DESTROYED == type && fetcher != NULL) { 42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher = NULL; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkFaviconFetcher::ExtractUrls(const BookmarkNode* node) { 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->is_url()) { 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url = node->url().spec(); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!url.empty()) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bookmark_urls_.push_back(url); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < node->child_count(); ++i) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtractUrls(node->GetChild(i)); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkFaviconFetcher::ExecuteWriter() { 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BookmarkModel isn't thread safe (nor would we want to lock it down 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for the duration of the write), as such we make a copy of the 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BookmarkModel using BookmarkCodec then write from that. 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkCodec codec; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&Writer::DoWrite, 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new Writer(codec.Encode(BookmarkModelFactory::GetForProfile( 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_)), 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_, favicons_map_.release(), observer_))); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fetcher != NULL) { 44890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher); 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher = NULL; 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkFaviconFetcher::FetchNextFavicon() { 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bookmark_urls_.empty()) { 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url = bookmark_urls_.front(); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Filter out urls that we've already got favicon for. 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) URLFaviconMap::const_iterator iter = favicons_map_->find(url); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (favicons_map_->end() == iter) { 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_, Profile::EXPLICIT_ACCESS); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicon_service->GetRawFaviconForURL( 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FaviconService::FaviconForURLParams( 46690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) profile_, GURL(url), chrome::FAVICON, gfx::kFaviconSize), 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::SCALE_FACTOR_100P, 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&BookmarkFaviconFetcher::OnFaviconDataAvailable, 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this)), 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &cancelable_task_tracker_); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bookmark_urls_.pop_front(); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (!bookmark_urls_.empty()); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkFaviconFetcher::OnFaviconDataAvailable( 48090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const chrome::FaviconBitmapResult& bitmap_result) { 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL url; 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!bookmark_urls_.empty()) { 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url = GURL(bookmark_urls_.front()); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bookmark_urls_.pop_front(); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bitmap_result.is_valid() && !url.is_empty()) { 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicons_map_->insert( 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_pair(url.spec(), bitmap_result.bitmap_data)); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FetchNextFavicon()) { 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExecuteWriter(); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace bookmark_html_writer { 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteBookmarks(Profile* profile, 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& path, 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarksExportObserver* observer) { 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BookmarkModel isn't thread safe (nor would we want to lock it down 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for the duration of the write), as such we make a copy of the 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BookmarkModel using BookmarkCodec then write from that. 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fetcher == NULL) { 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher = new BookmarkFaviconFetcher(profile, path, observer); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher->ExportBookmarks(); 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace bookmark_html_writer 512