Home | History | Annotate | Download | only in importer
      1 // Copyright (c) 2012 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/ie_importer_win.h"
      6 
      7 #include <ole2.h>
      8 #include <intshcut.h>
      9 #include <shlobj.h>
     10 #include <urlhist.h>
     11 #include <wininet.h>
     12 
     13 #include <algorithm>
     14 #include <map>
     15 #include <string>
     16 #include <vector>
     17 
     18 #include "base/file_util.h"
     19 #include "base/files/file_enumerator.h"
     20 #include "base/files/file_path.h"
     21 #include "base/strings/string16.h"
     22 #include "base/strings/string_split.h"
     23 #include "base/strings/string_util.h"
     24 #include "base/strings/utf_string_conversions.h"
     25 #include "base/time/time.h"
     26 #include "base/win/registry.h"
     27 #include "base/win/scoped_co_mem.h"
     28 #include "base/win/scoped_comptr.h"
     29 #include "base/win/scoped_handle.h"
     30 #include "base/win/scoped_propvariant.h"
     31 #include "base/win/windows_version.h"
     32 #include "chrome/common/importer/ie_importer_utils_win.h"
     33 #include "chrome/common/importer/imported_bookmark_entry.h"
     34 #include "chrome/common/importer/imported_favicon_usage.h"
     35 #include "chrome/common/importer/importer_bridge.h"
     36 #include "chrome/common/importer/importer_data_types.h"
     37 #include "chrome/common/importer/importer_url_row.h"
     38 #include "chrome/common/importer/pstore_declarations.h"
     39 #include "chrome/common/url_constants.h"
     40 #include "chrome/utility/importer/favicon_reencode.h"
     41 #include "content/public/common/password_form.h"
     42 #include "grit/generated_resources.h"
     43 #include "ui/base/l10n/l10n_util.h"
     44 #include "url/gurl.h"
     45 
     46 namespace {
     47 
     48 // Registry key paths from which we import IE settings.
     49 const char16 kSearchScopePath[] =
     50   L"Software\\Microsoft\\Internet Explorer\\SearchScopes";
     51 const char16 kIEVersionKey[] =
     52   L"Software\\Microsoft\\Internet Explorer";
     53 const char16 kIEToolbarKey[] =
     54   L"Software\\Microsoft\\Internet Explorer\\Toolbar";
     55 
     56 // NTFS stream name of favicon image data.
     57 const char16 kFaviconStreamName[] = L":favicon:$DATA";
     58 
     59 // A struct that hosts the information of AutoComplete data in PStore.
     60 struct AutoCompleteInfo {
     61   string16 key;
     62   std::vector<string16> data;
     63   bool is_url;
     64 };
     65 
     66 // Gets the creation time of the given file or directory.
     67 base::Time GetFileCreationTime(const string16& file) {
     68   base::Time creation_time;
     69   base::win::ScopedHandle file_handle(
     70       CreateFile(file.c_str(), GENERIC_READ,
     71                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     72                  NULL, OPEN_EXISTING,
     73                  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL));
     74   FILETIME creation_filetime;
     75   if (GetFileTime(file_handle, &creation_filetime, NULL, NULL))
     76     creation_time = base::Time::FromFileTime(creation_filetime);
     77   return creation_time;
     78 }
     79 
     80 // Safely read an object of type T from a raw sequence of bytes.
     81 template<typename T>
     82 bool BinaryRead(T* data, size_t offset, const std::vector<uint8>& blob) {
     83   if (offset + sizeof(T) > blob.size())
     84     return false;
     85   memcpy(data, &blob[offset], sizeof(T));
     86   return true;
     87 }
     88 
     89 // Safely read an ITEMIDLIST from a raw sequence of bytes.
     90 //
     91 // An ITEMIDLIST is a list of SHITEMIDs, terminated by a SHITEMID with
     92 // .cb = 0. Here, before simply casting &blob[offset] to LPITEMIDLIST,
     93 // we verify that the list structure is not overrunning the boundary of
     94 // the binary blob.
     95 LPCITEMIDLIST BinaryReadItemIDList(size_t offset, size_t idlist_size,
     96                                    const std::vector<uint8>& blob) {
     97   size_t head = 0;
     98   while (true) {
     99     // Use a USHORT instead of SHITEMID to avoid buffer over read.
    100     USHORT id_cb;
    101     if (head >= idlist_size || !BinaryRead(&id_cb, offset + head, blob))
    102       return NULL;
    103     if (id_cb == 0)
    104       break;
    105     head += id_cb;
    106   }
    107   return reinterpret_cast<LPCITEMIDLIST>(&blob[offset]);
    108 }
    109 
    110 // Compares the two bookmarks in the order of IE's Favorites menu.
    111 // Returns true if rhs should come later than lhs (lhs < rhs).
    112 struct IEOrderBookmarkComparator {
    113   bool operator()(const ImportedBookmarkEntry& lhs,
    114                   const ImportedBookmarkEntry& rhs) const {
    115     static const uint32 kNotSorted = 0xfffffffb; // IE uses this magic value.
    116     base::FilePath lhs_prefix;
    117     base::FilePath rhs_prefix;
    118     for (size_t i = 0; i <= lhs.path.size() && i <= rhs.path.size(); ++i) {
    119       const base::FilePath::StringType lhs_i =
    120         (i < lhs.path.size() ? lhs.path[i] : lhs.title + L".url");
    121       const base::FilePath::StringType rhs_i =
    122         (i < rhs.path.size() ? rhs.path[i] : rhs.title + L".url");
    123       lhs_prefix = lhs_prefix.Append(lhs_i);
    124       rhs_prefix = rhs_prefix.Append(rhs_i);
    125       if (lhs_i == rhs_i)
    126         continue;
    127       // The first path element that differs between the two.
    128       std::map<base::FilePath, uint32>::const_iterator lhs_iter =
    129         sort_index_->find(lhs_prefix);
    130       std::map<base::FilePath, uint32>::const_iterator rhs_iter =
    131         sort_index_->find(rhs_prefix);
    132       uint32 lhs_sort_index = (lhs_iter == sort_index_->end() ? kNotSorted
    133         : lhs_iter->second);
    134       uint32 rhs_sort_index = (rhs_iter == sort_index_->end() ? kNotSorted
    135         : rhs_iter->second);
    136       if (lhs_sort_index != rhs_sort_index)
    137         return lhs_sort_index < rhs_sort_index;
    138       // If they have the same sort order, sort alphabetically.
    139       return lhs_i < rhs_i;
    140     }
    141     return lhs.path.size() < rhs.path.size();
    142   }
    143   const std::map<base::FilePath, uint32>* sort_index_;
    144 };
    145 
    146 // IE stores the order of the Favorites menu in registry under:
    147 // HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites.
    148 // The folder hierarchy of Favorites menu is directly mapped to the key
    149 // hierarchy in the registry.
    150 //
    151 // If the order of the items in a folder is customized by user, the order is
    152 // recorded in the REG_BINARY value named "Order" of the corresponding key.
    153 // The content of the "Order" value is a raw binary dump of an array of the
    154 // following data structure
    155 //   struct {
    156 //     uint32 size;  // Note that ITEMIDLIST is variably-sized.
    157 //     uint32 sort_index;  // 0 means this is the first item, 1 the second, ...
    158 //     ITEMIDLIST item_id;
    159 //   };
    160 // where each item_id should correspond to a favorites link file (*.url) in
    161 // the current folder.
    162 bool ParseFavoritesOrderBlob(
    163     const Importer* importer,
    164     const std::vector<uint8>& blob,
    165     const base::FilePath& path,
    166     std::map<base::FilePath, uint32>* sort_index) WARN_UNUSED_RESULT {
    167   static const int kItemCountOffset = 16;
    168   static const int kItemListStartOffset = 20;
    169 
    170   // Read the number of items.
    171   uint32 item_count = 0;
    172   if (!BinaryRead(&item_count, kItemCountOffset, blob))
    173     return false;
    174 
    175   // Traverse over the items.
    176   size_t base_offset = kItemListStartOffset;
    177   for (uint32 i = 0; i < item_count && !importer->cancelled(); ++i) {
    178     static const int kSizeOffset = 0;
    179     static const int kSortIndexOffset = 4;
    180     static const int kItemIDListOffset = 8;
    181 
    182     // Read the size (number of bytes) of the current item.
    183     uint32 item_size = 0;
    184     if (!BinaryRead(&item_size, base_offset + kSizeOffset, blob) ||
    185         base_offset + item_size <= base_offset || // checking overflow
    186         base_offset + item_size > blob.size())
    187       return false;
    188 
    189     // Read the sort index of the current item.
    190     uint32 item_sort_index = 0;
    191     if (!BinaryRead(&item_sort_index, base_offset + kSortIndexOffset, blob))
    192       return false;
    193 
    194     // Read the file name from the ITEMIDLIST structure.
    195     LPCITEMIDLIST idlist = BinaryReadItemIDList(
    196       base_offset + kItemIDListOffset, item_size - kItemIDListOffset, blob);
    197     TCHAR item_filename[MAX_PATH];
    198     if (!idlist || FAILED(SHGetPathFromIDList(idlist, item_filename)))
    199       return false;
    200     base::FilePath item_relative_path =
    201       path.Append(base::FilePath(item_filename).BaseName());
    202 
    203     // Record the retrieved information and go to the next item.
    204     sort_index->insert(std::make_pair(item_relative_path, item_sort_index));
    205     base_offset += item_size;
    206   }
    207   return true;
    208 }
    209 
    210 bool ParseFavoritesOrderRegistryTree(
    211     const Importer* importer,
    212     const base::win::RegKey& key,
    213     const base::FilePath& path,
    214     std::map<base::FilePath, uint32>* sort_index) WARN_UNUSED_RESULT {
    215   // Parse the order information of the current folder.
    216   DWORD blob_length = 0;
    217   if (key.ReadValue(L"Order", NULL, &blob_length, NULL) == ERROR_SUCCESS) {
    218     std::vector<uint8> blob(blob_length);
    219     if (blob_length > 0 &&
    220         key.ReadValue(L"Order", reinterpret_cast<DWORD*>(&blob[0]),
    221                       &blob_length, NULL) == ERROR_SUCCESS) {
    222       if (!ParseFavoritesOrderBlob(importer, blob, path, sort_index))
    223         return false;
    224     }
    225   }
    226 
    227   // Recursively parse subfolders.
    228   for (base::win::RegistryKeyIterator child(key.Handle(), L"");
    229        child.Valid() && !importer->cancelled();
    230        ++child) {
    231     base::win::RegKey subkey(key.Handle(), child.Name(), KEY_READ);
    232     if (subkey.Valid()) {
    233       base::FilePath subpath(path.Append(child.Name()));
    234       if (!ParseFavoritesOrderRegistryTree(importer, subkey, subpath,
    235                                            sort_index)) {
    236         return false;
    237       }
    238     }
    239   }
    240   return true;
    241 }
    242 
    243 bool ParseFavoritesOrderInfo(
    244     const Importer* importer,
    245     std::map<base::FilePath, uint32>* sort_index) WARN_UNUSED_RESULT {
    246   base::string16 key_path(importer::GetIEFavoritesOrderKey());
    247   base::win::RegKey key(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ);
    248   if (!key.Valid())
    249     return false;
    250   return ParseFavoritesOrderRegistryTree(importer, key, base::FilePath(),
    251                                          sort_index);
    252 }
    253 
    254 // Reads the sort order from registry. If failed, we don't touch the list
    255 // and use the default (alphabetical) order.
    256 void SortBookmarksInIEOrder(
    257     const Importer* importer,
    258     std::vector<ImportedBookmarkEntry>* bookmarks) {
    259   std::map<base::FilePath, uint32> sort_index;
    260   if (!ParseFavoritesOrderInfo(importer, &sort_index))
    261     return;
    262   IEOrderBookmarkComparator compare = {&sort_index};
    263   std::sort(bookmarks->begin(), bookmarks->end(), compare);
    264 }
    265 
    266 // Reads an internet shortcut (*.url) |file| and returns a COM object
    267 // representing it.
    268 bool LoadInternetShortcut(
    269     const string16& file,
    270     base::win::ScopedComPtr<IUniformResourceLocator>* shortcut) {
    271   base::win::ScopedComPtr<IUniformResourceLocator> url_locator;
    272   if (FAILED(url_locator.CreateInstance(CLSID_InternetShortcut, NULL,
    273                                         CLSCTX_INPROC_SERVER)))
    274     return false;
    275 
    276   base::win::ScopedComPtr<IPersistFile> persist_file;
    277   if (FAILED(persist_file.QueryFrom(url_locator)))
    278     return false;
    279 
    280   // Loads the Internet Shortcut from persistent storage.
    281   if (FAILED(persist_file->Load(file.c_str(), STGM_READ)))
    282     return false;
    283 
    284   std::swap(url_locator, *shortcut);
    285   return true;
    286 }
    287 
    288 // Reads the URL stored in the internet shortcut.
    289 GURL ReadURLFromInternetShortcut(IUniformResourceLocator* url_locator) {
    290   base::win::ScopedCoMem<wchar_t> url;
    291   // GetURL can return S_FALSE (FAILED(S_FALSE) is false) when url == NULL.
    292   return (FAILED(url_locator->GetURL(&url)) || !url) ?
    293       GURL() : GURL(WideToUTF16(std::wstring(url)));
    294 }
    295 
    296 // Reads the URL of the favicon of the internet shortcut.
    297 GURL ReadFaviconURLFromInternetShortcut(IUniformResourceLocator* url_locator) {
    298   base::win::ScopedComPtr<IPropertySetStorage> property_set_storage;
    299   if (FAILED(property_set_storage.QueryFrom(url_locator)))
    300     return GURL();
    301 
    302   base::win::ScopedComPtr<IPropertyStorage> property_storage;
    303   if (FAILED(property_set_storage->Open(FMTID_Intshcut, STGM_READ,
    304                                         property_storage.Receive()))) {
    305     return GURL();
    306   }
    307 
    308   PROPSPEC properties[] = {{PRSPEC_PROPID, PID_IS_ICONFILE}};
    309   // ReadMultiple takes a non-const array of PROPVARIANTs, but since this code
    310   // only needs an array of size 1: a non-const pointer to |output| is
    311   // equivalent.
    312   base::win::ScopedPropVariant output;
    313   // ReadMultiple can return S_FALSE (FAILED(S_FALSE) is false) when the
    314   // property is not found, in which case output[0].vt is set to VT_EMPTY.
    315   if (FAILED(property_storage->ReadMultiple(1, properties, output.Receive())) ||
    316       output.get().vt != VT_LPWSTR)
    317     return GURL();
    318   return GURL(WideToUTF16(output.get().pwszVal));
    319 }
    320 
    321 // Reads the favicon imaga data in an NTFS alternate data stream. This is where
    322 // IE7 and above store the data.
    323 bool ReadFaviconDataFromInternetShortcut(const string16& file,
    324                                          std::string* data) {
    325   return file_util::ReadFileToString(
    326       base::FilePath(file + kFaviconStreamName), data);
    327 }
    328 
    329 // Reads the favicon imaga data in the Internet cache. IE6 doesn't hold the data
    330 // explicitly, but it might be found in the cache.
    331 bool ReadFaviconDataFromCache(const GURL& favicon_url, std::string* data) {
    332   std::wstring url_wstring(UTF8ToWide(favicon_url.spec()));
    333   DWORD info_size = 0;
    334   GetUrlCacheEntryInfoEx(url_wstring.c_str(), NULL, &info_size, NULL, NULL,
    335                          NULL, 0);
    336   if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    337     return false;
    338 
    339   std::vector<char> buf(info_size);
    340   INTERNET_CACHE_ENTRY_INFO* cache =
    341       reinterpret_cast<INTERNET_CACHE_ENTRY_INFO*>(&buf[0]);
    342   if (!GetUrlCacheEntryInfoEx(url_wstring.c_str(), cache, &info_size, NULL,
    343                               NULL, NULL, 0)) {
    344     return false;
    345   }
    346   return file_util::ReadFileToString(base::FilePath(cache->lpszLocalFileName),
    347                                      data);
    348 }
    349 
    350 // Reads the binary image data of favicon of an internet shortcut file |file|.
    351 // |favicon_url| read by ReadFaviconURLFromInternetShortcut is also needed to
    352 // examine the IE cache.
    353 bool ReadReencodedFaviconData(const string16& file,
    354                               const GURL& favicon_url,
    355                               std::vector<unsigned char>* data) {
    356   std::string image_data;
    357   if (!ReadFaviconDataFromInternetShortcut(file, &image_data) &&
    358       !ReadFaviconDataFromCache(favicon_url, &image_data)) {
    359     return false;
    360   }
    361 
    362   const unsigned char* ptr =
    363       reinterpret_cast<const unsigned char*>(image_data.c_str());
    364   return importer::ReencodeFavicon(ptr, image_data.size(), data);
    365 }
    366 
    367 // Loads favicon image data and registers to |favicon_map|.
    368 void UpdateFaviconMap(
    369     const string16& url_file,
    370     const GURL& url,
    371     IUniformResourceLocator* url_locator,
    372     std::map<GURL, ImportedFaviconUsage>* favicon_map) {
    373   GURL favicon_url = ReadFaviconURLFromInternetShortcut(url_locator);
    374   if (!favicon_url.is_valid())
    375     return;
    376 
    377   std::map<GURL, ImportedFaviconUsage>::iterator it =
    378     favicon_map->find(favicon_url);
    379   if (it != favicon_map->end()) {
    380     // Known favicon URL.
    381     it->second.urls.insert(url);
    382   } else {
    383     // New favicon URL. Read the image data and store.
    384     ImportedFaviconUsage usage;
    385     if (ReadReencodedFaviconData(url_file, favicon_url, &usage.png_data)) {
    386       usage.favicon_url = favicon_url;
    387       usage.urls.insert(url);
    388       favicon_map->insert(std::make_pair(favicon_url, usage));
    389     }
    390   }
    391 }
    392 
    393 }  // namespace
    394 
    395 // static
    396 // {E161255A-37C3-11D2-BCAA-00C04fD929DB}
    397 const GUID IEImporter::kPStoreAutocompleteGUID = {
    398     0xe161255a, 0x37c3, 0x11d2,
    399     { 0xbc, 0xaa, 0x00, 0xc0, 0x4f, 0xd9, 0x29, 0xdb }
    400 };
    401 // {A79029D6-753E-4e27-B807-3D46AB1545DF}
    402 const GUID IEImporter::kUnittestGUID = {
    403     0xa79029d6, 0x753e, 0x4e27,
    404     { 0xb8, 0x7, 0x3d, 0x46, 0xab, 0x15, 0x45, 0xdf }
    405 };
    406 
    407 IEImporter::IEImporter() {
    408 }
    409 
    410 void IEImporter::StartImport(const importer::SourceProfile& source_profile,
    411                              uint16 items,
    412                              ImporterBridge* bridge) {
    413   bridge_ = bridge;
    414   source_path_ = source_profile.source_path;
    415 
    416   bridge_->NotifyStarted();
    417 
    418   if ((items & importer::HOME_PAGE) && !cancelled()) {
    419     bridge_->NotifyItemStarted(importer::HOME_PAGE);
    420     ImportHomepage();  // Doesn't have a UI item.
    421     bridge_->NotifyItemEnded(importer::HOME_PAGE);
    422   }
    423   // The order here is important!
    424   if ((items & importer::HISTORY) && !cancelled()) {
    425     bridge_->NotifyItemStarted(importer::HISTORY);
    426     ImportHistory();
    427     bridge_->NotifyItemEnded(importer::HISTORY);
    428   }
    429   if ((items & importer::FAVORITES) && !cancelled()) {
    430     bridge_->NotifyItemStarted(importer::FAVORITES);
    431     ImportFavorites();
    432     bridge_->NotifyItemEnded(importer::FAVORITES);
    433   }
    434   if ((items & importer::SEARCH_ENGINES) && !cancelled()) {
    435     bridge_->NotifyItemStarted(importer::SEARCH_ENGINES);
    436     ImportSearchEngines();
    437     bridge_->NotifyItemEnded(importer::SEARCH_ENGINES);
    438   }
    439   if ((items & importer::PASSWORDS) && !cancelled()) {
    440     bridge_->NotifyItemStarted(importer::PASSWORDS);
    441     // Always import IE6 passwords.
    442     ImportPasswordsIE6();
    443 
    444     if (CurrentIEVersion() >= 7)
    445       ImportPasswordsIE7();
    446     bridge_->NotifyItemEnded(importer::PASSWORDS);
    447   }
    448   bridge_->NotifyEnded();
    449 }
    450 
    451 IEImporter::~IEImporter() {
    452 }
    453 
    454 void IEImporter::ImportFavorites() {
    455   FavoritesInfo info;
    456   if (!GetFavoritesInfo(&info))
    457     return;
    458 
    459   BookmarkVector bookmarks;
    460   std::vector<ImportedFaviconUsage> favicons;
    461   ParseFavoritesFolder(info, &bookmarks, &favicons);
    462 
    463   if (!bookmarks.empty() && !cancelled()) {
    464     const string16& first_folder_name =
    465         l10n_util::GetStringUTF16(IDS_BOOKMARK_GROUP_FROM_IE);
    466     bridge_->AddBookmarks(bookmarks, first_folder_name);
    467   }
    468   if (!favicons.empty() && !cancelled())
    469     bridge_->SetFavicons(favicons);
    470 }
    471 
    472 void IEImporter::ImportHistory() {
    473   const std::string kSchemes[] = {chrome::kHttpScheme,
    474                                   chrome::kHttpsScheme,
    475                                   chrome::kFtpScheme,
    476                                   chrome::kFileScheme};
    477   int total_schemes = arraysize(kSchemes);
    478 
    479   base::win::ScopedComPtr<IUrlHistoryStg2> url_history_stg2;
    480   HRESULT result;
    481   result = url_history_stg2.CreateInstance(CLSID_CUrlHistory, NULL,
    482                                            CLSCTX_INPROC_SERVER);
    483   if (FAILED(result))
    484     return;
    485   base::win::ScopedComPtr<IEnumSTATURL> enum_url;
    486   if (SUCCEEDED(result = url_history_stg2->EnumUrls(enum_url.Receive()))) {
    487     std::vector<ImporterURLRow> rows;
    488     STATURL stat_url;
    489     ULONG fetched;
    490     while (!cancelled() &&
    491            (result = enum_url->Next(1, &stat_url, &fetched)) == S_OK) {
    492       string16 url_string;
    493       if (stat_url.pwcsUrl) {
    494         url_string = stat_url.pwcsUrl;
    495         CoTaskMemFree(stat_url.pwcsUrl);
    496       }
    497       string16 title_string;
    498       if (stat_url.pwcsTitle) {
    499         title_string = stat_url.pwcsTitle;
    500         CoTaskMemFree(stat_url.pwcsTitle);
    501       }
    502 
    503       GURL url(url_string);
    504       // Skips the URLs that are invalid or have other schemes.
    505       if (!url.is_valid() ||
    506           (std::find(kSchemes, kSchemes + total_schemes, url.scheme()) ==
    507            kSchemes + total_schemes))
    508         continue;
    509 
    510       ImporterURLRow row(url);
    511       row.title = title_string;
    512       row.last_visit = base::Time::FromFileTime(stat_url.ftLastVisited);
    513       if (stat_url.dwFlags == STATURL_QUERYFLAG_TOPLEVEL) {
    514         row.visit_count = 1;
    515         row.hidden = false;
    516       } else {
    517         row.hidden = true;
    518       }
    519 
    520       rows.push_back(row);
    521     }
    522 
    523     if (!rows.empty() && !cancelled()) {
    524       bridge_->SetHistoryItems(rows, importer::VISIT_SOURCE_IE_IMPORTED);
    525     }
    526   }
    527 }
    528 
    529 void IEImporter::ImportPasswordsIE6() {
    530   GUID AutocompleteGUID = kPStoreAutocompleteGUID;
    531   if (!source_path_.empty()) {
    532     // We supply a fake GUID for testting.
    533     AutocompleteGUID = kUnittestGUID;
    534   }
    535 
    536   // The PStoreCreateInstance function retrieves an interface pointer
    537   // to a storage provider. But this function has no associated import
    538   // library or header file, we must call it using the LoadLibrary()
    539   // and GetProcAddress() functions.
    540   typedef HRESULT (WINAPI *PStoreCreateFunc)(IPStore**, DWORD, DWORD, DWORD);
    541   HMODULE pstorec_dll = LoadLibrary(L"pstorec.dll");
    542   if (!pstorec_dll)
    543     return;
    544   PStoreCreateFunc PStoreCreateInstance =
    545       (PStoreCreateFunc)GetProcAddress(pstorec_dll, "PStoreCreateInstance");
    546   if (!PStoreCreateInstance) {
    547     FreeLibrary(pstorec_dll);
    548     return;
    549   }
    550 
    551   base::win::ScopedComPtr<IPStore, &IID_IPStore> pstore;
    552   HRESULT result = PStoreCreateInstance(pstore.Receive(), 0, 0, 0);
    553   if (result != S_OK) {
    554     FreeLibrary(pstorec_dll);
    555     return;
    556   }
    557 
    558   std::vector<AutoCompleteInfo> ac_list;
    559 
    560   // Enumerates AutoComplete items in the protected database.
    561   base::win::ScopedComPtr<IEnumPStoreItems, &IID_IEnumPStoreItems> item;
    562   result = pstore->EnumItems(0, &AutocompleteGUID,
    563                              &AutocompleteGUID, 0, item.Receive());
    564   if (result != PST_E_OK) {
    565     pstore.Release();
    566     FreeLibrary(pstorec_dll);
    567     return;
    568   }
    569 
    570   wchar_t* item_name;
    571   while (!cancelled() && SUCCEEDED(item->Next(1, &item_name, 0))) {
    572     DWORD length = 0;
    573     unsigned char* buffer = NULL;
    574     result = pstore->ReadItem(0, &AutocompleteGUID, &AutocompleteGUID,
    575                               item_name, &length, &buffer, NULL, 0);
    576     if (SUCCEEDED(result)) {
    577       AutoCompleteInfo ac;
    578       ac.key = item_name;
    579       string16 data;
    580       data.insert(0, reinterpret_cast<wchar_t*>(buffer),
    581                   length / sizeof(wchar_t));
    582 
    583       // The key name is always ended with ":StringData".
    584       const wchar_t kDataSuffix[] = L":StringData";
    585       size_t i = ac.key.rfind(kDataSuffix);
    586       if (i != string16::npos && ac.key.substr(i) == kDataSuffix) {
    587         ac.key.erase(i);
    588         ac.is_url = (ac.key.find(L"://") != string16::npos);
    589         ac_list.push_back(ac);
    590         base::SplitString(data, L'\0', &ac_list[ac_list.size() - 1].data);
    591       }
    592       CoTaskMemFree(buffer);
    593     }
    594     CoTaskMemFree(item_name);
    595   }
    596   // Releases them before unload the dll.
    597   item.Release();
    598   pstore.Release();
    599   FreeLibrary(pstorec_dll);
    600 
    601   size_t i;
    602   for (i = 0; i < ac_list.size(); i++) {
    603     if (!ac_list[i].is_url || ac_list[i].data.size() < 2)
    604       continue;
    605 
    606     GURL url(ac_list[i].key.c_str());
    607     if (!(LowerCaseEqualsASCII(url.scheme(), chrome::kHttpScheme) ||
    608         LowerCaseEqualsASCII(url.scheme(), chrome::kHttpsScheme))) {
    609       continue;
    610     }
    611 
    612     content::PasswordForm form;
    613     GURL::Replacements rp;
    614     rp.ClearUsername();
    615     rp.ClearPassword();
    616     rp.ClearQuery();
    617     rp.ClearRef();
    618     form.origin = url.ReplaceComponents(rp);
    619     form.username_value = ac_list[i].data[0];
    620     form.password_value = ac_list[i].data[1];
    621     form.signon_realm = url.GetOrigin().spec();
    622 
    623     // This is not precise, because a scheme of https does not imply a valid
    624     // certificate was presented; however we assign it this way so that if we
    625     // import a password from IE whose scheme is https, we give it the benefit
    626     // of the doubt and DONT auto-fill it unless the form appears under
    627     // valid SSL conditions.
    628     form.ssl_valid = url.SchemeIsSecure();
    629 
    630     // Goes through the list to find out the username field
    631     // of the web page.
    632     size_t list_it, item_it;
    633     for (list_it = 0; list_it < ac_list.size(); ++list_it) {
    634       if (ac_list[list_it].is_url)
    635         continue;
    636 
    637       for (item_it = 0; item_it < ac_list[list_it].data.size(); ++item_it)
    638         if (ac_list[list_it].data[item_it] == form.username_value) {
    639           form.username_element = ac_list[list_it].key;
    640           break;
    641         }
    642     }
    643 
    644     bridge_->SetPasswordForm(form);
    645   }
    646 }
    647 
    648 void IEImporter::ImportPasswordsIE7() {
    649   base::string16 key_path(importer::GetIE7PasswordsKey());
    650   base::win::RegKey key(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ);
    651   base::win::RegistryValueIterator reg_iterator(HKEY_CURRENT_USER,
    652                                                 key_path.c_str());
    653   importer::ImporterIE7PasswordInfo password_info;
    654   while (reg_iterator.Valid() && !cancelled()) {
    655     // Get the size of the encrypted data.
    656     DWORD value_len = 0;
    657     key.ReadValue(reg_iterator.Name(), NULL, &value_len, NULL);
    658     if (value_len) {
    659       // Query the encrypted data.
    660       password_info.encrypted_data.resize(value_len);
    661       if (key.ReadValue(reg_iterator.Name(),
    662                         &password_info.encrypted_data.front(),
    663                         &value_len, NULL) == ERROR_SUCCESS) {
    664         password_info.url_hash = reg_iterator.Name();
    665         password_info.date_created = base::Time::Now();
    666 
    667         bridge_->AddIE7PasswordInfo(password_info);
    668       }
    669     }
    670 
    671     ++reg_iterator;
    672   }
    673 }
    674 
    675 void IEImporter::ImportSearchEngines() {
    676   // On IE, search engines are stored in the registry, under:
    677   // Software\Microsoft\Internet Explorer\SearchScopes
    678   // Each key represents a search engine. The URL value contains the URL and
    679   // the DisplayName the name.
    680   typedef std::map<std::string, string16> SearchEnginesMap;
    681   SearchEnginesMap search_engines_map;
    682   for (base::win::RegistryKeyIterator key_iter(HKEY_CURRENT_USER,
    683        kSearchScopePath); key_iter.Valid(); ++key_iter) {
    684     string16 sub_key_name = kSearchScopePath;
    685     sub_key_name.append(L"\\").append(key_iter.Name());
    686     base::win::RegKey sub_key(HKEY_CURRENT_USER, sub_key_name.c_str(),
    687                               KEY_READ);
    688     string16 wide_url;
    689     if ((sub_key.ReadValue(L"URL", &wide_url) != ERROR_SUCCESS) ||
    690         wide_url.empty()) {
    691       VLOG(1) << "No URL for IE search engine at " << key_iter.Name();
    692       continue;
    693     }
    694     // For the name, we try the default value first (as Live Search uses a
    695     // non displayable name in DisplayName, and the readable name under the
    696     // default value).
    697     string16 name;
    698     if ((sub_key.ReadValue(NULL, &name) != ERROR_SUCCESS) || name.empty()) {
    699       // Try the displayable name.
    700       if ((sub_key.ReadValue(L"DisplayName", &name) != ERROR_SUCCESS) ||
    701           name.empty()) {
    702         VLOG(1) << "No name for IE search engine at " << key_iter.Name();
    703         continue;
    704       }
    705     }
    706 
    707     std::string url(WideToUTF8(wide_url));
    708     SearchEnginesMap::iterator t_iter = search_engines_map.find(url);
    709     if (t_iter == search_engines_map.end()) {
    710       // First time we see that URL.
    711       GURL gurl(url);
    712       if (gurl.is_valid()) {
    713         t_iter = search_engines_map.insert(std::make_pair(url, name)).first;
    714       }
    715     }
    716   }
    717   // ProfileWriter::AddKeywords() requires a vector and we have a map.
    718   std::vector<importer::URLKeywordInfo> url_keywords;
    719   for (SearchEnginesMap::iterator i = search_engines_map.begin();
    720        i != search_engines_map.end(); ++i) {
    721     importer::URLKeywordInfo url_keyword_info;
    722     url_keyword_info.url = GURL(i->first);
    723     url_keyword_info.display_name = i->second;
    724     url_keywords.push_back(url_keyword_info);
    725   }
    726   bridge_->SetKeywords(url_keywords, true);
    727 }
    728 
    729 void IEImporter::ImportHomepage() {
    730   const wchar_t* kIEHomepage = L"Start Page";
    731   const wchar_t* kIEDefaultHomepage = L"Default_Page_URL";
    732 
    733   base::string16 key_path(importer::GetIESettingsKey());
    734 
    735   base::win::RegKey key(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ);
    736   string16 homepage_url;
    737   if (key.ReadValue(kIEHomepage, &homepage_url) != ERROR_SUCCESS ||
    738       homepage_url.empty())
    739     return;
    740 
    741   GURL homepage = GURL(homepage_url);
    742   if (!homepage.is_valid())
    743     return;
    744 
    745   // Check to see if this is the default website and skip import.
    746   base::win::RegKey keyDefault(HKEY_LOCAL_MACHINE, key_path.c_str(), KEY_READ);
    747   string16 default_homepage_url;
    748   LONG result = keyDefault.ReadValue(kIEDefaultHomepage, &default_homepage_url);
    749   if (result == ERROR_SUCCESS && !default_homepage_url.empty()) {
    750     if (homepage.spec() == GURL(default_homepage_url).spec())
    751       return;
    752   }
    753   bridge_->AddHomePage(homepage);
    754 }
    755 
    756 bool IEImporter::GetFavoritesInfo(IEImporter::FavoritesInfo* info) {
    757   if (!source_path_.empty()) {
    758     // Source path exists during testing.
    759     info->path = source_path_;
    760     info->path = info->path.AppendASCII("Favorites");
    761     info->links_folder = L"Links";
    762     return true;
    763   }
    764 
    765   // IE stores the favorites in the Favorites under user profile's folder.
    766   wchar_t buffer[MAX_PATH];
    767   if (FAILED(SHGetFolderPath(NULL, CSIDL_FAVORITES, NULL,
    768                              SHGFP_TYPE_CURRENT, buffer)))
    769     return false;
    770   info->path = base::FilePath(buffer);
    771 
    772   // There is a Links folder under Favorites folder in Windows Vista, but it
    773   // is not recording in Vista's registry. So in Vista, we assume the Links
    774   // folder is under Favorites folder since it looks like there is not name
    775   // different in every language version of Windows Vista.
    776   if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    777     // The Link folder name is stored in the registry.
    778     DWORD buffer_length = sizeof(buffer);
    779     base::win::RegKey reg_key(HKEY_CURRENT_USER, kIEToolbarKey, KEY_READ);
    780     if (reg_key.ReadValue(L"LinksFolderName", buffer,
    781                           &buffer_length, NULL) != ERROR_SUCCESS)
    782       return false;
    783     info->links_folder = buffer;
    784   } else {
    785     info->links_folder = L"Links";
    786   }
    787 
    788   return true;
    789 }
    790 
    791 void IEImporter::ParseFavoritesFolder(
    792     const FavoritesInfo& info,
    793     BookmarkVector* bookmarks,
    794     std::vector<ImportedFaviconUsage>* favicons) {
    795   base::FilePath file;
    796   std::vector<base::FilePath::StringType> file_list;
    797   base::FilePath favorites_path(info.path);
    798   // Favorites path length.  Make sure it doesn't include the trailing \.
    799   size_t favorites_path_len =
    800       favorites_path.StripTrailingSeparators().value().size();
    801   base::FileEnumerator file_enumerator(
    802       favorites_path, true, base::FileEnumerator::FILES);
    803   while (!(file = file_enumerator.Next()).value().empty() && !cancelled())
    804     file_list.push_back(file.value());
    805 
    806   // Keep the bookmarks in alphabetical order.
    807   std::sort(file_list.begin(), file_list.end());
    808 
    809   // Map from favicon URLs to the favicon data (the binary image data and the
    810   // set of bookmark URLs referring to the favicon).
    811   typedef std::map<GURL, ImportedFaviconUsage> FaviconMap;
    812   FaviconMap favicon_map;
    813 
    814   for (std::vector<base::FilePath::StringType>::iterator it = file_list.begin();
    815        it != file_list.end(); ++it) {
    816     base::FilePath shortcut(*it);
    817     if (!LowerCaseEqualsASCII(shortcut.Extension(), ".url"))
    818       continue;
    819 
    820     // Skip the bookmark with invalid URL.
    821     base::win::ScopedComPtr<IUniformResourceLocator> url_locator;
    822     if (!LoadInternetShortcut(*it, &url_locator))
    823       continue;
    824     GURL url = ReadURLFromInternetShortcut(url_locator);
    825     if (!url.is_valid())
    826       continue;
    827     // Skip default bookmarks. go.microsoft.com redirects to
    828     // search.microsoft.com, and http://go.microsoft.com/fwlink/?LinkId=XXX,
    829     // which URLs IE has as default, to some another sites.
    830     // We expect that users will never themselves create bookmarks having this
    831     // hostname.
    832     if (url.host() == "go.microsoft.com")
    833       continue;
    834     // Read favicon.
    835     UpdateFaviconMap(*it, url, url_locator, &favicon_map);
    836 
    837     // Make the relative path from the Favorites folder, without the basename.
    838     // ex. Suppose that the Favorites folder is C:\Users\Foo\Favorites.
    839     //   C:\Users\Foo\Favorites\Foo.url -> ""
    840     //   C:\Users\Foo\Favorites\Links\Bar\Baz.url -> "Links\Bar"
    841     base::FilePath::StringType relative_string =
    842         shortcut.DirName().value().substr(favorites_path_len);
    843     if (!relative_string.empty() &&
    844         base::FilePath::IsSeparator(relative_string[0]))
    845       relative_string = relative_string.substr(1);
    846     base::FilePath relative_path(relative_string);
    847 
    848     ImportedBookmarkEntry entry;
    849     // Remove the dot, the file extension, and the directory path.
    850     entry.title = shortcut.RemoveExtension().BaseName().value();
    851     entry.url = url;
    852     entry.creation_time = GetFileCreationTime(*it);
    853     if (!relative_path.empty())
    854       relative_path.GetComponents(&entry.path);
    855 
    856     // Add the bookmark.
    857     if (!entry.path.empty() && entry.path[0] == info.links_folder) {
    858       // Bookmarks in the Link folder should be imported to the toolbar.
    859       entry.in_toolbar = true;
    860     }
    861     bookmarks->push_back(entry);
    862   }
    863 
    864   // Reflect the menu order in IE.
    865   SortBookmarksInIEOrder(this, bookmarks);
    866 
    867   // Record favicon data.
    868   for (FaviconMap::iterator iter = favicon_map.begin();
    869        iter != favicon_map.end(); ++iter)
    870     favicons->push_back(iter->second);
    871 }
    872 
    873 int IEImporter::CurrentIEVersion() const {
    874   static int version = -1;
    875   if (version < 0) {
    876     wchar_t buffer[128];
    877     DWORD buffer_length = sizeof(buffer);
    878     base::win::RegKey reg_key(HKEY_LOCAL_MACHINE, kIEVersionKey, KEY_READ);
    879     LONG result = reg_key.ReadValue(L"Version", buffer, &buffer_length, NULL);
    880     version = ((result == ERROR_SUCCESS)? _wtoi(buffer) : 0);
    881   }
    882   return version;
    883 }
    884