summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-15 19:54:56 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-15 19:54:56 +0000
commitd82443b8abc227bd9aa383bfc62702cf36c97476 (patch)
tree2aa9125983c41369ed92ef78837919853145ca2e /chrome
parent0063a45b4515ead768e917a4f62f8fe96574a02d (diff)
downloadchromium_src-d82443b8abc227bd9aa383bfc62702cf36c97476.zip
chromium_src-d82443b8abc227bd9aa383bfc62702cf36c97476.tar.gz
chromium_src-d82443b8abc227bd9aa383bfc62702cf36c97476.tar.bz2
Fie.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8111 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.cc4
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup.cc4
-rw-r--r--chrome/browser/autocomplete/keyword_provider.cc4
-rw-r--r--chrome/browser/autocomplete/keyword_provider_unittest.cc4
-rw-r--r--chrome/browser/autocomplete/search_provider.cc2
-rw-r--r--chrome/browser/autocomplete/search_provider.h2
-rw-r--r--chrome/browser/browser.scons10
-rw-r--r--chrome/browser/browser.vcproj174
-rw-r--r--chrome/browser/browser_prefs.cc2
-rw-r--r--chrome/browser/browsing_data_remover.cc2
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.cc2
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.h2
-rw-r--r--chrome/browser/history/history.h2
-rw-r--r--chrome/browser/history/url_database.h2
-rw-r--r--chrome/browser/importer/firefox2_importer.cc4
-rw-r--r--chrome/browser/importer/firefox_importer_utils.cc6
-rw-r--r--chrome/browser/importer/ie_importer.cc2
-rw-r--r--chrome/browser/importer/importer.cc2
-rw-r--r--chrome/browser/importer/importer.h2
-rw-r--r--chrome/browser/metrics_service.cc4
-rw-r--r--chrome/browser/profile.cc4
-rw-r--r--chrome/browser/render_view_context_menu.cc2
-rw-r--r--chrome/browser/render_view_context_menu_controller.cc2
-rw-r--r--chrome/browser/rlz/rlz.cc2
-rw-r--r--chrome/browser/search_engines/template_url.cc0
-rw-r--r--chrome/browser/search_engines/template_url.h0
-rw-r--r--chrome/browser/search_engines/template_url_fetcher.cc0
-rw-r--r--chrome/browser/search_engines/template_url_fetcher.h0
-rw-r--r--chrome/browser/search_engines/template_url_model.cc0
-rw-r--r--chrome/browser/search_engines/template_url_model.h0
-rw-r--r--chrome/browser/search_engines/template_url_model_unittest.cc0
-rw-r--r--chrome/browser/search_engines/template_url_parser.cc0
-rw-r--r--chrome/browser/search_engines/template_url_parser.h0
-rw-r--r--chrome/browser/search_engines/template_url_parser_unittest.cc0
-rw-r--r--chrome/browser/search_engines/template_url_prepopulate_data.cc0
-rw-r--r--chrome/browser/search_engines/template_url_prepopulate_data.h0
-rw-r--r--chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc0
-rw-r--r--chrome/browser/search_engines/template_url_unittest.cc0
-rw-r--r--chrome/browser/tab_contents/web_contents.cc4
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc2
-rw-r--r--chrome/browser/template_url.cc558
-rw-r--r--chrome/browser/template_url.h436
-rw-r--r--chrome/browser/template_url_fetcher.cc116
-rw-r--r--chrome/browser/template_url_fetcher.h104
-rw-r--r--chrome/browser/template_url_model.cc980
-rw-r--r--chrome/browser/template_url_model.h348
-rw-r--r--chrome/browser/template_url_model_unittest.cc633
-rw-r--r--chrome/browser/template_url_parser.cc586
-rw-r--r--chrome/browser/template_url_parser.h48
-rw-r--r--chrome/browser/template_url_parser_unittest.cc240
-rw-r--r--chrome/browser/template_url_prepopulate_data.cc3082
-rw-r--r--chrome/browser/template_url_prepopulate_data.h32
-rw-r--r--chrome/browser/template_url_prepopulate_data_unittest.cc59
-rw-r--r--chrome/browser/template_url_unittest.cc386
-rw-r--r--chrome/browser/views/clear_browsing_data.cc2
-rw-r--r--chrome/browser/views/edit_keyword_controller.cc4
-rw-r--r--chrome/browser/views/first_run_bubble.cc2
-rw-r--r--chrome/browser/views/keyword_editor_view.cc4
-rw-r--r--chrome/browser/views/keyword_editor_view.h2
-rw-r--r--chrome/browser/views/keyword_editor_view_unittest.cc4
-rw-r--r--chrome/browser/views/location_bar_view.cc4
-rw-r--r--chrome/browser/views/options/general_page_view.cc6
-rw-r--r--chrome/browser/views/tabs/tab_strip.cc13
-rw-r--r--chrome/browser/webdata/web_data_service.cc2
-rw-r--r--chrome/browser/webdata/web_database.cc2
-rw-r--r--chrome/browser/webdata/web_database.h2
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc2
-rw-r--r--chrome/chrome.xcodeproj/project.pbxproj28
-rw-r--r--chrome/test/testing_profile.h2
-rw-r--r--chrome/test/unit/unit_tests.scons8
-rw-r--r--chrome/test/unit/unittests.vcproj8
71 files changed, 7732 insertions, 223 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc
index 3d43dbb..1cff5ee 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit.cc
@@ -21,9 +21,9 @@
#include "chrome/browser/controller.h"
#include "chrome/browser/drag_utils.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/url_fixer_upper.h"
#include "chrome/browser/user_metrics.h"
#include "chrome/browser/views/location_bar_view.h"
diff --git a/chrome/browser/autocomplete/autocomplete_popup.cc b/chrome/browser/autocomplete/autocomplete_popup.cc
index d2437a3..23535c3 100644
--- a/chrome/browser/autocomplete/autocomplete_popup.cc
+++ b/chrome/browser/autocomplete/autocomplete_popup.cc
@@ -13,8 +13,8 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/net/dns_global.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/views/location_bar_view.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/l10n_util.h"
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index defb656..9f0eb3e 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -8,8 +8,8 @@
#include "base/string_util.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/common/l10n_util.h"
#include "net/base/escape.h"
#include "net/base/net_util.h"
diff --git a/chrome/browser/autocomplete/keyword_provider_unittest.cc b/chrome/browser/autocomplete/keyword_provider_unittest.cc
index a650701..e82e8d6 100644
--- a/chrome/browser/autocomplete/keyword_provider_unittest.cc
+++ b/chrome/browser/autocomplete/keyword_provider_unittest.cc
@@ -4,8 +4,8 @@
#include "base/message_loop.h"
#include "chrome/browser/autocomplete/keyword_provider.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index d302b30..cd25d13 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/google_util.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/url_fixer_upper.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/l10n_util.h"
diff --git a/chrome/browser/autocomplete/search_provider.h b/chrome/browser/autocomplete/search_provider.h
index 687ea07..8fe402f 100644
--- a/chrome/browser/autocomplete/search_provider.h
+++ b/chrome/browser/autocomplete/search_provider.h
@@ -17,7 +17,7 @@
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/history/history.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/template_url.h"
#include "chrome/browser/url_fetcher.h"
class Profile;
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons
index 0eb3d4b..e937d99 100644
--- a/chrome/browser/browser.scons
+++ b/chrome/browser/browser.scons
@@ -115,15 +115,15 @@ if not env.Bit('mac'):
'safe_browsing/safe_browsing_database_bloom.cc',
'safe_browsing/safe_browsing_database_impl.cc',
'safe_browsing/safe_browsing_util.cc',
- 'search_engines/template_url.cc',
- 'search_engines/template_url_model.cc',
- 'search_engines/template_url_parser.cc',
'session_startup_pref.cc',
'sessions/session_command.cc',
'sessions/session_id.cc',
'spellcheck_worditerator.cc',
'spellchecker.cc',
'ssl_error_info.cc',
+ 'template_url.cc',
+ 'template_url_model.cc',
+ 'template_url_parser.cc',
'url_fetcher.cc',
'url_fetcher_protect.cc',
'user_metrics.cc',
@@ -259,8 +259,6 @@ if env.Bit('windows'):
'safe_browsing/safe_browsing_blocking_page.cc',
'safe_browsing/safe_browsing_service.cc',
'sandbox_policy.cc',
- 'search_engines/template_url_fetcher.cc',
- 'search_engines/template_url_prepopulate_data.cc',
'sessions/base_session_service.cc',
'sessions/session_backend.cc',
'sessions/session_restore.cc',
@@ -293,6 +291,8 @@ if env.Bit('windows'):
'tabs/tab_strip_model_order_controller.cc',
'task_manager.cc',
'task_manager_resource_providers.cc',
+ 'template_url_fetcher.cc',
+ 'template_url_prepopulate_data.cc',
'toolbar_model.cc',
'url_fixer_upper.cc',
'user_data_manager.cc',
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index cd93d66..0fca784 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -602,6 +602,46 @@
>
</File>
<File
+ RelativePath=".\template_url.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\template_url.h"
+ >
+ </File>
+ <File
+ RelativePath=".\template_url_fetcher.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\template_url_fetcher.h"
+ >
+ </File>
+ <File
+ RelativePath=".\template_url_model.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\template_url_model.h"
+ >
+ </File>
+ <File
+ RelativePath=".\template_url_parser.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\template_url_parser.h"
+ >
+ </File>
+ <File
+ RelativePath=".\template_url_prepopulate_data.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\template_url_prepopulate_data.h"
+ >
+ </File>
+ <File
RelativePath=".\url_fetcher.cc"
>
</File>
@@ -2510,140 +2550,6 @@
>
</File>
</Filter>
- <Filter
- Name="Search Engines"
- >
- <File
- RelativePath=".\search_engines\template_url.cc"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath=".\search_engines\template_url.h"
- >
- </File>
- <File
- RelativePath=".\search_engines\template_url_fetcher.cc"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath=".\search_engines\template_url_fetcher.h"
- >
- </File>
- <File
- RelativePath=".\search_engines\template_url_model.cc"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath=".\search_engines\template_url_model.h"
- >
- </File>
- <File
- RelativePath=".\search_engines\template_url_parser.cc"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath=".\search_engines\template_url_parser.h"
- >
- </File>
- <File
- RelativePath=".\search_engines\template_url_prepopulate_data.cc"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- ObjectFile="$(IntDir)\$(InputName)1.obj"
- XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath=".\search_engines\template_url_prepopulate_data.h"
- >
- </File>
- </Filter>
<File
RelativePath=".\browser_trial.cc"
>
diff --git a/chrome/browser/browser_prefs.cc b/chrome/browser/browser_prefs.cc
index 4f83bac..abbf875 100644
--- a/chrome/browser/browser_prefs.cc
+++ b/chrome/browser/browser_prefs.cc
@@ -19,7 +19,7 @@
#include "chrome/browser/ssl_manager.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/task_manager.h"
-#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
+#include "chrome/browser/template_url_prepopulate_data.h"
#include "chrome/browser/views/bookmark_bar_view.h"
#include "chrome/browser/views/bookmark_manager_view.h"
#include "chrome/browser/views/bookmark_table_view.h"
diff --git a/chrome/browser/browsing_data_remover.cc b/chrome/browser/browsing_data_remover.cc
index e9140b2..86f8e98 100644
--- a/chrome/browser/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data_remover.cc
@@ -8,9 +8,9 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/user_metrics.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc
index 7bb7d9f..9b7107a 100644
--- a/chrome/browser/dom_ui/new_tab_ui.cc
+++ b/chrome/browser/dom_ui/new_tab_ui.cc
@@ -18,7 +18,7 @@
#include "chrome/browser/render_view_host.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/template_url.h"
#include "chrome/browser/user_data_manager.h"
#include "chrome/browser/user_metrics.h"
#include "chrome/browser/views/keyword_editor_view.h"
diff --git a/chrome/browser/dom_ui/new_tab_ui.h b/chrome/browser/dom_ui/new_tab_ui.h
index a8391e8..8f700b2 100644
--- a/chrome/browser/dom_ui/new_tab_ui.h
+++ b/chrome/browser/dom_ui/new_tab_ui.h
@@ -9,8 +9,8 @@
#include "chrome/browser/dom_ui/dom_ui_host.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/history/history.h"
-#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/template_url_model.h"
class GURL;
class Profile;
diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h
index 0e5a492..dcd5518 100644
--- a/chrome/browser/history/history.h
+++ b/chrome/browser/history/history.h
@@ -20,7 +20,7 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/template_url.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/ref_counted_util.h"
diff --git a/chrome/browser/history/url_database.h b/chrome/browser/history/url_database.h
index 20aeb78..745c7e3 100644
--- a/chrome/browser/history/url_database.h
+++ b/chrome/browser/history/url_database.h
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/template_url.h"
// Temporary until DBCloseScoper moves elsewhere.
#include "chrome/common/sqlite_compiled_statement.h"
diff --git a/chrome/browser/importer/firefox2_importer.cc b/chrome/browser/importer/firefox2_importer.cc
index b2f61c1..bbc4e6f 100644
--- a/chrome/browser/importer/firefox2_importer.cc
+++ b/chrome/browser/importer/firefox2_importer.cc
@@ -11,8 +11,8 @@
#include "base/values.h"
#include "chrome/browser/importer/firefox_importer_utils.h"
#include "chrome/browser/importer/mork_reader.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_parser.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_parser.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/time_format.h"
#include "generated_resources.h"
diff --git a/chrome/browser/importer/firefox_importer_utils.cc b/chrome/browser/importer/firefox_importer_utils.cc
index 023fcf9..719ebcc 100644
--- a/chrome/browser/importer/firefox_importer_utils.cc
+++ b/chrome/browser/importer/firefox_importer_utils.cc
@@ -13,9 +13,9 @@
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/time.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/search_engines/template_url_parser.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
+#include "chrome/browser/template_url_parser.h"
#include "chrome/common/win_util.h"
#include "googleurl/src/gurl.h"
#include "net/base/base64.h"
diff --git a/chrome/browser/importer/ie_importer.cc b/chrome/browser/importer/ie_importer.cc
index d362739..55bed64 100644
--- a/chrome/browser/importer/ie_importer.cc
+++ b/chrome/browser/importer/ie_importer.cc
@@ -19,7 +19,7 @@
#include "base/win_util.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/password_manager/ie7_password.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/time_format.h"
#include "chrome/common/win_util.h"
diff --git a/chrome/browser/importer/importer.cc b/chrome/browser/importer/importer.cc
index 52a035d..dcc1438 100644
--- a/chrome/browser/importer/importer.cc
+++ b/chrome/browser/importer/importer.cc
@@ -21,7 +21,7 @@
#include "chrome/browser/importer/firefox_profile_lock.h"
#include "chrome/browser/importer/ie_importer.h"
#include "chrome/browser/importer/toolbar_importer.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/views/importer_lock_view.h"
#include "chrome/browser/webdata/web_data_service.h"
diff --git a/chrome/browser/importer/importer.h b/chrome/browser/importer/importer.h
index e169eb7..df13150 100644
--- a/chrome/browser/importer/importer.h
+++ b/chrome/browser/importer/importer.h
@@ -19,7 +19,7 @@
#include "chrome/browser/password_manager/ie7_password.h"
#endif
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/template_url.h"
#include "chrome/common/notification_service.h"
#include "googleurl/src/gurl.h"
#include "webkit/glue/password_form.h"
diff --git a/chrome/browser/metrics_service.cc b/chrome/browser/metrics_service.cc
index bb2ba62..7909a0b 100644
--- a/chrome/browser/metrics_service.cc
+++ b/chrome/browser/metrics_service.cc
@@ -173,8 +173,8 @@
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/render_process_host.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/libxml_utils.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index 7d3a947..a849bf1 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -23,12 +23,12 @@
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/render_process_host.h"
-#include "chrome/browser/search_engines/template_url_fetcher.h"
-#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/spellchecker.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/template_url_fetcher.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/visitedlink_master.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/chrome_constants.h"
diff --git a/chrome/browser/render_view_context_menu.cc b/chrome/browser/render_view_context_menu.cc
index 311ba27..83082b4 100644
--- a/chrome/browser/render_view_context_menu.cc
+++ b/chrome/browser/render_view_context_menu.cc
@@ -8,8 +8,8 @@
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/spellchecker.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/common/l10n_util.h"
#include "webkit/glue/context_node_types.h"
diff --git a/chrome/browser/render_view_context_menu_controller.cc b/chrome/browser/render_view_context_menu_controller.cc
index bdb34e7..7a75577 100644
--- a/chrome/browser/render_view_context_menu_controller.cc
+++ b/chrome/browser/render_view_context_menu_controller.cc
@@ -18,7 +18,7 @@
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/save_package.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/views/page_info_window.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc
index 6434fb1..d65f180 100644
--- a/chrome/browser/rlz/rlz.cc
+++ b/chrome/browser/rlz/rlz.cc
@@ -19,7 +19,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/search_engines/template_url.cc b/chrome/browser/search_engines/template_url.cc
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url.cc
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url.h
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_fetcher.cc b/chrome/browser/search_engines/template_url_fetcher.cc
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_fetcher.cc
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_fetcher.h b/chrome/browser/search_engines/template_url_fetcher.h
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_fetcher.h
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_model.cc b/chrome/browser/search_engines/template_url_model.cc
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_model.cc
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_model.h b/chrome/browser/search_engines/template_url_model.h
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_model.h
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_model_unittest.cc b/chrome/browser/search_engines/template_url_model_unittest.cc
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_model_unittest.cc
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_parser.cc b/chrome/browser/search_engines/template_url_parser.cc
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_parser.cc
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_parser.h b/chrome/browser/search_engines/template_url_parser.h
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_parser.h
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_parser_unittest.cc b/chrome/browser/search_engines/template_url_parser_unittest.cc
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_parser_unittest.cc
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.cc b/chrome/browser/search_engines/template_url_prepopulate_data.cc
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_prepopulate_data.cc
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.h b/chrome/browser/search_engines/template_url_prepopulate_data.h
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_prepopulate_data.h
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
+++ /dev/null
diff --git a/chrome/browser/search_engines/template_url_unittest.cc b/chrome/browser/search_engines/template_url_unittest.cc
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/search_engines/template_url_unittest.cc
+++ /dev/null
diff --git a/chrome/browser/tab_contents/web_contents.cc b/chrome/browser/tab_contents/web_contents.cc
index 6c6ec47..77faa55 100644
--- a/chrome/browser/tab_contents/web_contents.cc
+++ b/chrome/browser/tab_contents/web_contents.cc
@@ -30,11 +30,11 @@
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/render_view_host.h"
#include "chrome/browser/render_widget_host_view_win.h" // TODO(brettw) delete me.
-#include "chrome/browser/search_engines/template_url_fetcher.h"
-#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/web_contents_view.h"
#include "chrome/browser/tab_contents/web_contents_view_win.h"
+#include "chrome/browser/template_url_fetcher.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/views/hung_renderer_view.h" // TODO(brettw) delete me.
#include "chrome/common/chrome_switches.h"
#include "chrome/common/l10n_util.h"
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index 3b0c4bb..2e42a64 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -533,7 +533,7 @@ bool TabStripModel::InternalCloseTabContentsAt(int index,
// them. Once they have fired, we'll get a message back saying whether
// to proceed closing the page or not, which sends us back to this method
// with the HasUnloadListener bit cleared.
- WebContents* web_contents = detached_contents->AsWebContents();
+ WebContents* web_contents = GetContentsAt(index)->AsWebContents();
// If we hit this code path, the tab had better be a WebContents tab.
DCHECK(web_contents);
web_contents->render_view_host()->FirePageBeforeUnload();
diff --git a/chrome/browser/template_url.cc b/chrome/browser/template_url.cc
new file mode 100644
index 0000000..844ec54
--- /dev/null
+++ b/chrome/browser/template_url.cc
@@ -0,0 +1,558 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/template_url.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/rlz/rlz.h"
+#include "chrome/browser/google_url_tracker.h"
+#include "chrome/browser/template_url_model.h"
+#include "chrome/common/gfx/favicon_size.h"
+#include "chrome/common/l10n_util.h"
+#include "net/base/escape.h"
+
+// The TemplateURLRef has any number of terms that need to be replaced. Each of
+// the terms is enclosed in braces. If the character preceeding the final
+// brace is a ?, it indicates the term is optional and can be replaced with
+// an empty string.
+static const wchar_t kStartParameter = '{';
+static const wchar_t kEndParameter = '}';
+static const wchar_t kOptional = '?';
+
+// Known parameters found in the URL.
+static const wchar_t kSearchTermsParameter[] = L"searchTerms";
+static const wchar_t kSearchTermsParameterFull[] = L"{searchTerms}";
+static const wchar_t kCountParameter[] = L"count";
+static const wchar_t kStartIndexParameter[] = L"startIndex";
+static const wchar_t kStartPageParameter[] = L"startPage";
+static const wchar_t kLanguageParameter[] = L"language";
+static const wchar_t kInputEncodingParameter[] = L"inputEncoding";
+static const wchar_t kOutputEncodingParameter[] = L"outputEncoding";
+
+static const wchar_t kGoogleAcceptedSuggestionParameter[] =
+ L"google:acceptedSuggestion";
+// Host/Domain Google searches are relative to.
+static const wchar_t kGoogleBaseURLParameter[] = L"google:baseURL";
+static const wchar_t kGoogleBaseURLParameterFull[] = L"{google:baseURL}";
+// Like google:baseURL, but for the Search Suggest capability.
+static const wchar_t kGoogleBaseSuggestURLParameter[] =
+ L"google:baseSuggestURL";
+static const wchar_t kGoogleBaseSuggestURLParameterFull[] =
+ L"{google:baseSuggestURL}";
+static const wchar_t kGoogleOriginalQueryForSuggestionParameter[] =
+ L"google:originalQueryForSuggestion";
+static const wchar_t kGoogleRLZParameter[] = L"google:RLZ";
+// Same as kSearchTermsParameter, with no escaping.
+static const wchar_t kGoogleUnescapedSearchTermsParameter[] =
+ L"google:unescapedSearchTerms";
+static const wchar_t kGoogleUnescapedSearchTermsParameterFull[] =
+ L"{google:unescapedSearchTerms}";
+
+// Display value for kSearchTermsParameter.
+static const wchar_t kDisplaySearchTerms[] = L"%s";
+
+// Display value for kGoogleUnescapedSearchTermsParameter.
+static const wchar_t kDisplayUnescapedSearchTerms[] = L"%S";
+
+// Used if the count parameter is not optional. Indicates we want 10 search
+// results.
+static const wchar_t kDefaultCount[] = L"10";
+
+// Used if the parameter kOutputEncodingParameter is required.
+static const wchar_t kOutputEncodingType[] = L"UTF-8";
+
+// static
+std::wstring* TemplateURLRef::google_base_url_ = NULL;
+
+TemplateURLRef::TemplateURLRef() {
+ Set(std::wstring(), 0, 0);
+}
+
+void TemplateURLRef::Set(const std::wstring& url,
+ int index_offset,
+ int page_offset) {
+ url_ = url;
+ index_offset_ = index_offset;
+ page_offset_ = page_offset;
+ InvalidateCachedValues();
+}
+
+bool TemplateURLRef::ParseParameter(size_t start,
+ size_t end,
+ std::wstring* url,
+ Replacements* replacements) const {
+ DCHECK(start != std::string::npos &&
+ end != std::string::npos && end > start);
+ size_t length = end - start - 1;
+ bool optional = false;
+ if ((*url)[end - 1] == kOptional) {
+ optional = true;
+ length--;
+ }
+ std::wstring parameter(url->substr(start + 1, length));
+ // Remove the parameter from the string.
+ url->erase(start, end - start + 1);
+ if (parameter == kSearchTermsParameter) {
+ replacements->push_back(Replacement(SEARCH_TERMS, static_cast<int>(start)));
+ } else if (parameter == kCountParameter) {
+ if (!optional)
+ url->insert(start, kDefaultCount);
+ } else if (parameter == kStartIndexParameter) {
+ if (!optional) {
+ url->insert(start, IntToWString(index_offset_));
+ }
+ } else if (parameter == kStartPageParameter) {
+ if (!optional) {
+ url->insert(start, IntToWString(page_offset_));
+ }
+ } else if (parameter == kLanguageParameter) {
+ replacements->push_back(Replacement(LANGUAGE, static_cast<int>(start)));
+ } else if (parameter == kInputEncodingParameter) {
+ replacements->push_back(Replacement(ENCODING, static_cast<int>(start)));
+ } else if (parameter == kOutputEncodingParameter) {
+ if (!optional)
+ url->insert(start, kOutputEncodingType);
+ } else if (parameter == kGoogleAcceptedSuggestionParameter) {
+ replacements->push_back(Replacement(GOOGLE_ACCEPTED_SUGGESTION,
+ static_cast<int>(start)));
+ } else if (parameter == kGoogleBaseURLParameter) {
+ replacements->push_back(Replacement(GOOGLE_BASE_URL,
+ static_cast<int>(start)));
+ } else if (parameter == kGoogleBaseSuggestURLParameter) {
+ replacements->push_back(Replacement(GOOGLE_BASE_SUGGEST_URL,
+ static_cast<int>(start)));
+ } else if (parameter == kGoogleOriginalQueryForSuggestionParameter) {
+ replacements->push_back(Replacement(GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION,
+ static_cast<int>(start)));
+ } else if (parameter == kGoogleRLZParameter) {
+ replacements->push_back(Replacement(GOOGLE_RLZ, static_cast<int>(start)));
+ } else if (parameter == kGoogleUnescapedSearchTermsParameter) {
+ replacements->push_back(Replacement(GOOGLE_UNESCAPED_SEARCH_TERMS,
+ static_cast<int>(start)));
+ } else if (!optional) {
+ // Unknown required parameter. No idea what to replace this with,
+ // so fail.
+ return false;
+ }
+ return true;
+}
+
+std::wstring TemplateURLRef::ParseURL(const std::wstring& url,
+ Replacements* replacements,
+ bool* valid) const {
+ *valid = false;
+ std::wstring parsed_url = url;
+ for (size_t last = 0; last != std::string::npos; ) {
+ last = parsed_url.find(kStartParameter, last);
+ if (last != std::string::npos) {
+ size_t endTemplate = parsed_url.find(kEndParameter, last);
+ if (endTemplate != std::string::npos) {
+ if (!ParseParameter(last, endTemplate, &parsed_url, replacements)) {
+ // Not a valid parameter, return.
+ return std::wstring();
+ }
+ // ParseParamter erases from the string, as such we don't need
+ // to update last.
+ } else {
+ // Open brace without a closing brace, return.
+ return std::wstring();
+ }
+ }
+ }
+ *valid = true;
+ return parsed_url;
+}
+
+void TemplateURLRef::ParseIfNecessary() const {
+ if (!parsed_) {
+ parsed_ = true;
+ parsed_url_ = ParseURL(url_, &replacements_, &valid_);
+ supports_replacements_ = false;
+ if (valid_) {
+ bool has_only_one_search_term = false;
+ for (Replacements::const_iterator i = replacements_.begin();
+ i != replacements_.end(); ++i) {
+ if ((i->type == SEARCH_TERMS) ||
+ (i->type == GOOGLE_UNESCAPED_SEARCH_TERMS)) {
+ if (has_only_one_search_term) {
+ has_only_one_search_term = false;
+ break;
+ }
+ has_only_one_search_term = true;
+ supports_replacements_ = true;
+ }
+ }
+ // Only parse the host/key if there is one search term. Technically there
+ // could be more than one term, but it's uncommon; so we punt.
+ if (has_only_one_search_term)
+ ParseHostAndSearchTermKey();
+ }
+ }
+}
+
+void TemplateURLRef::ParseHostAndSearchTermKey() const {
+ std::wstring url_string = url_;
+ ReplaceSubstringsAfterOffset(&url_string, 0, kGoogleBaseURLParameterFull,
+ GoogleBaseURLValue());
+ ReplaceSubstringsAfterOffset(&url_string, 0,
+ kGoogleBaseSuggestURLParameterFull,
+ GoogleBaseSuggestURLValue());
+
+ GURL url(WideToUTF8(url_string));
+ if (!url.is_valid())
+ return;
+
+ std::string query_string = url.query();
+ if (query_string.empty())
+ return;
+
+ url_parse::Component query, key, value;
+ query.len = static_cast<int>(query_string.size());
+ while (url_parse::ExtractQueryKeyValue(query_string.c_str(), &query, &key,
+ &value)) {
+ if (key.is_nonempty() && value.is_nonempty()) {
+ std::string value_string = query_string.substr(value.begin, value.len);
+ if (value_string.find(WideToASCII(kSearchTermsParameterFull), 0) !=
+ std::string::npos ||
+ value_string.find(
+ WideToASCII(kGoogleUnescapedSearchTermsParameterFull), 0) !=
+ std::string::npos) {
+ search_term_key_ = query_string.substr(key.begin, key.len);
+ host_ = url.host();
+ path_ = url.path();
+ break;
+ }
+ }
+ }
+}
+
+GURL TemplateURLRef::ReplaceSearchTerms(
+ const TemplateURL& host,
+ const std::wstring& terms,
+ int accepted_suggestion,
+ const std::wstring& original_query_for_suggestion) const {
+ ParseIfNecessary();
+ if (!valid_)
+ return GURL();
+
+ if (replacements_.empty())
+ return GURL(WideToUTF8(parsed_url_));
+
+ // Encode the search terms so that we know the encoding.
+ const std::vector<std::string>& encodings = host.input_encodings();
+ std::wstring encoded_terms;
+ std::wstring encoded_original_query;
+ std::wstring input_encoding;
+ for (size_t i = 0; i < encodings.size(); ++i) {
+ if (EscapeQueryParamValue(terms, encodings[i].c_str(), &encoded_terms)) {
+ if (!original_query_for_suggestion.empty()) {
+ EscapeQueryParamValue(original_query_for_suggestion,
+ encodings[i].c_str(), &encoded_original_query);
+ }
+ input_encoding = ASCIIToWide(encodings[i]);
+ break;
+ }
+ }
+ if (input_encoding.empty()) {
+ encoded_terms = EscapeQueryParamValueUTF8(terms);
+ if (!original_query_for_suggestion.empty()) {
+ encoded_original_query =
+ EscapeQueryParamValueUTF8(original_query_for_suggestion);
+ }
+ input_encoding = L"UTF-8";
+ }
+
+ std::wstring url = parsed_url_;
+
+ // replacements_ is ordered in ascending order, as such we need to iterate
+ // from the back.
+ for (Replacements::reverse_iterator i = replacements_.rbegin();
+ i != replacements_.rend(); ++i) {
+ switch (i->type) {
+ case ENCODING:
+ url.insert(i->index, input_encoding);
+ break;
+
+ case GOOGLE_ACCEPTED_SUGGESTION:
+ if (accepted_suggestion == NO_SUGGESTION_CHOSEN)
+ url.insert(i->index, L"aq=f&");
+ else if (accepted_suggestion != NO_SUGGESTIONS_AVAILABLE)
+ url.insert(i->index, StringPrintf(L"aq=%d&", accepted_suggestion));
+ break;
+
+ case GOOGLE_BASE_URL:
+ url.insert(i->index, GoogleBaseURLValue());
+ break;
+
+ case GOOGLE_BASE_SUGGEST_URL:
+ url.insert(i->index, GoogleBaseSuggestURLValue());
+ break;
+
+ case GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION:
+ if (accepted_suggestion >= 0)
+ url.insert(i->index, L"oq=" + encoded_original_query + L"&");
+ break;
+
+ case GOOGLE_RLZ: {
+ std::wstring rlz_string;
+ RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz_string);
+ if (!rlz_string.empty()) {
+ rlz_string = L"rlz=" + rlz_string + L"&";
+ url.insert(i->index, rlz_string);
+ }
+ break;
+ }
+
+ case GOOGLE_UNESCAPED_SEARCH_TERMS: {
+ std::string unescaped_terms;
+ WideToCodepage(terms, WideToASCII(input_encoding).c_str(),
+ OnStringUtilConversionError::SKIP, &unescaped_terms);
+ url.insert(i->index, std::wstring(unescaped_terms.begin(),
+ unescaped_terms.end()));
+ break;
+ }
+
+ case LANGUAGE:
+ url.insert(i->index, g_browser_process->GetApplicationLocale());
+ break;
+
+ case SEARCH_TERMS:
+ url.insert(i->index, encoded_terms);
+ break;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ return GURL(WideToUTF8(url));
+}
+
+bool TemplateURLRef::SupportsReplacement() const {
+ ParseIfNecessary();
+ return valid_ && supports_replacements_;
+}
+
+bool TemplateURLRef::IsValid() const {
+ ParseIfNecessary();
+ return valid_;
+}
+
+std::wstring TemplateURLRef::DisplayURL() const {
+ ParseIfNecessary();
+ if (!valid_)
+ return url_; // If we're not valid, don't escape anything.
+
+ if (replacements_.empty())
+ return url_; // Nothing to replace, return the url.
+
+ std::wstring result = url_;
+ ReplaceSubstringsAfterOffset(&result, 0, kSearchTermsParameterFull,
+ kDisplaySearchTerms);
+
+ ReplaceSubstringsAfterOffset(&result, 0,
+ kGoogleUnescapedSearchTermsParameterFull,
+ kDisplayUnescapedSearchTerms);
+
+ return result;
+}
+
+// static
+std::wstring TemplateURLRef::DisplayURLToURLRef(
+ const std::wstring& display_url) {
+ std::wstring result = display_url;
+ ReplaceSubstringsAfterOffset(&result, 0, kDisplaySearchTerms,
+ kSearchTermsParameterFull);
+ ReplaceSubstringsAfterOffset(&result, 0, kDisplayUnescapedSearchTerms,
+ kGoogleUnescapedSearchTermsParameterFull);
+ return result;
+}
+
+const std::string& TemplateURLRef::GetHost() const {
+ ParseIfNecessary();
+ return host_;
+}
+
+const std::string& TemplateURLRef::GetPath() const {
+ ParseIfNecessary();
+ return path_;
+}
+
+const std::string& TemplateURLRef::GetSearchTermKey() const {
+ ParseIfNecessary();
+ return search_term_key_;
+}
+
+std::wstring TemplateURLRef::SearchTermToWide(const TemplateURL& host,
+ const std::string& term) const {
+ const std::vector<std::string>& encodings = host.input_encodings();
+ std::wstring result;
+
+ std::string unescaped =
+ UnescapeURLComponent(term, UnescapeRule::REPLACE_PLUS_WITH_SPACE);
+ for (size_t i = 0; i < encodings.size(); ++i) {
+ if (CodepageToWide(unescaped, encodings[i].c_str(),
+ OnStringUtilConversionError::FAIL, &result))
+ return result;
+ }
+
+ // Always fall back on UTF-8 if it works.
+ if (CodepageToWide(unescaped, "UTF-8",
+ OnStringUtilConversionError::FAIL, &result))
+ return result;
+
+ // When nothing worked, just use the escaped text. We have no idea what the
+ // encoding is. We need to substitute spaces for pluses ourselves since we're
+ // not sending it through an unescaper.
+ result = UTF8ToWide(term);
+ std::replace(result.begin(), result.end(), '+', ' ');
+ return result;
+}
+
+bool TemplateURLRef::HasGoogleBaseURLs() const {
+ ParseIfNecessary();
+ for (size_t i = 0; i < replacements_.size(); ++i) {
+ if ((replacements_[i].type == GOOGLE_BASE_URL) ||
+ (replacements_[i].type == GOOGLE_BASE_SUGGEST_URL))
+ return true;
+ }
+ return false;
+}
+
+void TemplateURLRef::InvalidateCachedValues() const {
+ supports_replacements_ = valid_ = parsed_ = false;
+ host_.clear();
+ path_.clear();
+ search_term_key_.clear();
+ replacements_.clear();
+}
+
+// Returns the value to use for replacements of type GOOGLE_BASE_URL.
+// static
+std::wstring TemplateURLRef::GoogleBaseURLValue() {
+ return google_base_url_ ?
+ (*google_base_url_) : UTF8ToWide(GoogleURLTracker::GoogleURL().spec());
+}
+
+// Returns the value to use for replacements of type GOOGLE_BASE_SUGGEST_URL.
+// static
+std::wstring TemplateURLRef::GoogleBaseSuggestURLValue() {
+ // The suggest base URL we want at the end is something like
+ // "http://clients1.google.TLD/complete/". The key bit we want from the
+ // original Google base URL is the TLD.
+
+ // Start with the Google base URL.
+ const GURL base_url(google_base_url_ ?
+ GURL(WideToUTF8(*google_base_url_)) : GoogleURLTracker::GoogleURL());
+ DCHECK(base_url.is_valid());
+
+ // Change "www." to "clients1." in the hostname. If no "www." was found, just
+ // prepend "clients1.".
+ const std::string base_host(base_url.host());
+ GURL::Replacements repl;
+ const std::string suggest_host("clients1." +
+ (base_host.compare(0, 4, "www.") ? base_host : base_host.substr(4)));
+ repl.SetHostStr(suggest_host);
+
+ // Replace any existing path with "/complete/".
+ static const std::string suggest_path("/complete/");
+ repl.SetPathStr(suggest_path);
+
+ // Clear the query and ref.
+ repl.ClearQuery();
+ repl.ClearRef();
+ return UTF8ToWide(base_url.ReplaceComponents(repl).spec());
+}
+
+// TemplateURL ----------------------------------------------------------------
+
+// static
+GURL TemplateURL::GenerateFaviconURL(const GURL& url) {
+ DCHECK(url.is_valid());
+ GURL::Replacements rep;
+
+ const char favicon_path[] = "/favicon.ico";
+ int favicon_path_len = arraysize(favicon_path) - 1;
+
+ rep.SetPath(favicon_path, url_parse::Component(0, favicon_path_len));
+ rep.ClearUsername();
+ rep.ClearPassword();
+ rep.ClearQuery();
+ rep.ClearRef();
+ return url.ReplaceComponents(rep);
+}
+
+void TemplateURL::SetSuggestionsURL(const std::wstring& suggestions_url,
+ int index_offset,
+ int page_offset) {
+ suggestions_url_.Set(suggestions_url, index_offset, page_offset);
+}
+
+void TemplateURL::SetURL(const std::wstring& url,
+ int index_offset,
+ int page_offset) {
+ url_.Set(url, index_offset, page_offset);
+}
+
+void TemplateURL::set_keyword(const std::wstring& keyword) {
+ // Case sensitive keyword matching is confusing. As such, we force all
+ // keywords to be lower case.
+ keyword_ = l10n_util::ToLower(keyword);
+ autogenerate_keyword_ = false;
+}
+
+const std::wstring& TemplateURL::keyword() const {
+ if (autogenerate_keyword_ && keyword_.empty()) {
+ // Generate a keyword and cache it.
+ keyword_ = TemplateURLModel::GenerateKeyword(
+ TemplateURLModel::GenerateSearchURL(this).GetWithEmptyPath(), true);
+ }
+ return keyword_;
+}
+
+bool TemplateURL::ShowInDefaultList() const {
+ return show_in_default_list() && url() && url()->SupportsReplacement();
+}
+
+void TemplateURL::SetFavIconURL(const GURL& url) {
+ for (std::vector<ImageRef>::iterator i = image_refs_.begin();
+ i != image_refs_.end(); ++i) {
+ if (i->type == L"image/x-icon" &&
+ i->width == kFavIconSize && i->height == kFavIconSize) {
+ if (!url.is_valid())
+ image_refs_.erase(i);
+ else
+ i->url = url;
+ return;
+ }
+ }
+ // Don't have one yet, add it.
+ if (url.is_valid()) {
+ add_image_ref(
+ TemplateURL::ImageRef(L"image/x-icon", kFavIconSize, kFavIconSize,
+ url));
+ }
+}
+
+GURL TemplateURL::GetFavIconURL() const {
+ for (std::vector<ImageRef>::const_iterator i = image_refs_.begin();
+ i != image_refs_.end(); ++i) {
+ if ((i->type == L"image/x-icon" || i->type == L"image/vnd.microsoft.icon")
+ && i->width == kFavIconSize && i->height == kFavIconSize) {
+ return i->url;
+ }
+ }
+ return GURL();
+}
+
+void TemplateURL::InvalidateCachedValues() const {
+ url_.InvalidateCachedValues();
+ suggestions_url_.InvalidateCachedValues();
+ if (autogenerate_keyword_)
+ keyword_.clear();
+}
+
diff --git a/chrome/browser/template_url.h b/chrome/browser/template_url.h
new file mode 100644
index 0000000..a675eec
--- /dev/null
+++ b/chrome/browser/template_url.h
@@ -0,0 +1,436 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TEMPLATE_URL_H__
+#define CHROME_BROWSER_TEMPLATE_URL_H__
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/time.h"
+#include "googleurl/src/gurl.h"
+
+class TemplateURL;
+
+// TemplateURL represents the relevant portions of the Open Search Description
+// Document (http://www.opensearch.org/Specifications/OpenSearch).
+// The main use case for TemplateURL is to use the TemplateURLRef returned by
+// suggestions_url or url for keyword/suggestion expansion:
+// . suggestions_url describes a URL that is ideal for as you type suggestions.
+// The returned results are in the mime type application/x-suggestions+json.
+// . url describes a URL that may be used as a shortcut. Returned results are
+// are text/html.
+// Before using either one, make sure it's non-NULL, and if you intend to use
+// it to replace search terms, make sure SupportsReplacement returns true.
+// To use either URL invoke the ReplaceSearchTerms method on the corresponding
+// TemplateURLRef.
+//
+// For files parsed from the Web, be sure and invoke IsValid. IsValid returns
+// true if the URL could be parsed.
+//
+// Both TemplateURL and TemplateURLRef have value semantics. This allows the
+// UI to create a copy while the user modifies the values.
+class TemplateURLRef {
+ public:
+ // Magic numbers to pass to ReplaceSearchTerms() for the |accepted_suggestion|
+ // parameter. Most callers aren't using Suggest capabilities and should just
+ // pass NO_SUGGESTIONS_AVAILABLE.
+ // NOTE: Because positive values are meaningful, make sure these are negative!
+ enum AcceptedSuggestion {
+ NO_SUGGESTION_CHOSEN = -1,
+ NO_SUGGESTIONS_AVAILABLE = -2,
+ };
+
+ TemplateURLRef();
+
+ TemplateURLRef(const std::wstring& url, int index_offset, int page_offset)
+ : url_(url),
+ index_offset_(index_offset),
+ page_offset_(page_offset),
+ parsed_(false),
+ valid_(false),
+ supports_replacements_(false) {
+ }
+
+ // Returns true if this URL supports replacement.
+ bool SupportsReplacement() const;
+
+ // Returns a string that is the result of replacing the search terms in
+ // the url with the specified value.
+ //
+ // If this TemplateURLRef does not support replacement (SupportsReplacement
+ // returns false), an empty string is returned.
+ //
+ // The TemplateURL is used to determine the input encoding for the term.
+ GURL ReplaceSearchTerms(
+ const TemplateURL& host,
+ const std::wstring& terms,
+ int accepted_suggestion,
+ const std::wstring& original_query_for_suggestion) const;
+
+ // Returns the raw URL. None of the parameters will have been replaced.
+ const std::wstring& url() const { return url_; }
+
+ // Returns the index number of the first search result.
+ int index_offset() const { return index_offset_; }
+
+ // Returns the page number of the first search results.
+ int page_offset() const { return page_offset_; }
+
+ // Returns true if the TemplateURLRef is valid. An invalid TemplateURLRef is
+ // one that contains unknown terms, or invalid characters.
+ bool IsValid() const;
+
+ // Returns a string representation of this TemplateURLRef suitable for
+ // display. The display format is the same as the format used by Firefox.
+ std::wstring DisplayURL() const;
+
+ // Converts a string as returned by DisplayURL back into a string as
+ // understood by TemplateURLRef.
+ static std::wstring DisplayURLToURLRef(const std::wstring& display_url);
+
+ // If this TemplateURLRef is valid and contains one search term, this returns
+ // the host/path of the URL, otherwise this returns an empty string.
+ const std::string& GetHost() const;
+ const std::string& GetPath() const;
+
+ // If this TemplateURLRef is valid and contains one search term, this returns
+ // the key of the search term, otherwise this returns an empty string.
+ const std::string& GetSearchTermKey() const;
+
+ // Converts the specified term in the encoding of the host TemplateURL to a
+ // wide string.
+ std::wstring SearchTermToWide(const TemplateURL& host,
+ const std::string& term) const;
+
+ // Returns true if this TemplateURLRef has a replacement term of
+ // {google:baseURL} or {google:baseSuggestURL}.
+ bool HasGoogleBaseURLs() const;
+
+ private:
+ friend class TemplateURL;
+ friend class TemplateURLModelTest;
+ friend class TemplateURLTest;
+
+ // Enumeration of the known types.
+ enum ReplacementType {
+ ENCODING,
+ GOOGLE_ACCEPTED_SUGGESTION,
+ GOOGLE_BASE_URL,
+ GOOGLE_BASE_SUGGEST_URL,
+ GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION,
+ GOOGLE_RLZ,
+ GOOGLE_UNESCAPED_SEARCH_TERMS,
+ LANGUAGE,
+ SEARCH_TERMS,
+ };
+
+ // Used to identify an element of the raw url that can be replaced.
+ struct Replacement {
+ Replacement(ReplacementType type, int index) : type(type), index(index) {}
+ ReplacementType type;
+ int index;
+ };
+
+ // The list of elements to replace.
+ typedef std::vector<struct Replacement> Replacements;
+
+ // TemplateURLRef internally caches values to make replacement quick. This
+ // method invalidates any cached values.
+ void InvalidateCachedValues() const;
+
+ // Resets the url.
+ void Set(const std::wstring& url, int index_offset, int page_offset);
+
+ // Parses the parameter in url at the specified offset. start/end specify the
+ // range of the parameter in the url, including the braces. If the parameter
+ // is valid, url is updated to reflect the appropriate parameter. If
+ // the parameter is one of the known parameters an element is added to
+ // replacements indicating the type and range of the element.
+ //
+ // If the parameter is not a known parameter, false is returned.
+ bool ParseParameter(size_t start,
+ size_t end,
+ std::wstring* url,
+ Replacements* replacements) const;
+
+ // Parses the specified url, replacing parameters as necessary. If
+ // successful, valid is set to true, and the parsed url is returned. For all
+ // known parameters that are encountered an entry is added to replacements.
+ // If there is an error parsing (unknown parameter, or bogus url), valid is
+ // set to false, and an empty string is returned.
+ std::wstring ParseURL(const std::wstring& url,
+ Replacements* replacements,
+ bool* valid) const;
+
+ // If the url has not yet been parsed, ParseURL is invoked.
+ // NOTE: While this is const, it modifies parsed_, valid_, parsed_url_ and
+ // search_offset_.
+ void ParseIfNecessary() const;
+
+ // Extracts the query key and host from the url.
+ void ParseHostAndSearchTermKey() const;
+
+ // Returns the value for the GOOGLE_BASE_URL term.
+ static std::wstring GoogleBaseURLValue();
+
+ // Returns the value for the GOOGLE_BASE_SUGGEST_URL term.
+ static std::wstring GoogleBaseSuggestURLValue();
+
+ // The raw URL. Where as this contains all the terms (such as {searchTerms}),
+ // parsed_url_ has them all stripped out.
+ std::wstring url_;
+
+ // indexOffset defined for the Url element.
+ int index_offset_;
+
+ // searchOffset defined for the Url element.
+ int page_offset_;
+
+ // Whether the URL has been parsed.
+ mutable bool parsed_;
+
+ // Whether the url was successfully parsed.
+ mutable bool valid_;
+
+ // The parsed URL. All terms have been stripped out of this with
+ // replacements_ giving the index of the terms to replace.
+ mutable std::wstring parsed_url_;
+
+ // Do we support replacement?
+ mutable bool supports_replacements_;
+
+ // The replaceable parts of url (parsed_url_). These are ordered by index
+ // into the string, and may be empty.
+ mutable Replacements replacements_;
+
+ // Host, path and key of the search term. These are only set if the url
+ // contains one search term.
+ mutable std::string host_;
+ mutable std::string path_;
+ mutable std::string search_term_key_;
+
+ // For testing. If non-null this is the replacement value for GOOGLE_BASE_URL
+ // terms.
+ static std::wstring* google_base_url_;
+};
+
+// Describes the relevant portions of a single OSD document.
+class TemplateURL {
+ public:
+ typedef int64 IDType;
+
+ // Describes a single image reference. Each TemplateURL may have
+ // any number (including 0) of ImageRefs.
+ //
+ // If a TemplateURL has no images, the favicon for the generated URL
+ // should be used.
+ struct ImageRef {
+ ImageRef(const std::wstring& type, int width, int height)
+ : type(type), width(width), height(height) {
+ }
+
+ ImageRef(const std::wstring& type, int width, int height, const GURL& url)
+ : type(type), width(width), height(height), url(url) {
+ }
+
+ // Mime type for the image.
+ // ICO image will have the format: image/x-icon or image/vnd.microsoft.icon
+ std::wstring type;
+
+ // Size of the image
+ int width;
+ int height;
+
+ // URL of the image.
+ GURL url;
+ };
+
+ // Generates a favicon URL from the specified url.
+ static GURL GenerateFaviconURL(const GURL& url);
+
+ TemplateURL()
+ : autogenerate_keyword_(false),
+ show_in_default_list_(false),
+ safe_for_autoreplace_(false),
+ id_(0),
+ date_created_(base::Time::Now()),
+ usage_count_(0),
+ prepopulate_id_(0) {}
+ ~TemplateURL() {}
+
+ // A short description of the template. This is the name we show to the user
+ // in various places that use keywords. For example, the location bar shows
+ // this when the user selects the keyword.
+ void set_short_name(const std::wstring& short_name) {
+ short_name_ = short_name;
+ }
+ const std::wstring& short_name() const { return short_name_; }
+
+ // A description of the template; this may be empty.
+ void set_description(const std::wstring& description) {
+ description_ = description;
+ }
+ const std::wstring& description() const { return description_; }
+
+ // URL providing JSON results. This is typically used to provide suggestions
+ // as your type. If NULL, this url does not support suggestions.
+ // Be sure and check the resulting TemplateURLRef for SupportsReplacement
+ // before using.
+ void SetSuggestionsURL(const std::wstring& suggestions_url,
+ int index_offset,
+ int page_offset);
+ const TemplateURLRef* suggestions_url() const {
+ if (suggestions_url_.url().empty())
+ return NULL;
+ return &suggestions_url_;
+ }
+
+ // Parameterized URL for providing the results. This may be NULL.
+ // Be sure and check the resulting TemplateURLRef for SupportsReplacement
+ // before using.
+ void SetURL(const std::wstring& url, int index_offset, int page_offset);
+ // Returns the TemplateURLRef that may be used for search results. This
+ // returns NULL if a url element was not specified.
+ const TemplateURLRef* url() const {
+ if (url_.url().empty())
+ return NULL;
+ return &url_;
+ }
+
+ // URL to the OSD file this came from. May be empty.
+ void set_originating_url(const GURL& url) {
+ originating_url_ = url;
+ }
+ const GURL& originating_url() const { return originating_url_; }
+
+ // The shortcut for this template url. May be empty.
+ void set_keyword(const std::wstring& keyword);
+ const std::wstring& keyword() const;
+
+ // Whether to autogenerate a keyword from the url() in GetKeyword(). Most
+ // consumers should not need this.
+ // NOTE: Calling set_keyword() turns this back off. Manual and automatic
+ // keywords are mutually exclusive.
+ void set_autogenerate_keyword(bool autogenerate_keyword) {
+ autogenerate_keyword_ = autogenerate_keyword;
+ if (autogenerate_keyword_)
+ keyword_.clear();
+ }
+ bool autogenerate_keyword() const {
+ return autogenerate_keyword_;
+ }
+
+ // Whether this keyword is shown in the default list of search providers. This
+ // is just a property and does not indicate whether this TemplateURL has
+ // a TemplateURLRef that supports replacement. Use ShowInDefaultList to
+ // test both.
+ // The default value is false.
+ void set_show_in_default_list(bool show_in_default_list) {
+ show_in_default_list_ = show_in_default_list;
+ }
+ bool show_in_default_list() const { return show_in_default_list_; }
+
+ // Returns true if show_in_default_list() is true and this TemplateURL has a
+ // TemplateURLRef that supports replacement.
+ bool ShowInDefaultList() const;
+
+ // Whether it's safe for auto-modification code (the autogenerator and the
+ // code that imports data from other browsers) to replace the TemplateURL.
+ // This should be set to false for any keyword the user edits, or any keyword
+ // that the user clearly manually edited in the past, like a bookmark keyword
+ // from another browser.
+ void set_safe_for_autoreplace(bool safe_for_autoreplace) {
+ safe_for_autoreplace_ = safe_for_autoreplace;
+ }
+ bool safe_for_autoreplace() const { return safe_for_autoreplace_; }
+
+ // Images for this URL. May be empty.
+ void add_image_ref(const ImageRef& ref) { image_refs_.push_back(ref); }
+ const std::vector<ImageRef>& image_refs() const { return image_refs_; }
+
+ // Convenience methods for getting/setting an ImageRef that points to a
+ // favicon. A TemplateURL need not have an ImageRef for a favicon. In such
+ // a situation GetFavIconURL returns an invalid url.
+ //
+ // If url is empty and there is an image ref for a favicon, it is removed.
+ void SetFavIconURL(const GURL& url);
+ GURL GetFavIconURL() const;
+
+ // Set of languages supported. This may be empty.
+ void add_language(const std::wstring& language) {
+ languages_.push_back(language);
+ }
+ const std::vector<std::wstring>& languages() const { return languages_; }
+
+ // Date this keyword was created.
+ //
+ // NOTE: this may be 0, which indicates the keyword was created before we
+ // started tracking creation time.
+ void set_date_created(base::Time time) { date_created_ = time; }
+ base::Time date_created() const { return date_created_; }
+
+ // Number of times this keyword has been explicitly used to load a URL. We
+ // don't increment this for uses as the "default search engine" since that's
+ // not really "explicit" usage and incrementing would result in pinning the
+ // user's default search engine(s) to the top of the list of searches on the
+ // New Tab page, de-emphasizing the omnibox as "where you go to search".
+ void set_usage_count(int count) { usage_count_ = count; }
+ int usage_count() const { return usage_count_; }
+
+ // The list of supported encodings for the search terms. This may be empty,
+ // which indicates the terms should be encoded with UTF-8.
+ void set_input_encodings(const std::vector<std::string>& encodings) {
+ input_encodings_ = encodings;
+ }
+ void add_input_encoding(const std::string& encoding) {
+ input_encodings_.push_back(encoding);
+ }
+ const std::vector<std::string>& input_encodings() const {
+ return input_encodings_;
+ }
+
+ // Returns the unique identifier of this TemplateURL. The unique ID is set
+ // by the TemplateURLModel when the TemplateURL is added to it.
+ IDType id() const { return id_; }
+
+ // If this TemplateURL comes from prepopulated data the prepopulate_id is > 0.
+ void set_prepopulate_id(int id) { prepopulate_id_ = id; }
+ int prepopulate_id() const { return prepopulate_id_; }
+
+ private:
+ friend class WebDatabaseTest;
+ friend class WebDatabase;
+ friend class TemplateURLModel;
+
+ // Invalidates cached values on this object and its child TemplateURLRefs.
+ void InvalidateCachedValues() const;
+
+ // Unique identifier, used when archived to the database.
+ void set_id(IDType id) { id_ = id;}
+
+ std::wstring short_name_;
+ std::wstring description_;
+ TemplateURLRef suggestions_url_;
+ TemplateURLRef url_;
+ GURL originating_url_;
+ mutable std::wstring keyword_;
+ bool autogenerate_keyword_; // If this is set, |keyword_| holds the cached
+ // generated keyword if available.
+ bool show_in_default_list_;
+ bool safe_for_autoreplace_;
+ std::vector<ImageRef> image_refs_;
+ std::vector<std::wstring> languages_;
+ // List of supported input encodings.
+ std::vector<std::string> input_encodings_;
+ IDType id_;
+ base::Time date_created_;
+ int usage_count_;
+ int prepopulate_id_;
+
+ // TODO(sky): Add date last parsed OSD file.
+};
+
+#endif // CHROME_BROWSER_TEMPLATE_URL_PARSER_H__
+
diff --git a/chrome/browser/template_url_fetcher.cc b/chrome/browser/template_url_fetcher.cc
new file mode 100644
index 0000000..57bb259
--- /dev/null
+++ b/chrome/browser/template_url_fetcher.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/template_url_fetcher.h"
+
+#include "chrome/browser/profile.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
+#include "chrome/browser/template_url_parser.h"
+#include "chrome/browser/views/edit_keyword_controller.h"
+
+// RequestDelegate ------------------------------------------------------------
+
+void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete(
+ const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ // Make sure we can still replace the keyword.
+ if (response_code != 200) {
+ fetcher_->RequestCompleted(this);
+ // WARNING: RequestCompleted deletes us.
+ return;
+ }
+
+ scoped_ptr<TemplateURL> template_url(new TemplateURL());
+ if (TemplateURLParser::Parse(
+ reinterpret_cast<const unsigned char*>(data.c_str()),
+ data.length(),
+ NULL,
+ template_url.get()) &&
+ template_url->url() && template_url->url()->SupportsReplacement()) {
+ TemplateURLModel* model = fetcher_->profile()->GetTemplateURLModel();
+ const TemplateURL* existing_url;
+ if (!model || !model->loaded() ||
+ !model->CanReplaceKeyword(keyword_, template_url->url()->url(),
+ &existing_url)) {
+ // TODO(pamg): If we're coming from JS (not autodetected) and this URL
+ // already exists in the model, consider bringing up the
+ // EditKeywordController to edit it. This would be helpful feedback in
+ // the case of clicking a button twice, and annoying in the case of a
+ // page that calls AddSearchProvider() in JS without a user action.
+ fetcher_->RequestCompleted(this);
+ // WARNING: RequestCompleted deletes us.
+ return;
+ }
+
+ if (existing_url)
+ model->Remove(existing_url);
+
+ // The short name is what is shown to the user. We reset it to make sure
+ // we don't display random text from the web.
+ template_url->set_short_name(keyword_);
+ template_url->set_keyword(keyword_);
+ template_url->set_originating_url(osdd_url_);
+
+ // The page may have specified a URL to use for favicons, if not, set it.
+ if (!template_url->GetFavIconURL().is_valid())
+ template_url->SetFavIconURL(favicon_url_);
+
+ if (autodetected_) {
+ // Mark the keyword as replaceable so it can be removed if necessary.
+ template_url->set_safe_for_autoreplace(true);
+ model->Add(template_url.release());
+ } else {
+ // Confirm addition and allow user to edit default choices. It's ironic
+ // that only *non*-autodetected additions get confirmed, but the user
+ // expects feedback that his action did something.
+ // The edit controller will take care of adding the URL to the model,
+ // which takes ownership, or of deleting it if the add is cancelled.
+ EditKeywordController* controller =
+ new EditKeywordController(parent_window_,
+ template_url.release(),
+ NULL, // no KeywordEditorView
+ fetcher_->profile());
+ controller->Show();
+ }
+ }
+ fetcher_->RequestCompleted(this);
+ // WARNING: RequestCompleted deletes us.
+}
+
+// TemplateURLFetcher ---------------------------------------------------------
+
+TemplateURLFetcher::TemplateURLFetcher(Profile* profile) : profile_(profile) {
+ DCHECK(profile_);
+}
+
+void TemplateURLFetcher::ScheduleDownload(const std::wstring& keyword,
+ const GURL& osdd_url,
+ const GURL& favicon_url,
+ const HWND parent_window,
+ bool autodetected) {
+ DCHECK(!keyword.empty() && osdd_url.is_valid());
+ // Make sure we aren't already downloading this request.
+ for (std::vector<RequestDelegate*>::iterator i = requests_->begin();
+ i != requests_->end(); ++i) {
+ if ((*i)->url() == osdd_url || (*i)->keyword() == keyword)
+ return;
+ }
+
+ requests_->push_back(
+ new RequestDelegate(this, keyword, osdd_url, favicon_url, parent_window,
+ autodetected));
+}
+
+void TemplateURLFetcher::RequestCompleted(RequestDelegate* request) {
+ DCHECK(find(requests_->begin(), requests_->end(), request) !=
+ requests_->end());
+ requests_->erase(find(requests_->begin(), requests_->end(), request));
+ delete request;
+}
+
diff --git a/chrome/browser/template_url_fetcher.h b/chrome/browser/template_url_fetcher.h
new file mode 100644
index 0000000..a07277f
--- /dev/null
+++ b/chrome/browser/template_url_fetcher.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TEMPLATE_URL_FETCHER_H__
+#define CHROME_BROWSER_TEMPLATE_URL_FETCHER_H__
+
+#include "chrome/browser/profile.h"
+#include "chrome/browser/url_fetcher.h"
+#include "chrome/common/scoped_vector.h"
+
+class GURL;
+class Profile;
+class TemplateURL;
+class WebContents;
+
+// TemplateURLFetcher is responsible for downloading OpenSearch description
+// documents, creating a TemplateURL from the OSDD, and adding the TemplateURL
+// to the TemplateURLModel. Downloading is done in the background.
+//
+class TemplateURLFetcher {
+ public:
+ // Creates a TemplateURLFetcher with the specified Profile.
+ explicit TemplateURLFetcher(Profile* profile);
+
+ // If TemplateURLFetcher is not already downloading the OSDD for osdd_url,
+ // it is downloaded. If successful and the result can be parsed, a TemplateURL
+ // is added to the TemplateURLModel.
+ void ScheduleDownload(const std::wstring& keyword,
+ const GURL& osdd_url,
+ const GURL& favicon_url,
+ const HWND parent_window,
+ bool autodetected);
+
+ private:
+ friend class RequestDelegate;
+
+ // A RequestDelegate is created to download each OSDD. When done downloading
+ // RequestCompleted is invoked back on the TemplateURLFetcher.
+ class RequestDelegate : public URLFetcher::Delegate {
+ public:
+ RequestDelegate(TemplateURLFetcher* fetcher,
+ const std::wstring& keyword,
+ const GURL& osdd_url,
+ const GURL& favicon_url,
+ const HWND parent_window,
+ bool autodetected)
+#pragma warning(disable:4355)
+ : url_fetcher_(osdd_url, URLFetcher::GET, this),
+ fetcher_(fetcher),
+ keyword_(keyword),
+ osdd_url_(osdd_url),
+ favicon_url_(favicon_url),
+ parent_window_(parent_window),
+ autodetected_(autodetected) {
+ url_fetcher_.set_request_context(fetcher->profile()->GetRequestContext());
+ url_fetcher_.Start();
+ }
+
+ // If data contains a valid OSDD, a TemplateURL is created and added to
+ // the TemplateURLModel.
+ virtual void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+
+ // URL of the OSDD.
+ const GURL& url() const { return osdd_url_; }
+
+ // Keyword to use.
+ const std::wstring keyword() const { return keyword_; }
+
+ private:
+ URLFetcher url_fetcher_;
+ TemplateURLFetcher* fetcher_;
+ const std::wstring keyword_;
+ const GURL osdd_url_;
+ const GURL favicon_url_;
+ bool autodetected_;
+
+ // Used to determine where to place a confirmation dialog. May be NULL,
+ // in which case the confirmation will be centered in the screen if needed.
+ const HWND parent_window_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RequestDelegate);
+ };
+
+ Profile* profile() const { return profile_; }
+
+ // Invoked from the RequestDelegate when done downloading.
+ void RequestCompleted(RequestDelegate* request);
+
+ Profile* profile_;
+
+ // In progress requests.
+ ScopedVector<RequestDelegate> requests_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TemplateURLFetcher);
+};
+
+#endif // CHROME_BROWSER_OSDD_FETCHER_H__
+
diff --git a/chrome/browser/template_url_model.cc b/chrome/browser/template_url_model.cc
new file mode 100644
index 0000000..a3ffd5f
--- /dev/null
+++ b/chrome/browser/template_url_model.cc
@@ -0,0 +1,980 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/template_url_model.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "chrome/app/locales/locale_settings.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/google_url_tracker.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/rlz/rlz.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_prepopulate_data.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/common/stl_util-inl.h"
+#include "googleurl/src/gurl.h"
+#include "googleurl/src/url_parse.h"
+#include "net/base/net_util.h"
+#include "unicode/rbbi.h"
+#include "unicode/uchar.h"
+
+using base::Time;
+
+// String in the URL that is replaced by the search term.
+static const wchar_t kSearchTermParameter[] = L"{searchTerms}";
+
+// String in Initializer that is replaced with kSearchTermParameter.
+static const wchar_t kTemplateParameter[] = L"%s";
+
+// Term used when generating a search url. Use something obscure so that on
+// the rare case the term replaces the URL it's unlikely another keyword would
+// have the same url.
+static const wchar_t kReplacementTerm[] = L"blah.blah.blah.blah.blah";
+
+class TemplateURLModel::LessWithPrefix {
+ public:
+ // We want to find the set of keywords that begin with a prefix. The STL
+ // algorithms will return the set of elements that are "equal to" the
+ // prefix, where "equal(x, y)" means "!(cmp(x, y) || cmp(y, x))". When
+ // cmp() is the typical std::less<>, this results in lexicographic equality;
+ // we need to extend this to mark a prefix as "not less than" a keyword it
+ // begins, which will cause the desired elements to be considered "equal to"
+ // the prefix. Note: this is still a strict weak ordering, as required by
+ // equal_range() (though I will not prove that here).
+ //
+ // Unfortunately the calling convention is not "prefix and element" but
+ // rather "two elements", so we pass the prefix as a fake "element" which has
+ // a NULL KeywordDataElement pointer.
+ bool operator()(const KeywordToTemplateMap::value_type& elem1,
+ const KeywordToTemplateMap::value_type& elem2) const {
+ return (elem1.second == NULL) ?
+ (elem2.first.compare(0, elem1.first.length(), elem1.first) > 0) :
+ (elem1.first < elem2.first);
+ }
+};
+
+TemplateURLModel::TemplateURLModel(Profile* profile)
+ : profile_(profile),
+ loaded_(false),
+ load_handle_(0),
+ default_search_provider_(NULL),
+ next_id_(1) {
+ DCHECK(profile_);
+ Init(NULL, 0);
+}
+
+TemplateURLModel::TemplateURLModel(const Initializer* initializers,
+ const int count)
+ : profile_(NULL),
+ loaded_(true),
+ load_handle_(0),
+ service_(NULL),
+ default_search_provider_(NULL),
+ next_id_(1) {
+ Init(initializers, count);
+}
+
+TemplateURLModel::~TemplateURLModel() {
+ if (load_handle_) {
+ DCHECK(service_.get());
+ service_->CancelRequest(load_handle_);
+ }
+
+ STLDeleteElements(&template_urls_);
+
+ NotificationService* ns = NotificationService::current();
+ if (profile_) {
+ ns->RemoveObserver(this, NOTIFY_HISTORY_URL_VISITED,
+ Source<Profile>(profile_->GetOriginalProfile()));
+ }
+ ns->RemoveObserver(this, NOTIFY_GOOGLE_URL_UPDATED,
+ NotificationService::AllSources());
+}
+
+void TemplateURLModel::Init(const Initializer* initializers,
+ int num_initializers) {
+ // Register for notifications.
+ NotificationService* ns = NotificationService::current();
+ if (profile_) {
+ // TODO(sky): bug 1166191. The keywords should be moved into the history
+ // db, which will mean we no longer need this notification and the history
+ // backend can handle automatically adding the search terms as the user
+ // navigates.
+ ns->AddObserver(this, NOTIFY_HISTORY_URL_VISITED,
+ Source<Profile>(profile_->GetOriginalProfile()));
+ }
+ ns->AddObserver(this, NOTIFY_GOOGLE_URL_UPDATED,
+ NotificationService::AllSources());
+
+ // Add specific initializers, if any.
+ for (int i(0); i < num_initializers; ++i) {
+ DCHECK(initializers[i].keyword);
+ DCHECK(initializers[i].url);
+ DCHECK(initializers[i].content);
+
+ size_t template_position =
+ std::wstring(initializers[i].url).find(kTemplateParameter);
+ DCHECK(template_position != std::wstring::npos);
+ std::wstring osd_url(initializers[i].url);
+ osd_url.replace(template_position, arraysize(kTemplateParameter) - 1,
+ kSearchTermParameter);
+
+ // TemplateURLModel ends up owning the TemplateURL, don't try and free it.
+ TemplateURL* template_url = new TemplateURL();
+ template_url->set_keyword(initializers[i].keyword);
+ template_url->set_short_name(initializers[i].content);
+ template_url->SetURL(osd_url, 0, 0);
+ Add(template_url);
+ }
+
+ // Request a server check for the correct Google URL if Google is the default
+ // search engine.
+ const TemplateURL* default_provider = GetDefaultSearchProvider();
+ if (default_provider) {
+ const TemplateURLRef* default_provider_ref = default_provider->url();
+ if (default_provider_ref && default_provider_ref->HasGoogleBaseURLs())
+ GoogleURLTracker::RequestServerCheck();
+ }
+}
+
+// static
+std::wstring TemplateURLModel::GenerateKeyword(const GURL& url,
+ bool autodetected) {
+ // Don't autogenerate keywords for referrers that are the result of a form
+ // submission (TODO: right now we approximate this by checking for the URL
+ // having a query, but we should replace this with a call to WebCore to see if
+ // the originating page was actually a form submission), anything other than
+ // http, or referrers with a path.
+ //
+ // If we relax the path constraint, we need to be sure to sanitize the path
+ // elements and update AutocompletePopup to look for keywords using the path.
+ // See http://b/issue?id=863583.
+ if (!url.is_valid() ||
+ (autodetected && (url.has_query() || (url.scheme() != "http") ||
+ ((url.path() != "") && (url.path() != "/")))))
+ return std::wstring();
+
+ // Strip "www." off the front of the keyword; otherwise the keyword won't work
+ // properly. See http://b/issue?id=1205573.
+ return net::StripWWW(UTF8ToWide(url.host()));
+}
+
+// static
+std::wstring TemplateURLModel::CleanUserInputKeyword(
+ const std::wstring& keyword) {
+ // Remove the scheme.
+ std::wstring result(l10n_util::ToLower(keyword));
+ url_parse::Component scheme_component;
+ if (url_parse::ExtractScheme(WideToUTF8(keyword).c_str(),
+ static_cast<int>(keyword.length()),
+ &scheme_component)) {
+ // Include trailing ':'.
+ result.erase(0, scheme_component.end() + 1);
+ // Many schemes usually have "//" after them, so strip it too.
+ const std::wstring after_scheme(L"//");
+ if (result.compare(0, after_scheme.length(), after_scheme) == 0)
+ result.erase(0, after_scheme.length());
+ }
+
+ // Remove leading "www.".
+ result = net::StripWWW(result);
+
+ // Remove trailing "/".
+ return (result.length() > 0 && result[result.length() - 1] == L'/') ?
+ result.substr(0, result.length() - 1) : result;
+}
+
+// static
+GURL TemplateURLModel::GenerateSearchURL(const TemplateURL* t_url) {
+ DCHECK(t_url);
+ const TemplateURLRef* search_ref = t_url->url();
+ if (!search_ref || !search_ref->IsValid())
+ return GURL();
+
+ if (!search_ref->SupportsReplacement())
+ return GURL(WideToUTF8(search_ref->url()));
+
+ return search_ref->ReplaceSearchTerms(
+ *t_url,
+ kReplacementTerm,
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+}
+
+bool TemplateURLModel::CanReplaceKeyword(
+ const std::wstring& keyword,
+ const std::wstring& url,
+ const TemplateURL** template_url_to_replace) {
+ DCHECK(!keyword.empty()); // This should only be called for non-empty
+ // keywords. If we need to support empty kewords
+ // the code needs to change slightly.
+ const TemplateURL* existing_url = GetTemplateURLForKeyword(keyword);
+ if (existing_url) {
+ // We already have a TemplateURL for this keyword. Only allow it to be
+ // replaced if the TemplateURL can be replaced.
+ if (template_url_to_replace)
+ *template_url_to_replace = existing_url;
+ return CanReplace(existing_url);
+ }
+
+ // We don't have a TemplateURL with keyword. Only allow a new one if there
+ // isn't a TemplateURL for the specified host, or there is one but it can
+ // be replaced. We do this to ensure that if the user assigns a different
+ // keyword to a generated TemplateURL, we won't regenerate another keyword for
+ // the same host.
+ GURL gurl(WideToUTF8(url));
+ if (gurl.is_valid() && !gurl.host().empty())
+ return CanReplaceKeywordForHost(gurl.host(), template_url_to_replace);
+ return true;
+}
+
+void TemplateURLModel::FindMatchingKeywords(
+ const std::wstring& prefix,
+ bool support_replacement_only,
+ std::vector<std::wstring>* matches) const {
+ // Sanity check args.
+ if (prefix.empty())
+ return;
+ DCHECK(matches != NULL);
+ DCHECK(matches->empty()); // The code for exact matches assumes this.
+
+ // Find matching keyword range. Searches the element map for keywords
+ // beginning with |prefix| and stores the endpoints of the resulting set in
+ // |match_range|.
+ const std::pair<KeywordToTemplateMap::const_iterator,
+ KeywordToTemplateMap::const_iterator> match_range(
+ std::equal_range(
+ keyword_to_template_map_.begin(), keyword_to_template_map_.end(),
+ KeywordToTemplateMap::value_type(prefix, NULL), LessWithPrefix()));
+
+ // Return vector of matching keywords.
+ for (KeywordToTemplateMap::const_iterator i(match_range.first);
+ i != match_range.second; ++i) {
+ DCHECK(i->second->url());
+ if (!support_replacement_only || i->second->url()->SupportsReplacement())
+ matches->push_back(i->first);
+ }
+}
+
+const TemplateURL* TemplateURLModel::GetTemplateURLForKeyword(
+ const std::wstring& keyword) const {
+ KeywordToTemplateMap::const_iterator elem(
+ keyword_to_template_map_.find(keyword));
+ return (elem == keyword_to_template_map_.end()) ? NULL : elem->second;
+}
+
+const TemplateURL* TemplateURLModel::GetTemplateURLForHost(
+ const std::string& host) const {
+ HostToURLsMap::const_iterator iter = host_to_urls_map_.find(host);
+ if (iter == host_to_urls_map_.end() || iter->second.empty())
+ return NULL;
+ return *(iter->second.begin()); // Return the 1st element.
+}
+
+void TemplateURLModel::Add(TemplateURL* template_url) {
+ DCHECK(template_url);
+ DCHECK(template_url->id() == 0);
+ DCHECK(find(template_urls_.begin(), template_urls_.end(), template_url) ==
+ template_urls_.end());
+ template_url->set_id(++next_id_);
+ template_urls_.push_back(template_url);
+ AddToMaps(template_url);
+
+ if (service_.get())
+ service_->AddKeyword(*template_url);
+
+ if (loaded_) {
+ FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
+ OnTemplateURLModelChanged());
+ }
+}
+
+void TemplateURLModel::AddToMaps(const TemplateURL* template_url) {
+ if (!template_url->keyword().empty())
+ keyword_to_template_map_[template_url->keyword()] = template_url;
+
+ const GURL url(GenerateSearchURL(template_url));
+ if (url.is_valid() && url.has_host())
+ host_to_urls_map_[url.host()].insert(template_url);
+}
+
+void TemplateURLModel::Remove(const TemplateURL* template_url) {
+ TemplateURLVector::iterator i = find(template_urls_.begin(),
+ template_urls_.end(),
+ template_url);
+ if (i == template_urls_.end())
+ return;
+
+ if (template_url == default_search_provider_) {
+ // Should never delete the default search provider.
+ NOTREACHED();
+ return;
+ }
+
+ RemoveFromMaps(template_url);
+
+ // Remove it from the vector containing all TemplateURLs.
+ template_urls_.erase(i);
+
+ if (loaded_) {
+ FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
+ OnTemplateURLModelChanged());
+ }
+
+ if (service_.get())
+ service_->RemoveKeyword(*template_url);
+
+ if (profile_) {
+ HistoryService* history =
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (history)
+ history->DeleteAllSearchTermsForKeyword(template_url->id());
+ }
+
+ // We own the TemplateURL and need to delete it.
+ delete template_url;
+}
+
+void TemplateURLModel::Replace(const TemplateURL* existing_turl,
+ TemplateURL* new_turl) {
+ DCHECK(existing_turl && new_turl);
+
+ TemplateURLVector::iterator i = find(template_urls_.begin(),
+ template_urls_.end(),
+ existing_turl);
+ DCHECK(i != template_urls_.end());
+ RemoveFromMaps(existing_turl);
+ template_urls_.erase(i);
+
+ new_turl->set_id(existing_turl->id());
+
+ template_urls_.push_back(new_turl);
+ AddToMaps(new_turl);
+
+ if (service_.get())
+ service_->UpdateKeyword(*new_turl);
+
+ if (default_search_provider_ == existing_turl)
+ SetDefaultSearchProvider(new_turl);
+
+ if (loaded_) {
+ FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
+ OnTemplateURLModelChanged());
+ }
+
+ delete existing_turl;
+}
+
+void TemplateURLModel::RemoveAutoGeneratedBetween(Time created_after,
+ Time created_before) {
+ for (size_t i = 0; i < template_urls_.size();) {
+ if (template_urls_[i]->date_created() >= created_after &&
+ (created_before.is_null() ||
+ template_urls_[i]->date_created() < created_before) &&
+ CanReplace(template_urls_[i])) {
+ Remove(template_urls_[i]);
+ } else {
+ ++i;
+ }
+ }
+}
+
+void TemplateURLModel::RemoveAutoGeneratedSince(Time created_after) {
+ RemoveAutoGeneratedBetween(created_after, Time());
+}
+
+void TemplateURLModel::SetKeywordSearchTermsForURL(const TemplateURL* t_url,
+ const GURL& url,
+ const std::wstring& term) {
+ HistoryService* history = profile_ ?
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS) : NULL;
+ if (!history)
+ return;
+ history->SetKeywordSearchTermsForURL(url, t_url->id(), term);
+}
+
+void TemplateURLModel::RemoveFromMaps(const TemplateURL* template_url) {
+ if (!template_url->keyword().empty()) {
+ keyword_to_template_map_.erase(template_url->keyword());
+ }
+
+ const GURL url(GenerateSearchURL(template_url));
+ if (url.is_valid() && url.has_host()) {
+ const std::string host(url.host());
+ DCHECK(host_to_urls_map_.find(host) != host_to_urls_map_.end());
+ TemplateURLSet& urls = host_to_urls_map_[host];
+ DCHECK(urls.find(template_url) != urls.end());
+ urls.erase(urls.find(template_url));
+ if (urls.empty())
+ host_to_urls_map_.erase(host_to_urls_map_.find(host));
+ }
+}
+
+void TemplateURLModel::RemoveFromMapsByPointer(
+ const TemplateURL* template_url) {
+ DCHECK(template_url);
+ for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin();
+ i != keyword_to_template_map_.end(); ++i) {
+ if (i->second == template_url) {
+ keyword_to_template_map_.erase(i);
+ // A given TemplateURL only occurs once in the map. As soon as we find the
+ // entry, stop.
+ break;
+ }
+ }
+
+ for (HostToURLsMap::iterator i = host_to_urls_map_.begin();
+ i != host_to_urls_map_.end(); ++i) {
+ TemplateURLSet::iterator url_set_iterator = i->second.find(template_url);
+ if (url_set_iterator != i->second.end()) {
+ i->second.erase(url_set_iterator);
+ if (i->second.empty())
+ host_to_urls_map_.erase(i);
+ // A given TemplateURL only occurs once in the map. As soon as we find the
+ // entry, stop.
+ return;
+ }
+ }
+}
+
+void TemplateURLModel::SetTemplateURLs(
+ const std::vector<const TemplateURL*>& urls) {
+ DCHECK(template_urls_.empty()); // This should only be called on load,
+ // when we have no TemplateURLs.
+
+ // Add mappings for the new items.
+ for (TemplateURLVector::const_iterator i = urls.begin(); i != urls.end();
+ ++i) {
+ next_id_ = std::max(next_id_, (*i)->id());
+ AddToMaps(*i);
+ }
+
+ template_urls_ = urls;
+}
+
+std::vector<const TemplateURL*> TemplateURLModel::GetTemplateURLs() const {
+ return template_urls_;
+}
+
+void TemplateURLModel::IncrementUsageCount(const TemplateURL* url) {
+ DCHECK(url && find(template_urls_.begin(), template_urls_.end(), url) !=
+ template_urls_.end());
+ const_cast<TemplateURL*>(url)->set_usage_count(url->usage_count() + 1);
+ if (service_.get())
+ service_.get()->UpdateKeyword(*url);
+}
+
+void TemplateURLModel::ResetTemplateURL(const TemplateURL* url,
+ const std::wstring& title,
+ const std::wstring& keyword,
+ const std::wstring& search_url) {
+ DCHECK(url && find(template_urls_.begin(), template_urls_.end(), url) !=
+ template_urls_.end());
+ RemoveFromMaps(url);
+ TemplateURL* modifiable_url = const_cast<TemplateURL*>(url);
+ modifiable_url->set_short_name(title);
+ modifiable_url->set_keyword(keyword);
+ if ((modifiable_url->url() && search_url.empty()) ||
+ (!modifiable_url->url() && !search_url.empty()) ||
+ (modifiable_url->url() && modifiable_url->url()->url() != search_url)) {
+ // The urls have changed, reset the favicon url.
+ modifiable_url->SetFavIconURL(GURL());
+ modifiable_url->SetURL(search_url, 0, 0);
+ }
+ modifiable_url->set_safe_for_autoreplace(false);
+ AddToMaps(url);
+ if (service_.get())
+ service_.get()->UpdateKeyword(*url);
+
+ FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
+ OnTemplateURLModelChanged());
+}
+
+void TemplateURLModel::SetDefaultSearchProvider(const TemplateURL* url) {
+ if (default_search_provider_ == url)
+ return;
+
+ DCHECK(!url || find(template_urls_.begin(), template_urls_.end(), url) !=
+ template_urls_.end());
+ default_search_provider_ = url;
+
+ if (url) {
+ TemplateURL* modifiable_url = const_cast<TemplateURL*>(url);
+ // Don't mark the url as edited, otherwise we won't be able to rev the
+ // templateurls we ship with.
+ modifiable_url->set_show_in_default_list(true);
+ if (service_.get())
+ service_.get()->UpdateKeyword(*url);
+
+ const TemplateURLRef* url_ref = url->url();
+ if (url_ref && url_ref->HasGoogleBaseURLs()) {
+ GoogleURLTracker::RequestServerCheck();
+ RLZTracker::RecordProductEvent(RLZTracker::CHROME,
+ RLZTracker::CHROME_OMNIBOX,
+ RLZTracker::SET_TO_GOOGLE);
+ }
+ }
+
+ SaveDefaultSearchProviderToPrefs(url);
+
+ if (service_.get())
+ service_->SetDefaultSearchProvider(url);
+
+ if (loaded_) {
+ FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
+ OnTemplateURLModelChanged());
+ }
+}
+
+const TemplateURL* TemplateURLModel::GetDefaultSearchProvider() {
+ if (loaded_)
+ return default_search_provider_;
+
+ if (!prefs_default_search_provider_.get()) {
+ TemplateURL* default_from_prefs;
+ if (LoadDefaultSearchProviderFromPrefs(&default_from_prefs)) {
+ prefs_default_search_provider_.reset(default_from_prefs);
+ } else {
+ std::vector<TemplateURL*> loaded_urls;
+ size_t default_search_index;
+ TemplateURLPrepopulateData::GetPrepopulatedEngines(GetPrefs(),
+ &loaded_urls,
+ &default_search_index);
+ if (default_search_index < loaded_urls.size()) {
+ prefs_default_search_provider_.reset(loaded_urls[default_search_index]);
+ loaded_urls.erase(loaded_urls.begin() + default_search_index);
+ }
+ STLDeleteElements(&loaded_urls);
+ }
+ }
+
+ return prefs_default_search_provider_.get();
+}
+
+void TemplateURLModel::AddObserver(TemplateURLModelObserver* observer) {
+ model_observers_.AddObserver(observer);
+}
+
+void TemplateURLModel::RemoveObserver(TemplateURLModelObserver* observer) {
+ model_observers_.RemoveObserver(observer);
+}
+
+void TemplateURLModel::Load() {
+ if (loaded_ || load_handle_)
+ return;
+
+ if (!service_.get())
+ service_ = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
+
+ if (service_.get()) {
+ load_handle_ = service_->GetKeywords(this);
+ } else {
+ loaded_ = true;
+ NotifyLoaded();
+ }
+}
+
+void TemplateURLModel::OnWebDataServiceRequestDone(
+ WebDataService::Handle h,
+ const WDTypedResult* result) {
+ // Reset the load_handle so that we don't try and cancel the load in
+ // the destructor.
+ load_handle_ = 0;
+
+ if (!result) {
+ // Results are null if the database went away.
+ loaded_ = true;
+ NotifyLoaded();
+ return;
+ }
+
+ DCHECK(result->GetType() == KEYWORDS_RESULT);
+
+ WDKeywordsResult keyword_result = reinterpret_cast<
+ const WDResult<WDKeywordsResult>*>(result)->GetValue();
+
+ // prefs_default_search_provider_ is only needed before we've finished
+ // loading. Now that we've loaded we can nuke it.
+ prefs_default_search_provider_.reset();
+
+ // Compiler won't implicitly convert std::vector<TemplateURL*> to
+ // std::vector<const TemplateURL*>, and reinterpret_cast is unsafe,
+ // so we just copy it.
+ std::vector<const TemplateURL*> template_urls(keyword_result.keywords.begin(),
+ keyword_result.keywords.end());
+
+ const int resource_keyword_version =
+ TemplateURLPrepopulateData::GetDataVersion();
+ if (keyword_result.builtin_keyword_version != resource_keyword_version) {
+ // There should never be duplicate TemplateURLs. We had a bug such that
+ // duplicate TemplateURLs existed for one locale. As such we invoke
+ // RemoveDuplicatePrepopulateIDs to nuke the duplicates.
+ RemoveDuplicatePrepopulateIDs(&template_urls);
+ }
+ SetTemplateURLs(template_urls);
+
+ if (keyword_result.default_search_provider_id) {
+ // See if we can find the default search provider.
+ for (TemplateURLVector::iterator i = template_urls_.begin();
+ i != template_urls_.end(); ++i) {
+ if ((*i)->id() == keyword_result.default_search_provider_id) {
+ default_search_provider_ = *i;
+ break;
+ }
+ }
+ }
+
+ if (keyword_result.builtin_keyword_version != resource_keyword_version) {
+ MergeEnginesFromPrepopulateData();
+ service_->SetBuiltinKeywordVersion(resource_keyword_version);
+ }
+
+ // Always save the default search provider to prefs. That way we don't have to
+ // worry about it being out of sync.
+ if (default_search_provider_)
+ SaveDefaultSearchProviderToPrefs(default_search_provider_);
+
+ // Delete any hosts that were deleted before we finished loading.
+ for (std::vector<std::wstring>::iterator i = hosts_to_delete_.begin();
+ i != hosts_to_delete_.end(); ++i) {
+ DeleteGeneratedKeywordsMatchingHost(*i);
+ }
+ hosts_to_delete_.clear();
+
+ // Index any visits that occurred before we finished loading.
+ for (size_t i = 0; i < visits_to_add_.size(); ++i)
+ UpdateKeywordSearchTermsForURL(visits_to_add_[i]);
+ visits_to_add_.clear();
+
+ loaded_ = true;
+
+ FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
+ OnTemplateURLModelChanged());
+
+ NotifyLoaded();
+}
+
+void TemplateURLModel::RemoveDuplicatePrepopulateIDs(
+ std::vector<const TemplateURL*>* urls) {
+ std::set<int> ids;
+ for (std::vector<const TemplateURL*>::iterator i = urls->begin();
+ i != urls->end(); ) {
+ int prepopulate_id = (*i)->prepopulate_id();
+ if (prepopulate_id) {
+ if (ids.find(prepopulate_id) != ids.end()) {
+ if (service_.get())
+ service_->RemoveKeyword(**i);
+ delete *i;
+ i = urls->erase(i);
+ } else {
+ ids.insert(prepopulate_id);
+ ++i;
+ }
+ } else {
+ ++i;
+ }
+ }
+}
+
+void TemplateURLModel::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NOTIFY_HISTORY_URL_VISITED) {
+ Details<history::URLVisitedDetails> visit_details(details);
+
+ if (!loaded())
+ visits_to_add_.push_back(visit_details->row);
+ else
+ UpdateKeywordSearchTermsForURL(visit_details->row);
+ } else if (type == NOTIFY_GOOGLE_URL_UPDATED) {
+ if (loaded_)
+ GoogleBaseURLChanged();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void TemplateURLModel::DeleteGeneratedKeywordsMatchingHost(
+ const std::wstring& host) {
+ const std::wstring host_slash = host + L"/";
+ // Iterate backwards as we may end up removing multiple entries.
+ for (int i = static_cast<int>(template_urls_.size()) - 1; i >= 0; --i) {
+ if (CanReplace(template_urls_[i]) &&
+ (template_urls_[i]->keyword() == host ||
+ template_urls_[i]->keyword().compare(0, host_slash.length(),
+ host_slash) == 0)) {
+ Remove(template_urls_[i]);
+ }
+ }
+}
+
+void TemplateURLModel::NotifyLoaded() {
+ NotificationService::current()->
+ Notify(TEMPLATE_URL_MODEL_LOADED, Source<TemplateURLModel>(this),
+ NotificationService::NoDetails());
+}
+
+void TemplateURLModel::MergeEnginesFromPrepopulateData() {
+ // Build a map from prepopulate id to TemplateURL of existing urls.
+ std::map<int, const TemplateURL*> id_to_turl;
+ for (size_t i = 0; i < template_urls_.size(); ++i) {
+ if (template_urls_[i]->prepopulate_id() > 0)
+ id_to_turl[template_urls_[i]->prepopulate_id()] = template_urls_[i];
+ }
+
+ std::vector<TemplateURL*> loaded_urls;
+ size_t default_search_index;
+ TemplateURLPrepopulateData::GetPrepopulatedEngines(GetPrefs(),
+ &loaded_urls,
+ &default_search_index);
+
+ for (size_t i = 0; i < loaded_urls.size(); ++i) {
+ scoped_ptr<TemplateURL> t_url(loaded_urls[i]);
+
+ if (!t_url->prepopulate_id()) {
+ // Prepopulate engines need an id.
+ NOTREACHED();
+ continue;
+ }
+
+ const TemplateURL* existing_url = id_to_turl[t_url->prepopulate_id()];
+ if (existing_url) {
+ if (!existing_url->safe_for_autoreplace()) {
+ // User edited the entry, preserve the keyword and description.
+ loaded_urls[i]->set_safe_for_autoreplace(false);
+ loaded_urls[i]->set_keyword(existing_url->keyword());
+ loaded_urls[i]->set_autogenerate_keyword(
+ existing_url->autogenerate_keyword());
+ loaded_urls[i]->set_short_name(existing_url->short_name());
+ }
+ Replace(existing_url, loaded_urls[i]);
+ id_to_turl[t_url->prepopulate_id()] = loaded_urls[i];
+ } else {
+ Add(loaded_urls[i]);
+ }
+ if (i == default_search_index && !default_search_provider_)
+ SetDefaultSearchProvider(loaded_urls[i]);
+
+ t_url.release();
+ }
+}
+
+void TemplateURLModel::SaveDefaultSearchProviderToPrefs(
+ const TemplateURL* t_url) {
+ PrefService* prefs = GetPrefs();
+ if (!prefs)
+ return;
+
+ RegisterPrefs(prefs);
+
+ const std::wstring search_url =
+ (t_url && t_url->url()) ? t_url->url()->url() : std::wstring();
+ prefs->SetString(prefs::kDefaultSearchProviderSearchURL, search_url);
+
+ const std::wstring suggest_url =
+ (t_url && t_url->suggestions_url()) ? t_url->suggestions_url()->url() :
+ std::wstring();
+ prefs->SetString(prefs::kDefaultSearchProviderSuggestURL, suggest_url);
+
+ const std::wstring name =
+ t_url ? t_url->short_name() : std::wstring();
+ prefs->SetString(prefs::kDefaultSearchProviderName, name);
+
+ const std::wstring id_string =
+ t_url ? Int64ToWString(t_url->id()) : std::wstring();
+ prefs->SetString(prefs::kDefaultSearchProviderID, id_string);
+
+ prefs->ScheduleSavePersistentPrefs(g_browser_process->file_thread());
+}
+
+bool TemplateURLModel::LoadDefaultSearchProviderFromPrefs(
+ TemplateURL** default_provider) {
+ PrefService* prefs = GetPrefs();
+ if (!prefs || !prefs->HasPrefPath(prefs::kDefaultSearchProviderSearchURL) ||
+ !prefs->HasPrefPath(prefs::kDefaultSearchProviderSuggestURL) ||
+ !prefs->HasPrefPath(prefs::kDefaultSearchProviderName) ||
+ !prefs->HasPrefPath(prefs::kDefaultSearchProviderID)) {
+ return false;
+ }
+ RegisterPrefs(prefs);
+
+ std::wstring suggest_url =
+ prefs->GetString(prefs::kDefaultSearchProviderSuggestURL);
+ std::wstring search_url =
+ prefs->GetString(prefs::kDefaultSearchProviderSearchURL);
+
+ if (suggest_url.empty() && search_url.empty()) {
+ // The user doesn't want a default search provider.
+ *default_provider = NULL;
+ return true;
+ }
+
+ std::wstring name = prefs->GetString(prefs::kDefaultSearchProviderName);
+
+ std::wstring id_string = prefs->GetString(prefs::kDefaultSearchProviderID);
+
+ *default_provider = new TemplateURL();
+ (*default_provider)->set_short_name(name);
+ (*default_provider)->SetURL(search_url, 0, 0);
+ (*default_provider)->SetSuggestionsURL(suggest_url, 0, 0);
+ if (!id_string.empty())
+ (*default_provider)->set_id(StringToInt64(id_string));
+ return true;
+}
+
+void TemplateURLModel::RegisterPrefs(PrefService* prefs) {
+ if (prefs->IsPrefRegistered(prefs::kDefaultSearchProviderName))
+ return;
+ prefs->RegisterStringPref(
+ prefs::kDefaultSearchProviderName, std::wstring());
+ prefs->RegisterStringPref(
+ prefs::kDefaultSearchProviderID, std::wstring());
+ prefs->RegisterStringPref(
+ prefs::kDefaultSearchProviderSuggestURL, std::wstring());
+ prefs->RegisterStringPref(
+ prefs::kDefaultSearchProviderSearchURL, std::wstring());
+}
+
+bool TemplateURLModel::CanReplaceKeywordForHost(
+ const std::string& host,
+ const TemplateURL** to_replace) {
+ const HostToURLsMap::iterator matching_urls = host_to_urls_map_.find(host);
+ const bool have_matching_urls = (matching_urls != host_to_urls_map_.end());
+ if (have_matching_urls) {
+ TemplateURLSet& urls = matching_urls->second;
+ for (TemplateURLSet::iterator i = urls.begin(); i != urls.end(); ++i) {
+ const TemplateURL* url = *i;
+ if (CanReplace(url)) {
+ if (to_replace)
+ *to_replace = url;
+ return true;
+ }
+ }
+ }
+
+ if (to_replace)
+ *to_replace = NULL;
+ return !have_matching_urls;
+}
+
+bool TemplateURLModel::CanReplace(const TemplateURL* t_url) {
+ return (t_url != default_search_provider_ && !t_url->show_in_default_list() &&
+ t_url->safe_for_autoreplace());
+}
+
+PrefService* TemplateURLModel::GetPrefs() {
+ return profile_ ? profile_->GetPrefs() : NULL;
+}
+
+void TemplateURLModel::UpdateKeywordSearchTermsForURL(
+ const history::URLRow& row) {
+ if (!row.url().is_valid() ||
+ !row.url().parsed_for_possibly_invalid_spec().query.is_nonempty()) {
+ return;
+ }
+
+ HostToURLsMap::const_iterator t_urls_for_host_iterator =
+ host_to_urls_map_.find(row.url().host());
+ if (t_urls_for_host_iterator == host_to_urls_map_.end() ||
+ t_urls_for_host_iterator->second.empty()) {
+ return;
+ }
+
+ const TemplateURLSet& urls_for_host = t_urls_for_host_iterator->second;
+ QueryTerms query_terms;
+ bool built_terms = false; // Most URLs won't match a TemplateURLs host;
+ // so we lazily build the query_terms.
+ const std::string path = row.url().path();
+
+ for (TemplateURLSet::const_iterator i = urls_for_host.begin();
+ i != urls_for_host.end(); ++i) {
+ const TemplateURLRef* search_ref = (*i)->url();
+
+ // Count the URL against a TemplateURL if the host and path of the
+ // visited URL match that of the TemplateURL as well as the search term's
+ // key of the TemplateURL occurring in the visited url.
+ //
+ // NOTE: Even though we're iterating over TemplateURLs indexed by the host
+ // of the URL we still need to call GetHost on the search_ref. In
+ // particular, GetHost returns an empty string if search_ref doesn't support
+ // replacement or isn't valid for use in keyword search terms.
+
+ if (search_ref && search_ref->GetHost() == row.url().host() &&
+ search_ref->GetPath() == path) {
+ if (!built_terms && !BuildQueryTerms(row.url(), &query_terms)) {
+ // No query terms. No need to continue with the rest of the
+ // TemplateURLs.
+ return;
+ }
+ built_terms = true;
+
+ QueryTerms::iterator terms_iterator =
+ query_terms.find(search_ref->GetSearchTermKey());
+ if (terms_iterator != query_terms.end() &&
+ !terms_iterator->second.empty()) {
+ SetKeywordSearchTermsForURL(
+ *i, row.url(), search_ref->SearchTermToWide(*(*i),
+ terms_iterator->second));
+ }
+ }
+ }
+}
+
+// static
+bool TemplateURLModel::BuildQueryTerms(const GURL& url,
+ QueryTerms* query_terms) {
+ url_parse::Component query = url.parsed_for_possibly_invalid_spec().query;
+ url_parse::Component key, value;
+ size_t valid_term_count = 0;
+ while (url_parse::ExtractQueryKeyValue(url.spec().c_str(), &query, &key,
+ &value)) {
+ if (key.is_nonempty() && value.is_nonempty()) {
+ std::string key_string = url.spec().substr(key.begin, key.len);
+ std::string value_string = url.spec().substr(value.begin, value.len);
+ QueryTerms::iterator query_terms_iterator =
+ query_terms->find(key_string);
+ if (query_terms_iterator != query_terms->end()) {
+ if (!query_terms_iterator->second.empty() &&
+ query_terms_iterator->second != value_string) {
+ // The term occurs in multiple places with different values. Treat
+ // this as if the term doesn't occur by setting the value to an empty
+ // string.
+ (*query_terms)[key_string] = std::string();
+ DCHECK (valid_term_count > 0);
+ valid_term_count--;
+ }
+ } else {
+ valid_term_count++;
+ (*query_terms)[key_string] = value_string;
+ }
+ }
+ }
+ return (valid_term_count > 0);
+}
+
+void TemplateURLModel::GoogleBaseURLChanged() {
+ bool something_changed = false;
+ for (size_t i = 0; i < template_urls_.size(); ++i) {
+ const TemplateURL* t_url = template_urls_[i];
+ if ((t_url->url() && t_url->url()->HasGoogleBaseURLs()) ||
+ (t_url->suggestions_url() &&
+ t_url->suggestions_url()->HasGoogleBaseURLs())) {
+ RemoveFromMapsByPointer(t_url);
+ t_url->InvalidateCachedValues();
+ AddToMaps(t_url);
+ something_changed = true;
+ }
+ }
+
+ if (something_changed && loaded_) {
+ FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
+ OnTemplateURLModelChanged());
+ }
+}
diff --git a/chrome/browser/template_url_model.h b/chrome/browser/template_url_model.h
new file mode 100644
index 0000000..6b9569b
--- /dev/null
+++ b/chrome/browser/template_url_model.h
@@ -0,0 +1,348 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TEMPLATE_URL_MODEL_H__
+#define CHROME_BROWSER_TEMPLATE_URL_MODEL_H__
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/observer_list.h"
+#include "chrome/browser/history/history_notifications.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/common/notification_service.h"
+
+class GURL;
+class PrefService;
+class Profile;
+class TemplateURL;
+class TemplateURLModelTest;
+
+// TemplateURLModel is the backend for keywords. It's used by
+// KeywordAutocomplete.
+//
+// TemplateURLModel stores a vector of TemplateURLs. The TemplateURLs are
+// persisted to the database maintained by WebDataService. *ALL* mutations
+// to the TemplateURLs must funnel through TemplateURLModel. This allows
+// TemplateURLModel to notify listeners of changes as well as keep the
+// database in sync.
+//
+// There is a TemplateURLModel per Profile.
+//
+// TemplateURLModel does not load the vector of TemplateURLs in it's
+// constructor (except for testing). Use the Load method to trigger a load.
+// When TemplateURLModel has completed loading, observers are notified via
+// OnTemplateURLModelChanged as well as the TEMPLATE_URL_MODEL_LOADED
+// notification message.
+//
+// TemplateURLModel takes ownership of any TemplateURL passed to it. If there
+// is a WebDataService, deletion is handled by WebDataService, otherwise
+// TemplateURLModel handles deletion.
+
+// TemplateURLModelObserver is notified whenever the set of TemplateURLs
+// are modified.
+class TemplateURLModelObserver {
+ public:
+ // Notification that the template url model has changed in some way.
+ virtual void OnTemplateURLModelChanged() = 0;
+};
+
+class TemplateURLModel : public WebDataServiceConsumer,
+ public NotificationObserver {
+ public:
+ typedef std::map<std::string, std::string> QueryTerms;
+
+ // Struct used for initializing the data store with fake data.
+ // Each initializer is mapped to a TemplateURL.
+ struct Initializer {
+ const wchar_t* const keyword;
+ const wchar_t* const url;
+ const wchar_t* const content;
+ };
+
+ explicit TemplateURLModel(Profile* profile);
+ // The following is for testing.
+ TemplateURLModel(const Initializer* initializers, const int count);
+
+ ~TemplateURLModel();
+
+ // Generates a suitable keyword for the specified url. Returns an empty
+ // string if a keyword couldn't be generated. If |autodetected| is true, we
+ // don't generate keywords for a variety of situations where we would probably
+ // not want to auto-add keywords, such as keywords for searches on pages that
+ // themselves come from form submissions.
+ static std::wstring GenerateKeyword(const GURL& url, bool autodetected);
+
+ // Removes any unnecessary characters from a user input keyword.
+ // This removes the leading scheme, "www." and any trailing slash.
+ static std::wstring CleanUserInputKeyword(const std::wstring& keyword);
+
+ // Returns the search url for t_url. Returns an empty GURL if t_url has no
+ // url().
+ static GURL GenerateSearchURL(const TemplateURL* t_url);
+
+ // Returns true if there is no TemplateURL that conflicts with the
+ // keyword/url pair, or there is one but it can be replaced. If there is an
+ // existing keyword that can be replaced and template_url_to_replace is
+ // non-NULL, template_url_to_replace is set to the keyword to replace.
+ //
+ // url gives the url of the search query. The url is used to avoid generating
+ // a TemplateURL for an existing TemplateURL that shares the same host.
+ bool CanReplaceKeyword(const std::wstring& keyword,
+ const std::wstring& url,
+ const TemplateURL** template_url_to_replace);
+
+ // Returns (in |matches|) all keywords beginning with |prefix|, sorted
+ // shortest-first. If support_replacement_only is true, only keywords that
+ // support replacement are returned.
+ void FindMatchingKeywords(const std::wstring& prefix,
+ bool support_replacement_only,
+ std::vector<std::wstring>* matches) const;
+
+ // Looks up |keyword| and returns the element it maps to. Returns NULL if
+ // the keyword was not found.
+ // The caller should not try to delete the returned pointer; the data store
+ // retains ownership of it.
+ const TemplateURL* GetTemplateURLForKeyword(
+ const std::wstring& keyword) const;
+
+ // Returns the first TemplateURL found with a URL using the specified |host|,
+ // or NULL if there are no such TemplateURLs
+ const TemplateURL* GetTemplateURLForHost(const std::string& host) const;
+
+ // Adds a new TemplateURL to this model. TemplateURLModel will own the
+ // reference, and delete it when the TemplateURL is removed.
+ void Add(TemplateURL* template_url);
+
+ // Removes the keyword from the model. This deletes the supplied TemplateURL.
+ // This fails if the supplied template_url is the default search provider.
+ void Remove(const TemplateURL* template_url);
+
+ // Removes all auto-generated keywords that were created in the specified
+ // range.
+ void RemoveAutoGeneratedBetween(base::Time created_after, base::Time created_before);
+
+ // Replaces existing_turl with new_turl. new_turl is given the same ID as
+ // existing_turl. If existing_turl was the default, new_turl is made the
+ // default. After this call existing_turl is deleted. As with Add,
+ // TemplateURLModel takes ownership of existing_turl.
+ void Replace(const TemplateURL* existing_turl,
+ TemplateURL* new_turl);
+
+ // Removes all auto-generated keywords that were created on or after the
+ // date passed in.
+ void RemoveAutoGeneratedSince(base::Time created_after);
+
+ // Returns the set of URLs describing the keywords. The elements are owned
+ // by TemplateURLModel and should not be deleted.
+ std::vector<const TemplateURL*> GetTemplateURLs() const;
+
+ // Increment the usage count of a keyword.
+ // Called when a URL is loaded that was generated from a keyword.
+ void IncrementUsageCount(const TemplateURL* url);
+
+ // Resets the title, keyword and search url of the specified TemplateURL.
+ // The TemplateURL is marked as not replaceable.
+ void ResetTemplateURL(const TemplateURL* url,
+ const std::wstring& title,
+ const std::wstring& keyword,
+ const std::wstring& search_url);
+
+ // The default search provider. This may be null.
+ void SetDefaultSearchProvider(const TemplateURL* url);
+
+ // Returns the default search provider. If the TemplateURLModel hasn't been
+ // loaded, the default search provider is pulled from preferences.
+ //
+ // NOTE: At least in unittest mode, this may return NULL.
+ const TemplateURL* GetDefaultSearchProvider();
+
+ // Observers used to listen for changes to the model.
+ // TemplateURLModel does NOT delete the observers when deleted.
+ void AddObserver(TemplateURLModelObserver* observer);
+ void RemoveObserver(TemplateURLModelObserver* observer);
+
+ // Loads the keywords. This has no effect if the keywords have already been
+ // loaded.
+ // Observers are notified when loading completes via the method
+ // OnTemplateURLsReset.
+ void Load();
+
+ // Whether or not the keywords have been loaded.
+ bool loaded() { return loaded_; }
+
+ // Notification that the keywords have been loaded.
+ // This is invoked from WebDataService, and should not be directly
+ // invoked.
+ virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
+ const WDTypedResult* result);
+
+ // Removes (and deletes) TemplateURLs from |urls| that have duplicate
+ // prepopulate ids. Duplicate prepopulate ids are not allowed, but due to a
+ // bug it was possible get dups. This step is only called when the version
+ // number changes.
+ void RemoveDuplicatePrepopulateIDs(std::vector<const TemplateURL*>* urls);
+
+ // NotificationObserver method. TemplateURLModel listens for three
+ // notification types:
+ // . NOTIFY_HISTORY_URL_VISITED: adds keyword search terms if the visit
+ // corresponds to a keyword.
+ // . NOTIFY_GOOGLE_URL_UPDATED: updates mapping for any keywords containing
+ // a google base url replacement term.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ Profile* profile() const { return profile_; }
+
+ protected:
+ // Cover method for the method of the same name on the HistoryService.
+ // url is the one that was visited with the given search terms.
+ //
+ // This exists and is virtual for testing.
+ virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
+ const GURL& url,
+ const std::wstring& term);
+
+ private:
+ FRIEND_TEST(TemplateURLModelTest, BuildQueryTerms);
+ FRIEND_TEST(TemplateURLModelTest, UpdateKeywordSearchTermsForURL);
+ FRIEND_TEST(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable);
+ FRIEND_TEST(TemplateURLModelTest, ChangeGoogleBaseValue);
+ friend class TemplateURLModelTest;
+
+ typedef std::map<std::wstring, const TemplateURL*> KeywordToTemplateMap;
+ typedef std::vector<const TemplateURL*> TemplateURLVector;
+
+ // Helper functor for FindMatchingKeywords(), for finding the range of
+ // keywords which begin with a prefix.
+ class LessWithPrefix;
+
+ void Init(const Initializer* initializers, int num_initializers);
+
+ void RemoveFromMaps(const TemplateURL* template_url);
+
+ // Removes the supplied template_url from the maps. This searches through all
+ // entries in the maps and does not generate the host or keyword.
+ // This is used when the cached content of the TemplateURL changes.
+ void RemoveFromMapsByPointer(const TemplateURL* template_url);
+
+ void AddToMaps(const TemplateURL* template_url);
+
+ // Sets the keywords. This is used once the keywords have been loaded.
+ // This does NOT notify the delegate or the database.
+ void SetTemplateURLs(const std::vector<const TemplateURL*>& urls);
+
+ void DeleteGeneratedKeywordsMatchingHost(const std::wstring& host);
+
+ // If there is a notification service, sends TEMPLATE_URL_MODEL_LOADED
+ // notification.
+ void NotifyLoaded();
+
+ // Loads engines from prepopulate data and merges them in with the existing
+ // engines. This is invoked when the version of the prepopulate data changes.
+ void MergeEnginesFromPrepopulateData();
+
+ // Saves enough of url to preferences so that it can be loaded from
+ // preferences on start up.
+ void SaveDefaultSearchProviderToPrefs(const TemplateURL* url);
+
+ // Creates a TemplateURL that was previously saved to prefs via
+ // SaveDefaultSearchProviderToPrefs. Returns true if successful, false
+ // otherwise. This is used if GetDefaultSearchProvider is invoked before the
+ // TemplateURL has loaded. If the user has opted for no default search, this
+ // returns true but default_provider is set to NULL.
+ bool LoadDefaultSearchProviderFromPrefs(TemplateURL** default_provider);
+
+ // Registers the preferences used to save a TemplateURL to prefs.
+ void RegisterPrefs(PrefService* prefs);
+
+ // Returns true if there is no TemplateURL that has a search url with the
+ // specified host, or the only TemplateURLs matching the specified host can
+ // be replaced.
+ bool CanReplaceKeywordForHost(const std::string& host,
+ const TemplateURL** to_replace);
+
+ // Returns true if the TemplateURL is replaceable. This doesn't look at the
+ // uniqueness of the keyword or host and is intended to be called after those
+ // checks have been done. This returns true if the TemplateURL doesn't appear
+ // in the default list and is marked as safe_for_autoreplace.
+ bool CanReplace(const TemplateURL* t_url);
+
+ // Returns the preferences we use.
+ PrefService* GetPrefs();
+
+ // Iterates through the TemplateURLs to see if one matches the visited url.
+ // For each TemplateURL whose url matches the visited url
+ // SetKeywordSearchTermsForURL is invoked.
+ void UpdateKeywordSearchTermsForURL(const history::URLRow& row);
+
+ // Adds each of the query terms in the specified url whose key and value are
+ // non-empty to query_terms. If a query key appears multiple times, the value
+ // is set to an empty string. Returns true if there is at least one key that
+ // does not occur multiple times.
+ static bool BuildQueryTerms(
+ const GURL& url,
+ std::map<std::string,std::string>* query_terms);
+
+ // Invoked when the Google base URL has changed. Updates the mapping for all
+ // TemplateURLs that have a replacement term of {google:baseURL} or
+ // {google:baseSuggestURL}.
+ void GoogleBaseURLChanged();
+
+ // Mapping from keyword to the TemplateURL.
+ KeywordToTemplateMap keyword_to_template_map_;
+
+ TemplateURLVector template_urls_;
+
+ ObserverList<TemplateURLModelObserver> model_observers_;
+
+ // Maps from host to set of TemplateURLs whose search url host is host.
+ typedef std::set<const TemplateURL*> TemplateURLSet;
+ typedef std::map<std::string, TemplateURLSet> HostToURLsMap;
+ HostToURLsMap host_to_urls_map_;
+
+ // Used to obtain the WebDataService.
+ // When Load is invoked, if we haven't yet loaded, the WebDataService is
+ // obtained from the Profile. This allows us to lazily access the database.
+ Profile* profile_;
+
+ // Whether the keywords have been loaded.
+ bool loaded_;
+
+ // If non-zero, we're waiting on a load.
+ WebDataService::Handle load_handle_;
+
+ // Service used to store entries.
+ scoped_refptr<WebDataService> service_;
+
+ // List of hosts to feed to DeleteGeneratedKeywordsMatchingHost. When
+ // we receive NOTIFY_HOST_DELETED_FROM_HISTORY if we haven't loaded yet,
+ // we force a load and add the host to hosts_to_delete_. When done loading
+ // we invoke DeleteGeneratedKeywordsMatchingHost with all the elements of
+ // the vector.
+ std::vector<std::wstring> hosts_to_delete_;
+
+ // All visits that occurred before we finished loading. Once loaded
+ // UpdateKeywordSearchTermsForURL is invoked for each element of the vector.
+ std::vector<history::URLRow> visits_to_add_;
+
+ const TemplateURL* default_search_provider_;
+
+ // The default search provider from preferences. This is only valid if
+ // GetDefaultSearchProvider is invoked and we haven't been loaded. Once loaded
+ // this is not used.
+ scoped_ptr<TemplateURL> prefs_default_search_provider_;
+
+ // ID assigned to next TemplateURL added to this model. This is an ever
+ // increasing integer that is initialized from the database.
+ TemplateURL::IDType next_id_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TemplateURLModel);
+};
+
+#endif // CHROME_BROWSER_TEMPLATE_URL_MODEL_H__
+
diff --git a/chrome/browser/template_url_model_unittest.cc b/chrome/browser/template_url_model_unittest.cc
new file mode 100644
index 0000000..b5198e4
--- /dev/null
+++ b/chrome/browser/template_url_model_unittest.cc
@@ -0,0 +1,633 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/test/testing_profile.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+
+// A Task used to coordinate when the database has finished processing
+// requests. See note in BlockTillServiceProcessesRequests for details.
+//
+// When Run() schedules a QuitTask on the message loop it was created with.
+class QuitTask2 : public Task {
+ public:
+ QuitTask2() : main_loop_(MessageLoop::current()) {}
+
+ virtual void Run() {
+ main_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ }
+
+ private:
+ MessageLoop* main_loop_;
+};
+
+// Subclass the TestingProfile so that it can return a WebDataService.
+class TemplateURLModelTestingProfile : public TestingProfile {
+ public:
+ TemplateURLModelTestingProfile() : TestingProfile() { }
+
+ void SetUp() {
+ // Name a subdirectory of the temp directory.
+ ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
+ file_util::AppendToPath(&test_dir_, L"TemplateURLModelTest");
+
+ // Create a fresh, empty copy of this directory.
+ file_util::Delete(test_dir_, true);
+ file_util::CreateDirectory(test_dir_);
+
+ std::wstring path = test_dir_;
+ file_util::AppendToPath(&path, L"TestDataService.db");
+ service_ = new WebDataService;
+ EXPECT_TRUE(service_->InitWithPath(path));
+ }
+
+ void TearDown() {
+ // Clean up the test directory.
+ service_->Shutdown();
+ ASSERT_TRUE(file_util::Delete(test_dir_, true));
+ ASSERT_FALSE(file_util::PathExists(test_dir_));
+ }
+
+ virtual WebDataService* GetWebDataService(ServiceAccessType access) {
+ return service_.get();
+ }
+
+ private:
+ scoped_refptr<WebDataService> service_;
+ std::wstring test_dir_;
+};
+
+// Trivial subclass of TemplateURLModel that records the last invocation of
+// SetKeywordSearchTermsForURL.
+class TestingTemplateURLModel : public TemplateURLModel {
+ public:
+ explicit TestingTemplateURLModel(Profile* profile)
+ : TemplateURLModel(profile) {
+ }
+
+ std::wstring GetAndClearSearchTerm() {
+ std::wstring search_term;
+ search_term.swap(search_term_);
+ return search_term;
+ }
+
+ protected:
+ virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
+ const GURL& url,
+ const std::wstring& term) {
+ search_term_ = term;
+ }
+
+ private:
+ std::wstring search_term_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TestingTemplateURLModel);
+};
+
+class TemplateURLModelTest : public testing::Test,
+ public TemplateURLModelObserver {
+ public:
+ TemplateURLModelTest() : changed_count_(0) {
+ }
+
+ virtual void SetUp() {
+ profile_.reset(new TemplateURLModelTestingProfile());
+ profile_->SetUp();
+ model_.reset(new TestingTemplateURLModel(profile_.get()));
+ model_->AddObserver(this);
+ }
+
+ virtual void TearDown() {
+ profile_->TearDown();
+ delete TemplateURLRef::google_base_url_;
+ TemplateURLRef::google_base_url_ = NULL;
+
+ // Flush the message loop to make Purify happy.
+ message_loop_.RunAllPending();
+ }
+
+ TemplateURL* AddKeywordWithDate(const std::wstring& keyword,
+ bool autogenerate_keyword,
+ const std::wstring& url,
+ const std::wstring& short_name,
+ bool safe_for_autoreplace,
+ Time created_date) {
+ TemplateURL* template_url = new TemplateURL();
+ template_url->SetURL(url, 0, 0);
+ template_url->set_keyword(keyword);
+ template_url->set_autogenerate_keyword(autogenerate_keyword);
+ template_url->set_short_name(short_name);
+ template_url->set_date_created(created_date);
+ template_url->set_safe_for_autoreplace(safe_for_autoreplace);
+ model_->Add(template_url);
+ EXPECT_NE(0, template_url->id());
+ return template_url;
+ }
+
+ virtual void OnTemplateURLModelChanged() {
+ changed_count_++;
+ }
+
+ void VerifyObserverCount(int expected_changed_count) {
+ ASSERT_EQ(expected_changed_count, changed_count_);
+ changed_count_ = 0;
+ }
+
+ // Blocks the caller until the service has finished servicing all pending
+ // requests.
+ void BlockTillServiceProcessesRequests() {
+ // Schedule a task on the background thread that is processed after all
+ // pending requests on the background thread.
+ profile_->GetWebDataService(Profile::EXPLICIT_ACCESS)->thread()->
+ message_loop()->PostTask(FROM_HERE, new QuitTask2());
+ // Run the current message loop. QuitTask2, when run, invokes Quit,
+ // which unblocks this.
+ MessageLoop::current()->Run();
+ }
+
+ // Makes sure the load was successful and sent the correct notification.
+ void VerifyLoad() {
+ ASSERT_FALSE(model_->loaded());
+ model_->Load();
+ BlockTillServiceProcessesRequests();
+ VerifyObserverCount(1);
+ changed_count_ = 0;
+ }
+
+ // Creates a new TemplateURLModel.
+ void ResetModel(bool verify_load) {
+ model_.reset(new TestingTemplateURLModel(profile_.get()));
+ model_->AddObserver(this);
+ changed_count_ = 0;
+ if (verify_load)
+ VerifyLoad();
+ }
+
+ // Verifies the two TemplateURLs are equal.
+ void AssertEquals(const TemplateURL& expected, const TemplateURL& actual) {
+ ASSERT_EQ(expected.url()->url(), actual.url()->url());
+ ASSERT_EQ(expected.keyword(), actual.keyword());
+ ASSERT_EQ(expected.short_name(), actual.short_name());
+ ASSERT_TRUE(expected.GetFavIconURL() == actual.GetFavIconURL());
+ ASSERT_EQ(expected.id(), actual.id());
+ ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace());
+ ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list());
+ ASSERT_TRUE(expected.date_created() == actual.date_created());
+ }
+
+ std::wstring GetAndClearSearchTerm() {
+ return model_->GetAndClearSearchTerm();
+ }
+
+ void SetGoogleBaseURL(const std::wstring& base_url) const {
+ delete TemplateURLRef::google_base_url_;
+ TemplateURLRef::google_base_url_ = new std::wstring(base_url);
+ }
+
+ MessageLoopForUI message_loop_;
+ scoped_ptr<TemplateURLModelTestingProfile> profile_;
+ scoped_ptr<TestingTemplateURLModel> model_;
+ int changed_count_;
+};
+
+TEST_F(TemplateURLModelTest, Load) {
+ VerifyLoad();
+}
+
+TEST_F(TemplateURLModelTest, AddUpdateRemove) {
+ // Add a new TemplateURL.
+ VerifyLoad();
+ const size_t initial_count = model_->GetTemplateURLs().size();
+
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL(L"http://www.google.com/foo/bar", 0, 0);
+ t_url->set_keyword(L"keyword");
+ t_url->set_short_name(L"google");
+ GURL favicon_url("http://favicon.url");
+ t_url->SetFavIconURL(favicon_url);
+ t_url->set_date_created(Time::FromTimeT(100));
+ t_url->set_safe_for_autoreplace(true);
+ model_->Add(t_url);
+ ASSERT_TRUE(model_->CanReplaceKeyword(L"keyword", std::wstring(), NULL));
+ VerifyObserverCount(1);
+ BlockTillServiceProcessesRequests();
+ // We need to clone as model takes ownership of TemplateURL and will
+ // delete it.
+ TemplateURL cloned_url(*t_url);
+ ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
+ ASSERT_TRUE(model_->GetTemplateURLForKeyword(t_url->keyword()) == t_url);
+ ASSERT_TRUE(t_url->date_created() == cloned_url.date_created());
+
+ // Reload the model to verify it was actually saved to the database.
+ ResetModel(true);
+ ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
+ const TemplateURL* loaded_url = model_->GetTemplateURLForKeyword(L"keyword");
+ ASSERT_TRUE(loaded_url != NULL);
+ AssertEquals(cloned_url, *loaded_url);
+ ASSERT_TRUE(model_->CanReplaceKeyword(L"keyword", std::wstring(), NULL));
+
+ // Mutate an element and verify it succeeded.
+ model_->ResetTemplateURL(loaded_url, L"a", L"b", L"c");
+ ASSERT_EQ(L"a", loaded_url->short_name());
+ ASSERT_EQ(L"b", loaded_url->keyword());
+ ASSERT_EQ(L"c", loaded_url->url()->url());
+ ASSERT_FALSE(loaded_url->safe_for_autoreplace());
+ ASSERT_TRUE(model_->CanReplaceKeyword(L"keyword", std::wstring(), NULL));
+ ASSERT_FALSE(model_->CanReplaceKeyword(L"b", std::wstring(), NULL));
+ cloned_url = *loaded_url;
+ BlockTillServiceProcessesRequests();
+ ResetModel(true);
+ ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
+ loaded_url = model_->GetTemplateURLForKeyword(L"b");
+ ASSERT_TRUE(loaded_url != NULL);
+ AssertEquals(cloned_url, *loaded_url);
+
+ // Remove an element and verify it succeeded.
+ model_->Remove(loaded_url);
+ VerifyObserverCount(1);
+ ResetModel(true);
+ ASSERT_EQ(initial_count, model_->GetTemplateURLs().size());
+ EXPECT_TRUE(model_->GetTemplateURLForKeyword(L"b") == NULL);
+}
+
+TEST_F(TemplateURLModelTest, GenerateKeyword) {
+ ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL(), true));
+ // Shouldn't generate keywords for https.
+ ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL("https://blah"), true));
+ ASSERT_EQ(L"foo", TemplateURLModel::GenerateKeyword(GURL("http://foo"),
+ true));
+ // www. should be stripped.
+ ASSERT_EQ(L"foo", TemplateURLModel::GenerateKeyword(GURL("http://www.foo"),
+ true));
+ // Shouldn't generate keywords with paths, if autodetected.
+ ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"),
+ true));
+ ASSERT_EQ(L"blah", TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"),
+ false));
+ // FTP shouldn't generate a keyword.
+ ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL("ftp://blah/"), true));
+ // Make sure we don't get a trailing /
+ ASSERT_EQ(L"blah", TemplateURLModel::GenerateKeyword(GURL("http://blah/"),
+ true));
+}
+
+TEST_F(TemplateURLModelTest, ClearBrowsingData_Keywords) {
+ Time now = Time::Now();
+ TimeDelta one_day = TimeDelta::FromDays(1);
+ Time month_ago = now - TimeDelta::FromDays(30);
+
+ // Nothing has been added.
+ EXPECT_EQ(0U, model_->GetTemplateURLs().size());
+
+ // Create one with a 0 time.
+ AddKeywordWithDate(L"key1", false, L"http://foo1", L"name1", true, Time());
+ // Create one for now and +/- 1 day.
+ AddKeywordWithDate(L"key2", false, L"http://foo2", L"name2", true,
+ now - one_day);
+ AddKeywordWithDate(L"key3", false, L"http://foo3", L"name3", true, now);
+ AddKeywordWithDate(L"key4", false, L"http://foo4", L"name4", true,
+ now + one_day);
+ // Try the other three states.
+ AddKeywordWithDate(L"key5", false, L"http://foo5", L"name5", false, now);
+ AddKeywordWithDate(L"key6", false, L"http://foo6", L"name6", false, month_ago);
+
+ // We just added a few items, validate them.
+ EXPECT_EQ(6U, model_->GetTemplateURLs().size());
+
+ // Try removing from current timestamp. This should delete the one in the
+ // future and one very recent one.
+ model_->RemoveAutoGeneratedSince(now);
+ EXPECT_EQ(4U, model_->GetTemplateURLs().size());
+
+ // Try removing from two months ago. This should only delete items that are
+ // auto-generated.
+ model_->RemoveAutoGeneratedSince(now - TimeDelta::FromDays(60));
+ EXPECT_EQ(3U, model_->GetTemplateURLs().size());
+
+ // Make sure the right values remain.
+ EXPECT_EQ(L"key1", model_->GetTemplateURLs()[0]->keyword());
+ EXPECT_TRUE(model_->GetTemplateURLs()[0]->safe_for_autoreplace());
+ EXPECT_EQ(0U, model_->GetTemplateURLs()[0]->date_created().ToInternalValue());
+
+ EXPECT_EQ(L"key5", model_->GetTemplateURLs()[1]->keyword());
+ EXPECT_FALSE(model_->GetTemplateURLs()[1]->safe_for_autoreplace());
+ EXPECT_EQ(now.ToInternalValue(),
+ model_->GetTemplateURLs()[1]->date_created().ToInternalValue());
+
+ EXPECT_EQ(L"key6", model_->GetTemplateURLs()[2]->keyword());
+ EXPECT_FALSE(model_->GetTemplateURLs()[2]->safe_for_autoreplace());
+ EXPECT_EQ(month_ago.ToInternalValue(),
+ model_->GetTemplateURLs()[2]->date_created().ToInternalValue());
+
+ // Try removing from Time=0. This should delete one more.
+ model_->RemoveAutoGeneratedSince(Time());
+ EXPECT_EQ(2U, model_->GetTemplateURLs().size());
+}
+
+TEST_F(TemplateURLModelTest, Reset) {
+ // Add a new TemplateURL.
+ VerifyLoad();
+ const size_t initial_count = model_->GetTemplateURLs().size();
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL(L"http://www.google.com/foo/bar", 0, 0);
+ t_url->set_keyword(L"keyword");
+ t_url->set_short_name(L"google");
+ GURL favicon_url("http://favicon.url");
+ t_url->SetFavIconURL(favicon_url);
+ t_url->set_date_created(Time::FromTimeT(100));
+ model_->Add(t_url);
+
+ VerifyObserverCount(1);
+ BlockTillServiceProcessesRequests();
+
+ // Reset the short name, keyword, url and make sure it takes.
+ const std::wstring new_short_name(L"a");
+ const std::wstring new_keyword(L"b");
+ const std::wstring new_url(L"c");
+ model_->ResetTemplateURL(t_url, new_short_name, new_keyword, new_url);
+ ASSERT_EQ(new_short_name, t_url->short_name());
+ ASSERT_EQ(new_keyword, t_url->keyword());
+ ASSERT_EQ(new_url, t_url->url()->url());
+
+ // Make sure the mappings in the model were updated.
+ ASSERT_TRUE(model_->GetTemplateURLForKeyword(new_keyword) == t_url);
+ ASSERT_TRUE(model_->GetTemplateURLForKeyword(L"keyword") == NULL);
+
+ TemplateURL last_url = *t_url;
+
+ // Reload the model from the database and make sure the change took.
+ ResetModel(true);
+ t_url = NULL;
+ EXPECT_EQ(initial_count + 1, model_->GetTemplateURLs().size());
+ const TemplateURL* read_url = model_->GetTemplateURLForKeyword(new_keyword);
+ ASSERT_TRUE(read_url);
+ AssertEquals(last_url, *read_url);
+}
+
+TEST_F(TemplateURLModelTest, DefaultSearchProvider) {
+ // Add a new TemplateURL.
+ VerifyLoad();
+ const size_t initial_count = model_->GetTemplateURLs().size();
+ TemplateURL* t_url = AddKeywordWithDate(L"key1", false, L"http://foo1",
+ L"name1", true, Time());
+
+ changed_count_ = 0;
+ model_->SetDefaultSearchProvider(t_url);
+
+ ASSERT_EQ(t_url, model_->GetDefaultSearchProvider());
+
+ ASSERT_TRUE(t_url->safe_for_autoreplace());
+ ASSERT_TRUE(t_url->show_in_default_list());
+
+ // Setting the default search provider should have caused notification.
+ VerifyObserverCount(1);
+
+ BlockTillServiceProcessesRequests();
+
+ TemplateURL cloned_url = *t_url;
+
+ ResetModel(true);
+ t_url = NULL;
+
+ // Make sure when we reload we get a default search provider.
+ EXPECT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
+ ASSERT_TRUE(model_->GetDefaultSearchProvider());
+ AssertEquals(cloned_url, *model_->GetDefaultSearchProvider());
+}
+
+TEST_F(TemplateURLModelTest, TemplateURLWithNoKeyword) {
+ VerifyLoad();
+
+ const size_t initial_count = model_->GetTemplateURLs().size();
+
+ AddKeywordWithDate(std::wstring(), false, L"http://foo1", L"name1", true,
+ Time());
+
+ // We just added a few items, validate them.
+ ASSERT_EQ(initial_count + 1, model_->GetTemplateURLs().size());
+
+ // Reload the model from the database and make sure we get the url back.
+ ResetModel(true);
+
+ ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
+
+ bool found_keyword = false;
+ for (size_t i = 0; i < initial_count + 1; ++i) {
+ if (model_->GetTemplateURLs()[i]->keyword().empty()) {
+ found_keyword = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(found_keyword);
+}
+
+TEST_F(TemplateURLModelTest, CantReplaceWithSameKeyword) {
+ ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", std::wstring(), NULL));
+ TemplateURL* t_url = AddKeywordWithDate(L"foo", false, L"http://foo1",
+ L"name1", true, Time());
+
+ // Can still replace, newly added template url is marked safe to replace.
+ ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", L"http://foo2", NULL));
+
+ // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
+ // no longer be replaceable.
+ model_->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
+ t_url->url()->url());
+
+ ASSERT_FALSE(model_->CanReplaceKeyword(L"foo", L"http://foo2", NULL));
+}
+
+TEST_F(TemplateURLModelTest, CantReplaceWithSameHosts) {
+ ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", L"http://foo.com", NULL));
+ TemplateURL* t_url = AddKeywordWithDate(L"foo", false, L"http://foo.com",
+ L"name1", true, Time());
+
+ // Can still replace, newly added template url is marked safe to replace.
+ ASSERT_TRUE(model_->CanReplaceKeyword(L"bar", L"http://foo.com", NULL));
+
+ // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
+ // no longer be replaceable.
+ model_->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
+ t_url->url()->url());
+
+ ASSERT_FALSE(model_->CanReplaceKeyword(L"bar", L"http://foo.com", NULL));
+}
+
+TEST_F(TemplateURLModelTest, HasDefaultSearchProvider) {
+ // We should have a default search provider even if we haven't loaded.
+ ASSERT_TRUE(model_->GetDefaultSearchProvider());
+
+ // Now force the model to load and make sure we still have a default.
+ VerifyLoad();
+
+ ASSERT_TRUE(model_->GetDefaultSearchProvider());
+}
+
+TEST_F(TemplateURLModelTest, DefaultSearchProviderLoadedFromPrefs) {
+ VerifyLoad();
+
+ TemplateURL* template_url = new TemplateURL();
+ template_url->SetURL(L"http://url", 0, 0);
+ template_url->SetSuggestionsURL(L"http://url2", 0, 0);
+ template_url->set_short_name(L"a");
+ template_url->set_safe_for_autoreplace(true);
+ template_url->set_date_created(Time::FromTimeT(100));
+
+ model_->Add(template_url);
+
+ const TemplateURL::IDType id = template_url->id();
+
+ model_->SetDefaultSearchProvider(template_url);
+
+ BlockTillServiceProcessesRequests();
+
+ TemplateURL first_default_search_provider = *template_url;
+
+ template_url = NULL;
+
+ // Reset the model and don't load it. The template url we set as the default
+ // should be pulled from prefs now.
+ ResetModel(false);
+
+ // NOTE: This doesn't use AssertEquals as only a subset of the TemplateURLs
+ // value are persisted to prefs.
+ const TemplateURL* default_turl = model_->GetDefaultSearchProvider();
+ ASSERT_TRUE(default_turl);
+ ASSERT_TRUE(default_turl->url());
+ ASSERT_EQ(L"http://url", default_turl->url()->url());
+ ASSERT_TRUE(default_turl->suggestions_url());
+ ASSERT_EQ(L"http://url2", default_turl->suggestions_url()->url());
+ ASSERT_EQ(L"a", default_turl->short_name());
+ ASSERT_EQ(id, default_turl->id());
+
+ // Now do a load and make sure the default search provider really takes.
+ VerifyLoad();
+
+ ASSERT_TRUE(model_->GetDefaultSearchProvider());
+ AssertEquals(first_default_search_provider,
+ *model_->GetDefaultSearchProvider());
+}
+
+TEST_F(TemplateURLModelTest, BuildQueryTerms) {
+ struct TestData {
+ const std::string url;
+ const bool result;
+ // Keys and values are a semicolon separated list of expected values in the
+ // map.
+ const std::string keys;
+ const std::string values;
+ } data[] = {
+ // No query should return false.
+ { "http://blah/", false, "", "" },
+
+ // Query with empty key should return false.
+ { "http://blah/foo?=y", false, "", "" },
+
+ // Query with key occurring multiple times should return false.
+ { "http://blah/foo?x=y&x=z", false, "", "" },
+
+ { "http://blah/foo?x=y", true, "x", "y" },
+ { "http://blah/foo?x=y&y=z", true, "x;y", "y;z" },
+
+ // Key occurring multiple times should get an empty string.
+ { "http://blah/foo?x=y&x=z&y=z", true, "x;y", ";z" },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
+ TemplateURLModel::QueryTerms terms;
+ ASSERT_EQ(data[i].result,
+ TemplateURLModel::BuildQueryTerms(GURL(data[i].url), &terms));
+ if (data[i].result) {
+ std::vector<std::string> keys;
+ std::vector<std::string> values;
+ SplitString(data[i].keys, ';', &keys);
+ SplitString(data[i].values, ';', &values);
+ ASSERT_TRUE(keys.size() == values.size());
+ ASSERT_EQ(keys.size(), terms.size());
+ for (size_t j = 0; j < keys.size(); ++j) {
+ TemplateURLModel::QueryTerms::iterator term_iterator =
+ terms.find(keys[j]);
+ ASSERT_TRUE(term_iterator != terms.end());
+ ASSERT_EQ(values[j], term_iterator->second);
+ }
+ }
+ }
+}
+
+TEST_F(TemplateURLModelTest, UpdateKeywordSearchTermsForURL) {
+ struct TestData {
+ const std::string url;
+ const std::wstring term;
+ } data[] = {
+ { "http://foo/", L"" },
+ { "http://foo/foo?q=xx", L"" },
+ { "http://x/bar?q=xx", L"" },
+ { "http://x/foo?y=xx", L"" },
+ { "http://x/foo?q=xx", L"xx" },
+ { "http://x/foo?a=b&q=xx", L"xx" },
+ { "http://x/foo?q=b&q=xx", L"" },
+ };
+
+ AddKeywordWithDate(L"x", false, L"http://x/foo?q={searchTerms}", L"name",
+ false, Time());
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
+ model_->UpdateKeywordSearchTermsForURL(history::URLRow(GURL(data[i].url)));
+ EXPECT_EQ(data[i].term, GetAndClearSearchTerm());
+ }
+}
+
+TEST_F(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable) {
+ struct TestData {
+ const std::string url;
+ } data[] = {
+ { "http://foo/" },
+ { "http://x/bar?q=xx" },
+ { "http://x/foo?y=xx" },
+ };
+
+ AddKeywordWithDate(L"x", false, L"http://x/foo", L"name", false, Time());
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
+ model_->UpdateKeywordSearchTermsForURL(history::URLRow(GURL(data[i].url)));
+ ASSERT_EQ(std::wstring(), GetAndClearSearchTerm());
+ }
+}
+
+TEST_F(TemplateURLModelTest, ChangeGoogleBaseValue) {
+ // NOTE: Do not do a VerifyLoad() here as it will load the prepopulate data,
+ // which also has a {google:baseURL} keyword in it, which will confuse this
+ // test.
+ SetGoogleBaseURL(L"http://google.com/");
+ const TemplateURL* t_url = AddKeywordWithDate(std::wstring(), true,
+ L"{google:baseURL}?q={searchTerms}", L"name", false, Time());
+ ASSERT_EQ(t_url, model_->GetTemplateURLForHost("google.com"));
+ EXPECT_EQ("google.com", t_url->url()->GetHost());
+ EXPECT_EQ(L"google.com", t_url->keyword());
+
+ // Change the Google base url.
+ model_->loaded_ = true; // Hack to make sure we get notified of the base URL
+ // changing.
+ SetGoogleBaseURL(L"http://foo.com/");
+ model_->GoogleBaseURLChanged();
+ VerifyObserverCount(1);
+
+ // Make sure the host->TemplateURL map was updated appropriately.
+ ASSERT_EQ(t_url, model_->GetTemplateURLForHost("foo.com"));
+ EXPECT_TRUE(model_->GetTemplateURLForHost("google.com") == NULL);
+ EXPECT_EQ("foo.com", t_url->url()->GetHost());
+ EXPECT_EQ(L"foo.com", t_url->keyword());
+ EXPECT_EQ("http://foo.com/?q=x", t_url->url()->ReplaceSearchTerms(*t_url,
+ L"x", TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()).spec());
+}
diff --git a/chrome/browser/template_url_parser.cc b/chrome/browser/template_url_parser.cc
new file mode 100644
index 0000000..93f9f79
--- /dev/null
+++ b/chrome/browser/template_url_parser.cc
@@ -0,0 +1,586 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/template_url_parser.h"
+
+#include <map>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/browser/template_url.h"
+#include "googleurl/src/gurl.h"
+#include "libxml/parser.h"
+#include "libxml/xmlwriter.h"
+
+namespace {
+
+//
+// NOTE: libxml uses the UTF-8 encoding. As 0-127 of UTF-8 corresponds
+// to that of char, the following names are all in terms of char. This avoids
+// having to convert to wide, then do comparisons
+
+// Defines for element names of the OSD document:
+static const char kURLElement[] = "Url";
+static const char kParamElement[] = "Param";
+static const char kShortNameElement[] = "ShortName";
+static const char kDescriptionElement[] = "Description";
+static const char kImageElement[] = "Image";
+static const char kOpenSearchDescriptionElement[] = "OpenSearchDescription";
+static const char kFirefoxSearchDescriptionElement[] = "SearchPlugin";
+static const char kLanguageElement[] = "Language";
+static const char kInputEncodingElement[] = "InputEncoding";
+
+// Various XML attributes used.
+static const char kURLTypeAttribute[] = "type";
+static const char kURLTemplateAttribute[] = "template";
+static const char kImageTypeAttribute[] = "type";
+static const char kImageWidthAttribute[] = "width";
+static const char kImageHeightAttribute[] = "height";
+static const char kURLIndexOffsetAttribute[] = "indexOffset";
+static const char kURLPageOffsetAttribute[] = "pageOffset";
+static const char kParamNameAttribute[] = "name";
+static const char kParamValueAttribute[] = "value";
+static const char kParamMethodAttribute[] = "method";
+
+// Mime type for search results.
+static const char kHTMLType[] = "text/html";
+
+// Mime type for as you type suggestions.
+static const char kSuggestionType[] = "application/x-suggestions+json";
+
+// Namespace identifier.
+static const char kOSDNS[] = "xmlns";
+
+// The namespace for documents we understand.
+static const char kNameSpace[] = "http://a9.com/-/spec/opensearch/1.1/";
+
+// Removes the namespace from the specified |name|, ex: os:Url -> Url.
+static void PruneNamespace(std::string* name) {
+ size_t index = name->find_first_of(":");
+ if (index != std::string::npos)
+ name->erase(0, index + 1);
+}
+
+//
+// To minimize memory overhead while parsing, a SAX style parser is used.
+// ParsingContext is used to maintain the state we're in the document
+// while parsing.
+class ParsingContext {
+ public:
+ // Enum of the known element types.
+ enum ElementType {
+ UNKNOWN,
+ OPEN_SEARCH_DESCRIPTION,
+ URL,
+ PARAM,
+ SHORT_NAME,
+ DESCRIPTION,
+ IMAGE,
+ LANGUAGE,
+ INPUT_ENCODING,
+ };
+
+ enum Method {
+ GET,
+ POST
+ };
+
+ // Key/value of a Param node.
+ typedef std::pair<std::string, std::string> Param;
+
+ ParsingContext(TemplateURLParser::ParameterFilter* parameter_filter,
+ TemplateURL* url)
+ : url_(url),
+ parameter_filter_(parameter_filter),
+ method_(GET),
+ suggestion_method_(GET),
+ is_suggest_url_(false),
+ derive_image_from_url_(false) {
+ if (kElementNameToElementTypeMap == NULL)
+ InitMapping();
+ }
+
+ // Invoked when an element starts.
+ void PushElement(const std::string& element) {
+ ElementType type;
+ if (kElementNameToElementTypeMap->find(element) ==
+ kElementNameToElementTypeMap->end()) {
+ type = UNKNOWN;
+ } else {
+ type = (*kElementNameToElementTypeMap)[element];
+ }
+ elements_.push_back(type);
+ }
+
+ void PopElement() {
+ elements_.pop_back();
+ }
+
+ // Returns the current ElementType.
+ ElementType GetKnownType() {
+ if (elements_.size() == 2 && elements_[0] == OPEN_SEARCH_DESCRIPTION)
+ return elements_[1];
+
+ // We only expect PARAM nodes under the Url node
+ if (elements_.size() == 3 && elements_[0] == OPEN_SEARCH_DESCRIPTION &&
+ elements_[1] == URL && elements_[2] == PARAM)
+ return PARAM;
+
+ return UNKNOWN;
+ }
+
+ TemplateURL* template_url() { return url_; }
+
+ void AddImageRef(const std::wstring& type, int width, int height) {
+ if (width > 0 && height > 0)
+ current_image_.reset(new TemplateURL::ImageRef(type, width, height));
+ }
+
+ void EndImage() {
+ current_image_.reset();
+ }
+
+ void SetImageURL(const std::wstring& url) {
+ if (current_image_.get()) {
+ current_image_->url = GURL(WideToUTF8(url));
+ url_->add_image_ref(*current_image_);
+ current_image_.reset();
+ }
+ }
+
+ void ResetString() {
+ string_.clear();
+ }
+
+ void AppendString(const std::wstring& string) {
+ string_ += string;
+ }
+
+ const std::wstring& GetString() {
+ return string_;
+ }
+
+ void ResetExtraParams() {
+ extra_params_.clear();
+ }
+
+ void AddExtraParams(const std::string& key, const std::string& value) {
+ if (parameter_filter_ && !parameter_filter_->KeepParameter(key, value))
+ return;
+ extra_params_.push_back(Param(key, value));
+ }
+
+ const std::vector<Param>& extra_params() const { return extra_params_; }
+
+ void set_is_suggestion(bool value) { is_suggest_url_ = value; }
+ bool is_suggestion() const { return is_suggest_url_; }
+
+ TemplateURLParser::ParameterFilter* parameter_filter() const {
+ return parameter_filter_;
+ }
+
+ void set_derive_image_from_url(bool derive_image_from_url) {
+ derive_image_from_url_ = derive_image_from_url;
+ }
+
+ void set_method(Method method) { method_ = method; }
+ Method method() { return method_; }
+
+ void set_suggestion_method(Method method) { suggestion_method_ = method; }
+ Method suggestion_method() { return suggestion_method_; }
+
+ // Builds the image URL from the Template search URL if no image URL has been
+ // set.
+ void DeriveImageFromURL() {
+ if (derive_image_from_url_ &&
+ url_->GetFavIconURL().is_empty() && url_->url()) {
+ GURL url(WideToUTF8(url_->url()->url())); // More url's please...
+ url_->SetFavIconURL(TemplateURL::GenerateFaviconURL(url));
+ }
+ }
+
+ private:
+ static void InitMapping() {
+ kElementNameToElementTypeMap = new std::map<std::string,ElementType>;
+ (*kElementNameToElementTypeMap)[kURLElement] = URL;
+ (*kElementNameToElementTypeMap)[kParamElement] = PARAM;
+ (*kElementNameToElementTypeMap)[kShortNameElement] = SHORT_NAME;
+ (*kElementNameToElementTypeMap)[kDescriptionElement] = DESCRIPTION;
+ (*kElementNameToElementTypeMap)[kImageElement] = IMAGE;
+ (*kElementNameToElementTypeMap)[kOpenSearchDescriptionElement] =
+ OPEN_SEARCH_DESCRIPTION;
+ (*kElementNameToElementTypeMap)[kFirefoxSearchDescriptionElement] =
+ OPEN_SEARCH_DESCRIPTION;
+ (*kElementNameToElementTypeMap)[kLanguageElement] =
+ LANGUAGE;
+ (*kElementNameToElementTypeMap)[kInputEncodingElement] =
+ INPUT_ENCODING;
+ }
+
+ // Key is UTF8 encoded.
+ static std::map<std::string,ElementType>* kElementNameToElementTypeMap;
+ // TemplateURL supplied to Read method. It's owned by the caller, so we
+ // don't need to free it.
+ TemplateURL* url_;
+ std::vector<ElementType> elements_;
+ scoped_ptr<TemplateURL::ImageRef> current_image_;
+
+ // Character content for the current element.
+ std::wstring string_;
+
+ TemplateURLParser::ParameterFilter* parameter_filter_;
+
+ // The list of parameters parsed in the Param nodes of a Url node.
+ std::vector<Param> extra_params_;
+
+ // The HTTP methods used.
+ Method method_;
+ Method suggestion_method_;
+
+ // If true, we are currently parsing a suggest URL, otherwise it is an HTML
+ // search. Note that we don't need a stack as Url nodes cannot be nested.
+ bool is_suggest_url_;
+
+ // Whether we should derive the image from the URL (when images are data
+ // URLs).
+ bool derive_image_from_url_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ParsingContext);
+};
+
+//static
+std::map<std::string,ParsingContext::ElementType>*
+ ParsingContext::kElementNameToElementTypeMap = NULL;
+
+std::wstring XMLCharToWide(const xmlChar* value) {
+ return UTF8ToWide(std::string((const char*)value));
+}
+
+std::wstring XMLCharToWide(const xmlChar* value, int length) {
+ return UTF8ToWide(std::string((const char*)value, length));
+}
+
+std::string XMLCharToString(const xmlChar* value) {
+ return std::string((const char*)value);
+}
+
+// Returns true if input_encoding contains a valid input encoding string. This
+// doesn't verify that we have a valid encoding for the string, just that the
+// string contains characters that constitute a valid input encoding.
+bool IsValidEncodingString(const std::string& input_encoding) {
+ if (input_encoding.empty())
+ return false;
+
+ if (!IsAsciiAlpha(input_encoding[0]))
+ return false;
+
+ for (size_t i = 1, max = input_encoding.size(); i < max; ++i) {
+ char c = input_encoding[i];
+ if (!IsAsciiAlpha(c) && !IsAsciiDigit(c) && c != '.' && c != '_' &&
+ c != '-') {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ParseURL(const xmlChar** atts, ParsingContext* context) {
+ if (!atts)
+ return;
+
+ TemplateURL* turl = context->template_url();
+ const xmlChar** attributes = atts;
+ std::wstring template_url;
+ bool is_post = false;
+ bool is_html_url = false;
+ bool is_suggest_url = false;
+ int index_offset = 1;
+ int page_offset = 1;
+
+ while (*attributes) {
+ std::string name(XMLCharToString(*attributes));
+ const xmlChar* value = attributes[1];
+ if (name == kURLTypeAttribute) {
+ std::string type = XMLCharToString(value);
+ is_html_url = (type == kHTMLType);
+ is_suggest_url = (type == kSuggestionType);
+ } else if (name == kURLTemplateAttribute) {
+ template_url = XMLCharToWide(value);
+ } else if (name == kURLIndexOffsetAttribute) {
+ index_offset = std::max(1, StringToInt(XMLCharToWide(value)));
+ } else if (name == kURLPageOffsetAttribute) {
+ page_offset = std::max(1, StringToInt(XMLCharToWide(value)));
+ } else if (name == kParamMethodAttribute) {
+ is_post = LowerCaseEqualsASCII(XMLCharToString(value), "post");
+ }
+ attributes += 2;
+ }
+ if (is_html_url) {
+ turl->SetURL(template_url, index_offset, page_offset);
+ context->set_is_suggestion(false);
+ if (is_post)
+ context->set_method(ParsingContext::POST);
+ } else if (is_suggest_url) {
+ turl->SetSuggestionsURL(template_url, index_offset, page_offset);
+ context->set_is_suggestion(true);
+ if (is_post)
+ context->set_suggestion_method(ParsingContext::POST);
+ }
+}
+
+void ParseImage(const xmlChar** atts, ParsingContext* context) {
+ if (!atts)
+ return;
+
+ const xmlChar** attributes = atts;
+ int width = 0;
+ int height = 0;
+ std::wstring type;
+ while (*attributes) {
+ std::string name(XMLCharToString(*attributes));
+ const xmlChar* value = attributes[1];
+ if (name == kImageTypeAttribute) {
+ type = XMLCharToWide(value);
+ } else if (name == kImageWidthAttribute) {
+ width = StringToInt(XMLCharToWide(value));
+ } else if (name == kImageHeightAttribute) {
+ height = StringToInt(XMLCharToWide(value));
+ }
+ attributes += 2;
+ }
+ if (width > 0 && height > 0 && !type.empty()) {
+ // Valid Image URL.
+ context->AddImageRef(type, width, height);
+ }
+}
+
+void ParseParam(const xmlChar** atts, ParsingContext* context) {
+ if (!atts)
+ return;
+
+ const xmlChar** attributes = atts;
+ std::wstring type;
+ std::string key, value;
+ while (*attributes) {
+ std::string name(XMLCharToString(*attributes));
+ const xmlChar* val = attributes[1];
+ if (name == kParamNameAttribute) {
+ key = XMLCharToString(val);
+ } else if (name == kParamValueAttribute) {
+ value = XMLCharToString(val);
+ }
+ attributes += 2;
+ }
+ if (!key.empty())
+ context->AddExtraParams(key, value);
+}
+
+static void AppendParamToQuery(const std::string& key,
+ const std::string& value,
+ std::string* query) {
+ if (!query->empty())
+ query->append("&");
+ if (!key.empty()) {
+ query->append(key);
+ query->append("=");
+ }
+ query->append(value);
+}
+
+void ProcessURLParams(ParsingContext* context) {
+ TemplateURL* t_url = context->template_url();
+ const TemplateURLRef* t_url_ref =
+ context->is_suggestion() ? t_url->suggestions_url() :
+ t_url->url();
+ if (!t_url_ref)
+ return;
+
+ if (!context->parameter_filter() && context->extra_params().empty())
+ return;
+
+ GURL url(WideToUTF8(t_url_ref->url()));
+ // If there is a parameter filter, parse the existing URL and remove any
+ // unwanted parameter.
+ TemplateURLParser::ParameterFilter* filter = context->parameter_filter();
+ std::string new_query;
+ bool modified = false;
+ if (filter) {
+ url_parse::Component query = url.parsed_for_possibly_invalid_spec().query;
+ url_parse::Component key, value;
+ const char* url_spec = url.spec().c_str();
+ while (url_parse::ExtractQueryKeyValue(url_spec, &query, &key, &value)) {
+ std::string key_str(url_spec, key.begin, key.len);
+ std::string value_str(url_spec, value.begin, value.len);
+ if (filter->KeepParameter(key_str, value_str)) {
+ AppendParamToQuery(key_str, value_str, &new_query);
+ } else {
+ modified = true;
+ }
+ }
+ }
+ if (!modified)
+ new_query = url.query();
+
+ // Add the extra parameters if any.
+ const std::vector<ParsingContext::Param>& params = context->extra_params();
+ if (!params.empty()) {
+ modified = true;
+ std::vector<ParsingContext::Param>::const_iterator iter;
+ for (iter = params.begin(); iter != params.end(); ++iter)
+ AppendParamToQuery(iter->first, iter->second, &new_query);
+ }
+
+ if (modified) {
+ GURL::Replacements repl;
+ repl.SetQueryStr(new_query);
+ url = url.ReplaceComponents(repl);
+ if (context->is_suggestion()) {
+ t_url->SetSuggestionsURL(UTF8ToWide(url.spec()),
+ t_url_ref->index_offset(),
+ t_url_ref->page_offset());
+ } else {
+ t_url->SetURL(UTF8ToWide(url.spec()),
+ t_url_ref->index_offset(),
+ t_url_ref->page_offset());
+ }
+ }
+}
+
+void StartElementImpl(void *ctx, const xmlChar *name, const xmlChar **atts) {
+ ParsingContext* context = reinterpret_cast<ParsingContext*>(ctx);
+ std::string node_name((const char*)name);
+ PruneNamespace(&node_name);
+ context->PushElement(node_name);
+ switch (context->GetKnownType()) {
+ case ParsingContext::URL:
+ context->ResetExtraParams();
+ ParseURL(atts, context);
+ break;
+ case ParsingContext::IMAGE:
+ ParseImage(atts, context);
+ break;
+ case ParsingContext::PARAM:
+ ParseParam(atts, context);
+ break;
+ default:
+ break;
+ }
+ context->ResetString();
+}
+
+void EndElementImpl(void *ctx, const xmlChar *name) {
+ ParsingContext* context = reinterpret_cast<ParsingContext*>(ctx);
+ switch (context->GetKnownType()) {
+ case ParsingContext::SHORT_NAME:
+ context->template_url()->set_short_name(context->GetString());
+ break;
+ case ParsingContext::DESCRIPTION:
+ context->template_url()->set_description(context->GetString());
+ break;
+ case ParsingContext::IMAGE: {
+ GURL image_url(WideToUTF8(context->GetString()));
+ if (image_url.SchemeIs("data")) {
+ // TODO (jcampan): bug 1169256: when dealing with data URL, we need to
+ // decode the data URL in the renderer. For now, we'll just point to the
+ // fav icon from the URL.
+ context->set_derive_image_from_url(true);
+ } else {
+ context->SetImageURL(context->GetString());
+ }
+ context->EndImage();
+ break;
+ }
+ case ParsingContext::LANGUAGE:
+ context->template_url()->add_language(context->GetString());
+ break;
+ case ParsingContext::INPUT_ENCODING: {
+ std::string input_encoding = WideToASCII(context->GetString());
+ if (IsValidEncodingString(input_encoding))
+ context->template_url()->add_input_encoding(input_encoding);
+ break;
+ }
+ case ParsingContext::URL:
+ ProcessURLParams(context);
+ break;
+ default:
+ break;
+ }
+ context->ResetString();
+ context->PopElement();
+}
+
+void CharactersImpl(void *ctx, const xmlChar *ch, int len) {
+ ParsingContext* context = reinterpret_cast<ParsingContext*>(ctx);
+ context->AppendString(XMLCharToWide(ch, len));
+}
+
+// Returns true if the ref is null, or the url wrapped by ref is
+// valid with a spec of http/https.
+bool IsHTTPRef(const TemplateURLRef* ref) {
+ if (ref == NULL)
+ return true;
+ GURL url(WideToUTF8(ref->url()));
+ return (url.is_valid() && (url.SchemeIs("http") || url.SchemeIs("https")));
+}
+
+// Returns true if the TemplateURL is legal. A legal TemplateURL is one
+// where all URLs have a spec of http/https.
+bool IsLegal(TemplateURL* url) {
+ if (!IsHTTPRef(url->url()) || !IsHTTPRef(url->suggestions_url()))
+ return false;
+ // Make sure all the image refs are legal.
+ const std::vector<TemplateURL::ImageRef>& image_refs = url->image_refs();
+ for (size_t i = 0; i < image_refs.size(); i++) {
+ GURL image_url(image_refs[i].url);
+ if (!image_url.is_valid() ||
+ !(image_url.SchemeIs("http") || image_url.SchemeIs("https"))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+// static
+bool TemplateURLParser::Parse(const unsigned char* data, size_t length,
+ TemplateURLParser::ParameterFilter* param_filter,
+ TemplateURL* url) {
+ DCHECK(url);
+ // xmlSubstituteEntitiesDefault(1) makes it so that &amp; isn't mapped to
+ // &#38; . Unfortunately xmlSubstituteEntitiesDefault effects global state.
+ // If this becomes problematic we'll need to provide our own entity
+ // type for &amp;, or strip out &#34; by hand after parsing.
+ int last_sub_entities_value = xmlSubstituteEntitiesDefault(1);
+ ParsingContext context(param_filter, url);
+ xmlSAXHandler sax_handler;
+ memset(&sax_handler, 0, sizeof(sax_handler));
+ sax_handler.startElement = &StartElementImpl;
+ sax_handler.endElement = &EndElementImpl;
+ sax_handler.characters = &CharactersImpl;
+ xmlSAXUserParseMemory(&sax_handler, &context,
+ reinterpret_cast<const char*>(data),
+ static_cast<int>(length));
+ xmlSubstituteEntitiesDefault(last_sub_entities_value);
+ // If the image was a data URL, use the favicon from the search URL instead.
+ // (see TODO inEndElementImpl()).
+ context.DeriveImageFromURL();
+
+ // TODO(jcampan): http://b/issue?id=1196285 we do not support search engines
+ // that use POST yet.
+ if (context.method() == ParsingContext::POST)
+ return false;
+ if (context.suggestion_method() == ParsingContext::POST)
+ url->SetSuggestionsURL(L"", 0, 0);
+
+ if (!url->short_name().empty() && !url->description().empty()) {
+ // So far so good, make sure the urls are http.
+ return IsLegal(url);
+ }
+ return false;
+}
+
+
diff --git a/chrome/browser/template_url_parser.h b/chrome/browser/template_url_parser.h
new file mode 100644
index 0000000..facf7c6
--- /dev/null
+++ b/chrome/browser/template_url_parser.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TEMPLATE_URL_PARSER_H__
+#define CHROME_BROWSER_TEMPLATE_URL_PARSER_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+
+class TemplateURL;
+
+// TemplateURLParser, as the name implies, handling reading of TemplateURLs
+// from OpenSearch description documents.
+class TemplateURLParser {
+ public:
+ class ParameterFilter {
+ public:
+ // Invoked for each parameter of the template URL while parsing. If this
+ // methods returns false, the parameter is not included.
+ virtual bool KeepParameter(const std::string& key,
+ const std::string& value) = 0;
+ };
+ // Decodes the chunk of data representing a TemplateURL. If data does
+ // not describe a valid TemplateURL false is returned. Additionally, if the
+ // URLs referenced do not point to valid http/https resources, false is
+ // returned. |parameter_filter| can be used if you want to filter out some
+ // parameters out of the URL. For example when importing from another browser
+ // we remove any parameter identifying that browser. If set to NULL, the URL
+ // is not modified.
+ //
+ // NOTE: This does not clear all values of the supplied TemplateURL; it's
+ // expected callers will supply a new TemplateURL to this method.
+ static bool Parse(const unsigned char* data,
+ size_t length,
+ ParameterFilter* parameter_filter,
+ TemplateURL* url);
+
+ private:
+ // No one should create one of these.
+ TemplateURLParser();
+
+ DISALLOW_EVIL_CONSTRUCTORS(TemplateURLParser);
+};
+
+#endif // CHROME_BROWSER_TEMPLATE_URL_PARSER_H__
+
diff --git a/chrome/browser/template_url_parser_unittest.cc b/chrome/browser/template_url_parser_unittest.cc
new file mode 100644
index 0000000..381eba0
--- /dev/null
+++ b/chrome/browser/template_url_parser_unittest.cc
@@ -0,0 +1,240 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_parser.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TemplateURLParserTest : public testing::Test {
+ public:
+ TemplateURLParserTest() : parse_result_(true) {
+ }
+
+ virtual void SetUp() {
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path_));
+ file_util::AppendToPath(&full_path_, L"osdd");
+ if (!file_util::PathExists(full_path_)) {
+ LOG(ERROR) <<
+ L"This test can't be run without some non-redistributable data";
+ full_path_.clear();
+ }
+ }
+
+ bool IsDisabled() {
+ return full_path_.empty();
+ }
+
+ // Parses the OpenSearch description document at file_name (relative to
+ // the data dir). The TemplateURL is placed in template_url_.
+ // The result of Parse is stored in the field parse_result_ (this doesn't
+ // use a return value due to internally using ASSERT_).
+ void ParseFile(const std::wstring& file_name,
+ TemplateURLParser::ParameterFilter* filter) {
+ std::wstring full_path(full_path_);
+ file_util::AppendToPath(&full_path, file_name);
+ parse_result_ = false;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path));
+ file_util::AppendToPath(&full_path, L"osdd");
+ file_util::AppendToPath(&full_path, file_name);
+ ASSERT_TRUE(file_util::PathExists(full_path));
+
+ std::string contents;
+ file_util::ReadFileToString(full_path, &contents);
+ parse_result_ = TemplateURLParser::Parse(
+ reinterpret_cast<const unsigned char*>(contents.c_str()),
+ contents.length(), filter, &template_url_);
+ }
+
+ // ParseFile parses the results into this template_url.
+ TemplateURL template_url_;
+
+ std::wstring full_path_;
+
+ // Result of the parse.
+ bool parse_result_;
+};
+
+TEST_F(TemplateURLParserTest, FailOnBogusURL) {
+ if (IsDisabled())
+ return;
+ ParseFile(L"bogus.xml", NULL);
+ EXPECT_FALSE(parse_result_);
+}
+
+TEST_F(TemplateURLParserTest, PassOnHTTPS) {
+ if (IsDisabled())
+ return;
+ ParseFile(L"https.xml", NULL);
+ EXPECT_TRUE(parse_result_);
+}
+
+TEST_F(TemplateURLParserTest, FailOnPost) {
+ if (IsDisabled())
+ return;
+ ParseFile(L"post.xml", NULL);
+ EXPECT_FALSE(parse_result_);
+}
+
+TEST_F(TemplateURLParserTest, TestDictionary) {
+ if (IsDisabled())
+ return;
+ ParseFile(L"dictionary.xml", NULL);
+ ASSERT_TRUE(parse_result_);
+ EXPECT_EQ(L"Dictionary.com", template_url_.short_name());
+ EXPECT_TRUE(template_url_.GetFavIconURL() ==
+ GURL("http://cache.lexico.com/g/d/favicon.ico"));
+ EXPECT_TRUE(template_url_.url() != NULL);
+ EXPECT_TRUE(template_url_.url()->SupportsReplacement());
+ EXPECT_EQ(template_url_.url()->url(),
+ L"http://dictionary.reference.com/browse/{searchTerms}?r=75");
+}
+
+TEST_F(TemplateURLParserTest, TestMSDN) {
+ if (IsDisabled())
+ return;
+ ParseFile(L"msdn.xml", NULL);
+ ASSERT_TRUE(parse_result_);
+ EXPECT_EQ(L"Search \" MSDN", template_url_.short_name());
+ EXPECT_TRUE(template_url_.GetFavIconURL() ==
+ GURL("http://search.msdn.microsoft.com/search/favicon.ico"));
+ EXPECT_TRUE(template_url_.url() != NULL);
+ EXPECT_TRUE(template_url_.url()->SupportsReplacement());
+ EXPECT_EQ(template_url_.url()->url(),
+ L"http://search.msdn.microsoft.com/search/default.aspx?Query={searchTerms}&brand=msdn&locale=en-US");
+}
+
+TEST_F(TemplateURLParserTest, TestWikipedia) {
+ if (IsDisabled())
+ return;
+ ParseFile(L"wikipedia.xml", NULL);
+ ASSERT_TRUE(parse_result_);
+ EXPECT_EQ(L"Wikipedia (English)", template_url_.short_name());
+ EXPECT_TRUE(template_url_.GetFavIconURL() ==
+ GURL("http://en.wikipedia.org/favicon.ico"));
+ EXPECT_TRUE(template_url_.url() != NULL);
+ EXPECT_TRUE(template_url_.url()->SupportsReplacement());
+ EXPECT_EQ(template_url_.url()->url(),
+ L"http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}");
+ EXPECT_TRUE(template_url_.suggestions_url() != NULL);
+ EXPECT_TRUE(template_url_.suggestions_url()->SupportsReplacement());
+ EXPECT_EQ(template_url_.suggestions_url()->url(),
+ L"http://en.wikipedia.org/w/api.php?action=opensearch&search={searchTerms}");
+ ASSERT_EQ(2U, template_url_.input_encodings().size());
+ EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]);
+ EXPECT_EQ("Shift_JIS", template_url_.input_encodings()[1]);
+}
+
+TEST_F(TemplateURLParserTest, NoCrashOnEmptyAttributes) {
+ if (IsDisabled())
+ return;
+ ParseFile(L"url_with_no_attributes.xml", NULL);
+}
+
+// Filters any param which as an occurrence of name_str_ in its name or an
+// occurrence of value_str_ in its value.
+class ParamFilterImpl : public TemplateURLParser::ParameterFilter {
+ public:
+ ParamFilterImpl(std::string name_str, std::string value_str)
+ : name_str_(name_str),
+ value_str_(value_str) {
+ }
+
+ bool KeepParameter(const std::string& key, const std::string& value) {
+ return (name_str_.empty() || key.find(name_str_) == std::string::npos) &&
+ (value_str_.empty() || value.find(value_str_) == std::string::npos);
+ }
+
+ private:
+ std::string name_str_;
+ std::string value_str_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ParamFilterImpl);
+};
+
+TEST_F(TemplateURLParserTest, TestFirefoxEbay) {
+ if (IsDisabled())
+ return;
+ // This file uses the Parameter extension
+ // (see http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0)
+ ParamFilterImpl filter("ebay", "ebay");
+ ParseFile(L"firefox_ebay.xml", &filter);
+ ASSERT_TRUE(parse_result_);
+ EXPECT_EQ(L"eBay", template_url_.short_name());
+ EXPECT_TRUE(template_url_.url() != NULL);
+ EXPECT_TRUE(template_url_.url()->SupportsReplacement());
+ std::wstring exp_url =
+ L"http://search.ebay.com/search/search.dll?query={searchTerms}&"
+ L"MfcISAPICommand=GetResult&ht=1&srchdesc=n&maxRecordsReturned=300&"
+ L"maxRecordsPerPage=50&SortProperty=MetaEndSort";
+ EXPECT_EQ(exp_url, template_url_.url()->url());
+ ASSERT_EQ(1U, template_url_.input_encodings().size());
+ EXPECT_EQ("ISO-8859-1", template_url_.input_encodings()[0]);
+ EXPECT_EQ(GURL("http://search.ebay.com/favicon.ico"),
+ template_url_.GetFavIconURL());
+}
+
+TEST_F(TemplateURLParserTest, TestFirefoxWebster) {
+ if (IsDisabled())
+ return;
+ // This XML file uses a namespace.
+ ParamFilterImpl filter("", "Mozilla");
+ ParseFile(L"firefox_webster.xml", &filter);
+ ASSERT_TRUE(parse_result_);
+ EXPECT_EQ(L"Webster", template_url_.short_name());
+ EXPECT_TRUE(template_url_.url() != NULL);
+ EXPECT_TRUE(template_url_.url()->SupportsReplacement());
+ EXPECT_EQ(L"http://www.webster.com/cgi-bin/dictionary?va={searchTerms}",
+ template_url_.url()->url());
+ ASSERT_EQ(1U, template_url_.input_encodings().size());
+ EXPECT_EQ("ISO-8859-1", template_url_.input_encodings()[0]);
+ EXPECT_EQ(GURL("http://www.webster.com/favicon.ico"),
+ template_url_.GetFavIconURL());
+}
+
+TEST_F(TemplateURLParserTest, TestFirefoxYahoo) {
+ if (IsDisabled())
+ return;
+ // This XML file uses a namespace.
+ ParamFilterImpl filter("", "Mozilla");
+ ParseFile(L"firefox_yahoo.xml", &filter);
+ ASSERT_TRUE(parse_result_);
+ EXPECT_EQ(L"Yahoo", template_url_.short_name());
+ EXPECT_TRUE(template_url_.url() != NULL);
+ EXPECT_TRUE(template_url_.url()->SupportsReplacement());
+ EXPECT_EQ(L"http://ff.search.yahoo.com/gossip?"
+ L"output=fxjson&command={searchTerms}",
+ template_url_.suggestions_url()->url());
+ EXPECT_EQ(L"http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8",
+ template_url_.url()->url());
+ ASSERT_EQ(1U, template_url_.input_encodings().size());
+ EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]);
+ EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"),
+ template_url_.GetFavIconURL());
+}
+
+// Make sure we ignore POST suggestions (this is the same XML file as
+// firefox_yahoo.xml, the suggestion method was just changed to POST).
+TEST_F(TemplateURLParserTest, TestPostSuggestion) {
+ if (IsDisabled())
+ return;
+ // This XML file uses a namespace.
+ ParamFilterImpl filter("", "Mozilla");
+ ParseFile(L"post_suggestion.xml", &filter);
+ ASSERT_TRUE(parse_result_);
+ EXPECT_EQ(L"Yahoo", template_url_.short_name());
+ EXPECT_TRUE(template_url_.url() != NULL);
+ EXPECT_TRUE(template_url_.url()->SupportsReplacement());
+ EXPECT_TRUE(template_url_.suggestions_url() == NULL);
+ EXPECT_EQ(L"http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8",
+ template_url_.url()->url());
+ ASSERT_EQ(1U, template_url_.input_encodings().size());
+ EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]);
+ EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"),
+ template_url_.GetFavIconURL());
+}
diff --git a/chrome/browser/template_url_prepopulate_data.cc b/chrome/browser/template_url_prepopulate_data.cc
new file mode 100644
index 0000000..11ebf21
--- /dev/null
+++ b/chrome/browser/template_url_prepopulate_data.cc
@@ -0,0 +1,3082 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/template_url_prepopulate_data.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#undef IN // On Windows, windef.h defines this, which screws up "India" cases.
+
+using base::Time;
+
+namespace {
+
+// NOTE: See comments in GetDataVersion() below! You should probably not change
+// the data in this file without changing the result of that function!
+
+// Engine definitions //////////////////////////////////////////////////////////
+
+struct PrepopulatedEngine {
+ const wchar_t* const name;
+ // If NULL, we'll autogenerate a keyword based on the search_url every time
+ // someone asks. Only entries which need keywords to auto-track a dynamically
+ // generated search URL should use this.
+ // If the empty string, the engine has no keyword.
+ const wchar_t* const keyword;
+ const wchar_t* const favicon_url; // If NULL, there is no favicon.
+ const wchar_t* const search_url;
+ const char* const encoding;
+ const wchar_t* const suggest_url; // If NULL, this engine does not support
+ // suggestions.
+ // Unique id for this prepopulate engine (corresponds to
+ // TemplateURL::prepopulate_id). This ID must be greater than zero and must
+ // remain the same for a particular site regardless of how the url changes;
+ // the ID is used when modifying engine data in subsequent versions, so that
+ // we can find the "old" entry to update even when the name or URL changes.
+ //
+ // This ID must be "unique" within one country's prepopulated data, but two
+ // entries can share an ID if they represent the "same" engine (e.g. Yahoo! US
+ // vs. Yahoo! UK) and will not appear in the same user-visible data set. This
+ // facilitates changes like adding more specific per-country data in the
+ // future; in such a case the localized engines will transparently replace the
+ // previous, non-localized versions. For engines where we need two instances
+ // to appear for one country (e.g. Live Search U.S. English and Spanish), we
+ // must use two different unique IDs (and different keywords).
+ //
+ // The following unique IDs are available: 66, 93, 103+
+ // NOTE: CHANGE THE ABOVE NUMBERS IF YOU ADD A NEW ENGINE; ID conflicts = bad!
+ const int id;
+};
+
+const PrepopulatedEngine abcsok = {
+ L"ABC S\x00f8k",
+ L"abcsok.no",
+ L"http://abcsok.no/favicon.ico",
+ L"http://abcsok.no/index.html?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 72,
+};
+
+const PrepopulatedEngine adonde = {
+ L"Adonde.com",
+ L"adonde.com",
+ L"http://www.adonde.com/favicon.ico",
+ L"http://www.adonde.com/peru/peru.html?sitesearch=adonde.com&"
+ L"client=pub-6263803831447773&ie={inputEncoding}&cof=GALT%3A%23CC0000"
+ L"%3BGL%3A1%3BDIV%3A%23E6E6E6%3BVLC%3A663399%3BAH%3Acenter%3BBGC%3AFFFFFF"
+ L"%3BLBGC%3AFFFFFF%3BALC%3A000000%3BLC%3A000000%3BT%3A0066CC%3BGFNT"
+ L"%3ACCCCCC%3BGIMP%3ACCCCCC%3BFORID%3A11&q={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 95,
+};
+
+const PrepopulatedEngine aeiou = {
+ L"AEIOU",
+ L"aeiou.pt",
+ L"http://aeiou.pt/favicon.ico",
+ L"http://aeiou.pt/pesquisa/index.php?p={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 79,
+};
+
+const PrepopulatedEngine aladin = {
+ L"Aladin",
+ L"aladin.info",
+ L"http://www.aladin.info/favicon.ico",
+ L"http://www.aladin.info/search/index.php?term={searchTerms}&req=search&"
+ L"source=2",
+ "UTF-8",
+ NULL,
+ 18,
+};
+
+const PrepopulatedEngine altavista = {
+ L"AltaVista",
+ L"altavista.com",
+ L"http://www.altavista.com/favicon.ico",
+ L"http://www.altavista.com/web/results?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 89,
+};
+
+const PrepopulatedEngine altavista_ar = {
+ L"AltaVista",
+ L"ar.altavista.com",
+ L"http://ar.altavista.com/favicon.ico",
+ L"http://ar.altavista.com/web/results?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 89,
+};
+
+const PrepopulatedEngine altavista_es = {
+ L"AltaVista",
+ L"es.altavista.com",
+ L"http://es.altavista.com/favicon.ico",
+ L"http://es.altavista.com/web/results?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 89,
+};
+
+const PrepopulatedEngine altavista_mx = {
+ L"AltaVista",
+ L"mx.altavista.com",
+ L"http://mx.altavista.com/favicon.ico",
+ L"http://mx.altavista.com/web/results?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 89,
+};
+
+const PrepopulatedEngine altavista_se = {
+ L"AltaVista",
+ L"se.altavista.com",
+ L"http://se.altavista.com/favicon.ico",
+ L"http://se.altavista.com/web/results?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 89,
+};
+
+const PrepopulatedEngine aol = {
+ L"AOL",
+ L"aol.com",
+ L"http://search.aol.com/favicon.ico",
+ L"http://search.aol.com/aol/search?query={searchTerms}",
+ "UTF-8",
+ NULL,
+ 35,
+};
+
+const PrepopulatedEngine aol_fr = {
+ L"AOL",
+ L"aol.fr",
+ L"http://www.aol.fr/favicon.ico",
+ L"http://www.recherche.aol.fr/aol/search?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 35,
+};
+
+const PrepopulatedEngine aonde = {
+ L"AONDE.com",
+ L"aonde.com",
+ L"http://busca.aonde.com/favicon.ico",
+ L"http://busca.aonde.com/?keys={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 80,
+};
+
+const PrepopulatedEngine araby = {
+ L"\x0639\x0631\x0628\x064a",
+ L"araby.com",
+ L"http://araby.com/favicon.ico",
+ L"http://araby.com/?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 12,
+};
+
+const PrepopulatedEngine ask = {
+ L"Ask",
+ L"ask.com",
+ L"http://www.ask.com/favicon.ico",
+ L"http://www.ask.com/web?q={searchTerms}",
+ "UTF-8",
+ L"http://ss.ask.com/query?q={searchTerms}&li=ff",
+ 4,
+};
+
+const PrepopulatedEngine ask_de = {
+ L"Ask.com Deutschland",
+ L"de.ask.com",
+ L"http://de.ask.com/favicon.ico",
+ L"http://de.ask.com/web?q={searchTerms}",
+ "UTF-8",
+ L"http://ss.de.ask.com/query?q={searchTerms}&li=ff",
+ 4,
+};
+
+const PrepopulatedEngine ask_es = {
+ L"Ask.com Espa" L"\x00f1" L"a",
+ L"es.ask.com",
+ L"http://es.ask.com/favicon.ico",
+ L"http://es.ask.com/web?q={searchTerms}",
+ "UTF-8",
+ L"http://ss.es.ask.com/query?q={searchTerms}&li=ff",
+ 4,
+};
+
+const PrepopulatedEngine ask_it = {
+ L"Ask.com Italia",
+ L"it.ask.com",
+ L"http://it.ask.com/favicon.ico",
+ L"http://it.ask.com/web?q={searchTerms}",
+ "UTF-8",
+ L"http://ss.it.ask.com/query?q={searchTerms}&li=ff",
+ 4,
+};
+
+const PrepopulatedEngine ask_uk = {
+ L"Ask.com UK",
+ L"uk.ask.com",
+ L"http://uk.ask.com/favicon.ico",
+ L"http://uk.ask.com/web?q={searchTerms}",
+ "UTF-8",
+ L"http://ss.uk.ask.com/query?q={searchTerms}&li=ff",
+ 4,
+};
+
+const PrepopulatedEngine atlas_cz = {
+ L"Atlas",
+ L"atlas.cz",
+ L"http://img.atlas.cz/favicon.ico",
+ L"http://search.atlas.cz/?q={searchTerms}",
+ "windows-1250",
+ NULL,
+ 27,
+};
+
+const PrepopulatedEngine atlas_sk = {
+ L"ATLAS.SK",
+ L"atlas.sk",
+ L"http://www.atlas.sk/images/favicon.ico",
+ L"http://hladaj.atlas.sk/fulltext/?phrase={searchTerms}",
+ "UTF-8",
+ NULL,
+ 27,
+};
+
+const PrepopulatedEngine baidu = {
+ L"\x767e\x5ea6",
+ L"baidu.com",
+ L"http://www.baidu.com/favicon.ico",
+ L"http://www.baidu.com/s?wd={searchTerms}",
+ "GB2312",
+ NULL,
+ 21,
+};
+
+const PrepopulatedEngine biglobe = {
+ L"BIGLOBE",
+ L"biglobe.ne.jp",
+ L"http://cgi.search.biglobe.ne.jp/favicon.ico",
+ L"http://cgi.search.biglobe.ne.jp/cgi-bin/search2-b?q={searchTerms}",
+ "Shift_JIS",
+ NULL,
+ 64,
+};
+
+const PrepopulatedEngine bigmir = {
+ L"bigmir)net",
+ L"bigmir.net",
+ L"http://i.bigmir.net/favicon.ico",
+ L"http://search.bigmir.net/index.php?q={searchTerms}",
+ "windows-1251",
+ NULL,
+ 33,
+};
+
+const PrepopulatedEngine bluewin = {
+ L"Bluewin",
+ L"search.bluewin.ch",
+ L"http://search.bluewin.ch/favicon.ico",
+ L"http://search.bluewin.ch/bw/search/web/de/result.jsp?query={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 52,
+};
+
+const PrepopulatedEngine centrum_cz = {
+ L"Centrum.cz",
+ L"centrum.cz",
+ L"http://img.centrum.cz/6/vy2/o/favicon.ico",
+ L"http://search.centrum.cz/index.php?charset={inputEncoding}&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 26,
+};
+
+const PrepopulatedEngine centrum_sk = {
+ L"Centrum.sk",
+ L"centrum.sk",
+ L"http://img.centrum.sk/4/favicon.ico",
+ L"http://search.centrum.sk/index.php?charset={inputEncoding}&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 26,
+};
+
+const PrepopulatedEngine conexcol = {
+ L"Conexcol.com",
+ L"conexcol.com",
+ L"http://www.conexcol.com/favicon.ico",
+ L"http://buscar.conexcol.com/cgi-ps/busqueda.cgi?query={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 91,
+};
+
+const PrepopulatedEngine daum = {
+ L"Daum",
+ L"daum.net",
+ L"http://search.daum.net/favicon.ico",
+ L"http://search.daum.net/search?q={searchTerms}",
+ "EUC-KR",
+ L"http://sug.search.daum.net/search_nsuggest?mod=fxjson&q={searchTerms}",
+ 68,
+};
+
+const PrepopulatedEngine delfi_ee = {
+ L"DELFI",
+ L"delfi.ee",
+ L"http://g.delfi.ee/s/search.png",
+ L"http://otsing.delfi.ee/i.php?q={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 45,
+};
+
+const PrepopulatedEngine delfi_lt = {
+ L"DELFI",
+ L"delfi.lt",
+ L"http://search.delfi.lt/img/favicon.png",
+ L"http://search.delfi.lt/search.php?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 45,
+};
+
+const PrepopulatedEngine delfi_lv = {
+ L"DELFI",
+ L"delfi.lv",
+ L"http://smart.delfi.lv/img/smart_search.png",
+ L"http://smart.delfi.lv/i.php?enc={inputEncoding}&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 45,
+};
+
+const PrepopulatedEngine embla = {
+ L"Embla",
+ L"embla.is",
+ L"http://embla.is/favicon.ico",
+ L"http://embla.is/mm/embla/?s={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 60,
+};
+
+const PrepopulatedEngine empas = {
+ L"\xc5e0\xd30c\xc2a4",
+ L"empas.com",
+ L"http://search.empas.com/favicon.ico",
+ L"http://search.empas.com/search/all.html?q={searchTerms}",
+ "EUC-KR",
+ // http://www.empas.com/ac/do.tsp?q={searchTerms}
+ // returns non-Firefox JSON. searchTerms needs to be in Java notation
+ // (\uAC00\uAC01).
+ NULL,
+ 70,
+};
+
+const PrepopulatedEngine eniro_dk = {
+ L"Eniro",
+ L"eniro.dk",
+ L"http://eniro.dk/favicon.ico",
+ L"http://eniro.dk/query?search_word={searchTerms}&what=web_local",
+ "ISO-8859-1",
+ NULL,
+ 29,
+};
+
+const PrepopulatedEngine eniro_fi = {
+ L"Eniro",
+ L"eniro.fi",
+ L"http://eniro.fi/favicon.ico",
+ L"http://eniro.fi/query?search_word={searchTerms}&what=web_local",
+ "ISO-8859-1",
+ NULL,
+ 29,
+};
+
+const PrepopulatedEngine eniro_se = {
+ L"Eniro",
+ L"eniro.se",
+ L"http://eniro.se/favicon.ico",
+ L"http://eniro.se/query?search_word={searchTerms}&what=web_local",
+ "ISO-8859-1",
+ NULL,
+ 29,
+};
+
+const PrepopulatedEngine finna = {
+ L"FINNA",
+ L"finna.is",
+ L"http://finna.is/favicon.ico",
+ L"http://finna.is/WWW_Search/?query={searchTerms}",
+ "UTF-8",
+ NULL,
+ 61,
+};
+
+const PrepopulatedEngine fonecta_02_fi = {
+ L"Fonecta 02.fi",
+ L"www.fi",
+ L"http://www.02.fi/img/favicon.ico",
+ L"http://www.02.fi/haku/{searchTerms}",
+ "UTF-8",
+ NULL,
+ 46,
+};
+
+const PrepopulatedEngine forthnet = {
+ L"Forthnet",
+ L"forthnet.gr",
+ L"http://search.forthnet.gr/favicon.ico",
+ L"http://search.forthnet.gr/cgi-bin/query?mss=search&q={searchTerms}",
+ "windows-1253",
+ NULL,
+ 53,
+};
+
+const PrepopulatedEngine gigabusca = {
+ L"GiGaBusca",
+ L"gigabusca.com.br",
+ L"http://www.gigabusca.com.br/favicon.ico",
+ L"http://www.gigabusca.com.br/buscar.php?query={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 81,
+};
+
+const PrepopulatedEngine go = {
+ L"GO.com",
+ L"go.com",
+ L"http://search.yahoo.com/favicon.ico",
+ L"http://search.yahoo.com/search?ei={inputEncoding}&p={searchTerms}&"
+ L"fr=hsusgo1",
+ "ISO-8859-1",
+ NULL,
+ 40,
+};
+
+const PrepopulatedEngine goo = {
+ L"goo",
+ L"goo.ne.jp",
+ L"http://goo.ne.jp/gooicon.ico",
+ L"http://search.goo.ne.jp/web.jsp?MT={searchTerms}&IE={inputEncoding}",
+ "UTF-8",
+ NULL,
+ 92,
+};
+
+const PrepopulatedEngine google = {
+ L"Google",
+ NULL,
+ L"http://www.google.com/favicon.ico",
+ L"{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}"
+ L"{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&"
+ L"q={searchTerms}",
+ "UTF-8",
+ L"{google:baseSuggestURL}search?client=chrome&output=chrome&hl={language}&"
+ L"q={searchTerms}",
+ 1,
+};
+
+const PrepopulatedEngine guruji = {
+ L"guruji",
+ L"guruji.com",
+ L"http://guruji.com/favicon.ico",
+ L"http://guruji.com/search?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 38,
+};
+
+const PrepopulatedEngine iafrica = {
+ L"iafrica.com",
+ L"iafrica.com",
+ NULL,
+ L"http://search.iafrica.com/search?q={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 43,
+};
+
+const PrepopulatedEngine ilse = {
+ L"Ilse",
+ L"ilse.nl",
+ L"http://search.ilse.nl/images/favicon.ico",
+ L"http://search.ilse.nl/web?search_for={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 30,
+};
+
+const PrepopulatedEngine in = {
+ L"in.gr",
+ L"in.gr",
+ L"http://www.in.gr/favicon.ico",
+ L"http://find.in.gr/result.asp?q={searchTerms}",
+ "ISO-8859-7",
+ NULL,
+ 54,
+};
+
+const PrepopulatedEngine jabse = {
+ L"Jabse",
+ L"jabse.com",
+ L"http://www.jabse.com/favicon.ico",
+ L"http://www.jabse.com/searchmachine.php?query={searchTerms}",
+ "UTF-8",
+ NULL,
+ 19,
+};
+
+const PrepopulatedEngine jamaicalive = {
+ L"JamaicaLive",
+ L"jalive.com.jm",
+ L"http://jalive.com.jm/favicon.ico",
+ L"http://jalive.com.jm/search/?mode=allwords&search={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 39,
+};
+
+const PrepopulatedEngine jubii = {
+ L"Jubii",
+ L"jubii.dk",
+ L"http://search.jubii.dk/favicon_jubii.ico",
+ L"http://search.jubii.dk/cgi-bin/pursuit?query={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 28,
+};
+
+const PrepopulatedEngine krstarica = {
+ L"Krstarica",
+ L"krstarica.rs",
+ L"http://pretraga.krstarica.com/favicon.ico",
+ L"http://pretraga.krstarica.com/index.php?q={searchTerms}",
+ "windows-1250",
+ NULL,
+ 84,
+};
+
+const PrepopulatedEngine kvasir = {
+ L"Kvasir",
+ L"kvasir.no",
+ L"http://www.kvasir.no/img/favicon.ico",
+ L"http://www.kvasir.no/nettsok/searchResult.html?searchExpr={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 73,
+};
+
+const PrepopulatedEngine latne = {
+ L"LATNE",
+ L"latne.lv",
+ L"http://latne.lv/favicon.ico",
+ L"http://latne.lv/siets.php?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 71,
+};
+
+const PrepopulatedEngine leit = {
+ L"leit.is",
+ L"leit.is",
+ L"http://leit.is/leit.ico",
+ L"http://leit.is/query.aspx?qt={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 59,
+};
+
+const PrepopulatedEngine libero = {
+ L"Libero",
+ L"libero.it",
+ L"http://arianna.libero.it/favicon.ico",
+ L"http://arianna.libero.it/search/abin/integrata.cgi?query={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 63,
+};
+
+const PrepopulatedEngine live = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_ar_XA = {
+ L"Live Search (\x0627\x0644\x0639\x0631\x0628\x064a\x0629)",
+ L"", // "live.com" is already taken by live_en_XA (see comment on ID below).
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?setlang=ar-XA&mkt=ar-XA&"
+ L"q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 7, // Can't be 3 as this has to appear in the Arabian countries' lists
+ // alongside live_en_XA.
+};
+
+const PrepopulatedEngine live_bg_BG = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=bg-BG&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_cs_CZ = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=cs-CZ&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_el_GR = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=el-GR&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_en_ID = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=en_ID&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_en_NZ = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=en-NZ&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_en_US = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?setlang=en-US&mkt=en-US&"
+ L"q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_en_XA = {
+ L"Live Search (English)",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?setlang=en-XA&mkt=en-XA&"
+ L"q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_et_EE = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=et-EE&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_hr_HR = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=hr-HR&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_hu_HU = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=hu-HU&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_it_IT = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=it-IT&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_lt_LT = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=lt-LT&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_pl_PL = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=pl-PL&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_pt_PT = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=pt-PT&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_ro_RO = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=ro-RO&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_ru_RU = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=ru-RU&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_sk_SK = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=sk-SK&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_sl_SI = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=sl-SI&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine live_th_TH = {
+ L"Live Search",
+ L"live.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=th-TH&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine lycos_es = {
+ L"Lycos Espa" L"\x00f1" L"a",
+ L"lycos.es",
+ L"http://buscador.lycos.es/favicon.ico",
+ L"http://buscador.lycos.es/cgi-bin/pursuit?query={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 34,
+};
+
+const PrepopulatedEngine lycos_nl = {
+ L"Lycos",
+ L"lycos.nl",
+ L"http://zoek.lycos.nl/favicon.ico",
+ L"http://zoek.lycos.nl/cgi-bin/pursuit?query={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 34,
+};
+
+const PrepopulatedEngine mail_ru = {
+ L"@MAIL.RU",
+ L"mail.ru",
+ L"http://img.go.mail.ru/favicon.ico",
+ L"http://go.mail.ru/search?q={searchTerms}",
+ "windows-1251",
+ NULL,
+ 83,
+};
+
+const PrepopulatedEngine maktoob = {
+ L"\x0645\x0643\x062a\x0648\x0628",
+ L"maktoob.com",
+ L"http://www.maktoob.com/favicon.ico",
+ L"http://www.maktoob.com/searchResult.php?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 13,
+};
+
+const PrepopulatedEngine masrawy = {
+ L"\x0645\x0635\x0631\x0627\x0648\x064a",
+ L"masrawy.com",
+ L"http://www.masrawy.com/new/images/masrawy.ico",
+ L"http://masrawy.com/new/search.aspx?sr={searchTerms}",
+ "windows-1256",
+ NULL,
+ 14,
+};
+
+const PrepopulatedEngine matkurja = {
+ L"Mat'Kurja",
+ L"matkurja.com",
+ L"http://matkurja.com/favicon.ico",
+ L"http://matkurja.com/si/iskalnik/?q={searchTerms}&search_source=directory",
+ "ISO-8859-2",
+ NULL,
+ 88,
+};
+
+const PrepopulatedEngine meta = {
+ L"<META>",
+ L"meta.ua",
+ L"http://meta.ua/favicon.ico",
+ L"http://meta.ua/search.asp?q={searchTerms}",
+ "windows-1251",
+ L"http://meta.ua/suggestions/?output=fxjson&oe=utf-8&q={searchTerms}",
+ 102,
+};
+
+const PrepopulatedEngine msn = {
+ L"MSN",
+ L"msn.com",
+ L"http://search.msn.com/s/wlflag.ico",
+ L"http://search.msn.com/results.aspx?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_ar_XA = {
+ L"MSN (\x0627\x0644\x0639\x0631\x0628\x064a\x0629)",
+ L"", // "arabia.msn.com" is already taken by msn_en_XA (see comment on ID
+ // below).
+ L"http://search.msn.com/s/wlflag.ico",
+ L"http://search.msn.com/results.aspx?setlang=ar-XA&mkt=ar-XA&"
+ L"q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 7, // Can't be 3 as this has to appear in the Arabian countries' lists
+ // alongside msn_en_XA.
+};
+
+const PrepopulatedEngine msn_da_DK = {
+ L"MSN Danmark",
+ L"dk.msn.com",
+ L"http://search.msn.dk/s/wlflag.ico",
+ L"http://search.msn.dk/results.aspx?mkt=da-DK&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_de_AT = {
+ L"MSN \x00d6sterreich",
+ L"at.msn.com",
+ L"http://search.msn.at/s/wlflag.ico",
+ L"http://search.msn.at/results.aspx?mkt=de-AT&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_de_CH = {
+ L"MSN Schweiz (Deutsch)",
+ L"ch.msn.com",
+ L"http://search.msn.ch/s/wlflag.ico",
+ L"http://search.msn.ch/results.aspx?setlang=de-CH&mkt=de-CH&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_de_DE = {
+ L"MSN",
+ L"de.msn.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=de-DE&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_AU = {
+ L"ninemsn.com.au",
+ L"ninemsn.com.au",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=en-AU&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_CA = {
+ L"Sympatico / MSN (English)",
+ L"sympatico.msn.ca",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?setlang=en-CA&mkt=en-CA&"
+ L"q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_GB = {
+ L"MSN UK",
+ L"uk.msn.com",
+ L"http://search.msn.co.uk/s/wlflag.ico",
+ L"http://search.msn.co.uk/results.aspx?mkt=en-GB&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_IE = {
+ L"MSN IE",
+ L"ie.msn.com",
+ L"http://search.msn.ie/s/wlflag.ico",
+ L"http://search.msn.ie/results.aspx?mkt=en-IE&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_IN = {
+ L"MSN India",
+ L"in.msn.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=en-IN&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_MY = {
+ L"MSN Malaysia",
+ L"malaysia.msn.com",
+ L"http://search.msn.com.my/s/wlflag.ico",
+ L"http://search.msn.com.my/results.aspx?mkt=en-MY&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_PH = {
+ L"MSN Philippines",
+ L"ph.msn.com",
+ L"http://search.msn.com.ph/s/wlflag.ico",
+ L"http://search.msn.com.ph/results.aspx?mkt=en-PH&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_SG = {
+ L"MSN Singapore",
+ L"sg.msn.com",
+ L"http://search.msn.com.sg/s/wlflag.ico",
+ L"http://search.msn.com.sg/results.aspx?mkt=en-SG&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_XA = {
+ L"MSN (English)",
+ L"arabia.msn.com",
+ L"http://search.msn.com/s/wlflag.ico",
+ L"http://search.msn.com/results.aspx?setlang=en-XA&mkt=en-XA&"
+ L"q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_en_ZA = {
+ L"MSN ZA",
+ L"za.msn.com",
+ L"http://search.msn.co.za/s/wlflag.ico",
+ L"http://search.msn.co.za/results.aspx?mkt=en-ZA&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_es_AR = {
+ L"MSN Argentina",
+ L"ar.msn.com",
+ L"http://search.msn.com/s/wlflag.ico",
+ L"http://search.msn.com/results.aspx?mkt=es-AR&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_es_CL = {
+ L"MSN Chile",
+ L"cl.msn.com",
+ L"http://search.msn.com/s/wlflag.ico",
+ L"http://search.msn.com/results.aspx?mkt=es-CL&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_es_CO = {
+ L"MSN Colombia",
+ L"co.msn.com",
+ L"http://search.msn.com/s/wlflag.ico",
+ L"http://search.msn.com/results.aspx?mkt=es-CO&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_es_ES = {
+ L"MSN Espa" L"\x00f1" L"a",
+ L"es.msn.com",
+ L"http://search.msn.es/s/wlflag.ico",
+ L"http://search.msn.es/results.aspx?mkt=es-ES&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_es_MX = {
+ L"Prodigy / MSN",
+ L"prodigy.msn.com",
+ L"http://search.prodigy.msn.com/s/wlflag.ico",
+ L"http://search.prodigy.msn.com/results.aspx?mkt=es-MX&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_es_XL = {
+ L"MSN Latinoam\x00e9rica",
+ L"latam.msn.com",
+ L"http://search.msn.com/s/wlflag.ico",
+ L"http://search.msn.com/results.aspx?mkt=es-XL&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_fi_FI = {
+ L"MSN",
+ L"fi.msn.com",
+ L"http://search.msn.fi/s/wlflag.ico",
+ L"http://search.msn.fi/results.aspx?mkt=fi-FI&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_fr_BE = {
+ L"MSN Belgique (Fran" L"\x00e7" L"ais)",
+ L"", // "be.msn.com" is already taken by msn_nl_BE (see comment on ID below).
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?setlang=fr-BE&mkt=fr-BE&"
+ L"q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 8, // Can't be 3 as this has to appear in the Belgium list alongside
+ // msn_nl_BE.
+};
+
+const PrepopulatedEngine msn_fr_CA = {
+ L"Sympatico / MSN (Fran" L"\x00e7" L"ais)",
+ L"", // "sympatico.msn.ca" is already taken by msn_en_CA (see comment on ID
+ // below).
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?setlang=fr-CA&mkt=fr-CA&"
+ L"q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 9, // Can't be 3 as this has to appear in the Canada list alongside
+ // msn_en_CA.
+};
+
+const PrepopulatedEngine msn_fr_CH = {
+ L"MSN Suisse (Fran" L"\x00e7" L"ais)",
+ L"", // "ch.msn.com" is already taken by msn_de_CH (see comment on ID below).
+ L"http://search.msn.ch/s/wlflag.ico",
+ L"http://search.msn.ch/results.aspx?setlang=fr-CH&mkt=fr-CH&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 10, // Can't be 3 as this has to appear in the Switzerland list alongside
+ // msn_de_CH.
+};
+
+const PrepopulatedEngine msn_fr_FR = {
+ L"MSN France",
+ L"fr.msn.com",
+ L"http://search.msn.fr/s/wlflag.ico",
+ L"http://search.msn.fr/results.aspx?mkt=fr-FR&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_he_IL = {
+ L"msn.co.il",
+ L"msn.co.il",
+ L"http://msn.co.il/favicon.ico",
+ L"http://search.msn.co.il/Search.aspx?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_ja_JP = {
+ L"MSN Japan",
+ L"jp.msn.com",
+ L"http://search.msn.co.jp/s/wlflag.ico",
+ L"http://search.msn.co.jp/results.aspx?mkt=ja-JP&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_nb_NO = {
+ L"MSN Norge",
+ L"no.msn.com",
+ L"http://search.msn.no/s/wlflag.ico",
+ L"http://search.msn.no/results.aspx?mkt=nb-NO&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_nl_BE = {
+ L"MSN (Nederlandstalige)",
+ L"be.msn.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?setlang=nl-BE&mkt=nl-BE&"
+ L"q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_nl_NL = {
+ L"MSN.nl",
+ L"nl.msn.com",
+ L"http://search.msn.nl/s/wlflag.ico",
+ L"http://search.msn.nl/results.aspx?mkt=nl-NL&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_pt_BR = {
+ L"MSN Brasil",
+ L"br.msn.com",
+ L"http://search.live.com/s/wlflag.ico",
+ L"http://search.live.com/results.aspx?mkt=pt-BR&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_sv_SE = {
+ L"MSN",
+ L"se.msn.com",
+ L"http://search.msn.se/s/wlflag.ico",
+ L"http://search.msn.se/results.aspx?mkt=pv-SE&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_tr_TR = {
+ L"MSN T\x00fckiye'ye",
+ L"tr.msn.com",
+ L"http://search.msn.com.tr/s/wlflag.ico",
+ L"http://search.msn.com.tr/results.aspx?mkt=tr-TR&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine msn_zh_HK = {
+ L"MSN Hong Kong",
+ L"hk.msn.com",
+ L"http://search.msn.com.hk/s/wlflag.ico",
+ L"http://search.msn.com.hk/results.aspx?mkt=zh-HK&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 3,
+};
+
+const PrepopulatedEngine mweb = {
+ L"MWEB",
+ L"mweb.co.za",
+ L"http://mweb.co.za/favicon.ico",
+ L"http://search.mweb.co.za/search?&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 42,
+};
+
+const PrepopulatedEngine mynet = {
+ L"MYNET",
+ L"mynet.com",
+ L"http://img.mynet.com/mynetfavori.ico",
+ L"http://arama.mynet.com/search.aspx?q={searchTerms}&pg=q",
+ "windows-1254",
+ NULL,
+ 101,
+};
+
+const PrepopulatedEngine mywebsearch = {
+ L"mywebsearch",
+ L"mywebsearch.com",
+ NULL,
+ L"http://search.mywebsearch.com/mywebsearch/AJmain.jhtml?"
+ L"searchfor={searchTerms}",
+ "UTF-8",
+ NULL,
+ 97,
+};
+
+const PrepopulatedEngine najdi = {
+ L"Najdi.si",
+ L"najdi.si",
+ L"http://www.najdi.si/master/favicon.ico",
+ L"http://www.najdi.si/search.jsp?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 87,
+};
+
+const PrepopulatedEngine nana10 = {
+ L"\x05e0\x05e2\x05e0\x05e2 10",
+ L"nana10.co.il",
+ L"http://f.nau.co.il/Common/Includes/Favicon.ico",
+ L"http://index.nana10.co.il/search.asp?q={searchTerms}",
+ "windows-1255",
+ NULL,
+ 56,
+};
+
+const PrepopulatedEngine nate = {
+ L"\xb124\xc774\xd2b8\xb2f7\xcef4",
+ L"nate.com",
+ L"http://nate.search.empas.com/favicon.ico",
+ L"http://nate.search.empas.com/search/all.html?q={searchTerms}",
+ "EUC-KR",
+ NULL,
+ 69,
+};
+
+const PrepopulatedEngine naver = {
+ L"\xb124\xc774\xbc84",
+ L"naver.com",
+ L"http://search.naver.com/favicon.ico",
+ L"http://search.naver.com/search.naver?ie={inputEncoding}"
+ L"&query={searchTerms}",
+ "UTF-8",
+ L"http://ac.search.naver.com/autocompl?m=s&ie={inputEncoding}&oe=utf-8&"
+ L"q={searchTerms}",
+ 67,
+};
+
+const PrepopulatedEngine neti = {
+ L"NETI",
+ L"neti.ee",
+ L"http://www.neti.ee/favicon.ico",
+ L"http://www.neti.ee/cgi-bin/otsing?query={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 44,
+};
+
+const PrepopulatedEngine netindex = {
+ L"NetINDEX",
+ L"netindex.pt",
+ L"http://www.netindex.pt/favicon.ico",
+ L"http://www.netindex.pt/cgi-bin/index.cgi?question={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 78,
+};
+
+const PrepopulatedEngine nifty = {
+ L"@nifty",
+ L"nifty.com",
+ L"http://www.nifty.com/favicon.ico",
+ L"http://search.nifty.com/cgi-bin/search.cgi?Text={searchTerms}",
+ "Shift_JIS",
+ NULL,
+ 65,
+};
+
+const PrepopulatedEngine ohperu = {
+ L"Oh Per\x00fa",
+ L"ohperu.com",
+ NULL,
+ L"http://www.google.com.pe/custom?q={searchTerms}&"
+ L"client=pub-1950414869696311&ie={inputEncoding}&cof=GALT%3A%23000000"
+ L"%3BGL%3A1%3BDIV%3A%23FFFFFF%3BVLC%3A000000%3BAH%3Acenter%3BBGC%3AFFFFFF"
+ L"%3BLBGC%3AFFFFFF%3BALC%3A000000%3BLC%3A000000%3BT%3A000000%3BGFNT"
+ L"%3A000000%3BGIMP%3A000000%3BLH%3A50%3BLW%3A142%3BL%3Ahttp%3A%2F%2F"
+ L"www.ohperu.com%2Fohperu-logo-inv2.gif%3BS%3Ahttp%3A%2F%2Fwww.ohperu.com"
+ L"%3BFORID%3A1",
+ "ISO-8859-1",
+ NULL,
+ 96,
+};
+
+const PrepopulatedEngine ok = {
+ L"OK.hu",
+ L"ok.hu",
+ L"http://ok.hu/gfx/favicon.ico",
+ L"http://ok.hu/katalogus?q={searchTerms}",
+ "ISO-8859-2",
+ NULL,
+ 6,
+};
+
+const PrepopulatedEngine onet = {
+ L"Onet.pl",
+ L"onet.pl",
+ L"http://szukaj.onet.pl/favicon.ico",
+ L"http://szukaj.onet.pl/query.html?qt={searchTerms}",
+ "ISO-8859-2",
+ NULL,
+ 75,
+};
+
+const PrepopulatedEngine orange = {
+ L"Orange",
+ L"orange.fr",
+ L"http://www.orange.fr/favicon.ico",
+ L"http://rws.search.ke.voila.fr/RW/S/opensearch_orange?rdata={searchTerms}",
+ "ISO-8859-1",
+ L"http://search.ke.voila.fr/fr/cmplopensearch/xml/fullxml?"
+ L"rdata={searchTerms}",
+ 48,
+};
+
+const PrepopulatedEngine ozu = {
+ L"OZ\x00da",
+ L"ozu.es",
+ L"http://www.ozu.es/favicon.ico",
+ L"http://buscar.ozu.es/index.php?q={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 98,
+};
+
+const PrepopulatedEngine pogodak_ba = {
+ L"Pogodak!",
+ L"pogodak.ba",
+ L"http://www.pogodak.ba/favicon.ico",
+ L"http://www.pogodak.ba/search.jsp?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 24,
+};
+
+const PrepopulatedEngine pogodak_hr = {
+ L"Pogodak!",
+ L"pogodak.hr",
+ L"http://www.pogodak.hr/favicon.ico",
+ L"http://www.pogodak.hr/search.jsp?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 24,
+};
+
+const PrepopulatedEngine pogodak_rs = {
+ L"Pogodak!",
+ L"pogodak.rs",
+ L"http://www.pogodak.rs/favicon.ico",
+ L"http://www.pogodak.rs/search.jsp?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 24,
+};
+
+const PrepopulatedEngine pogodok = {
+ L"\x041f\x043e\x0433\x043e\x0434\x043e\x043a!",
+ L"pogodok.com.mk",
+ L"http://www.pogodok.com.mk/favicon.ico",
+ L"http://www.pogodok.com.mk/search.jsp?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 24, // Really the same engine as Pogodak, just has a small name change.
+};
+
+const PrepopulatedEngine rambler = {
+ L"Rambler",
+ L"rambler.ru",
+ L"http://www.rambler.ru/favicon.ico",
+ L"http://www.rambler.ru/srch?words={searchTerms}",
+ "windows-1251",
+ NULL,
+ 16,
+};
+
+const PrepopulatedEngine rediff = {
+ L"Rediff",
+ L"rediff.com",
+ L"http://search1.rediff.com/favicon.ico",
+ L"http://search1.rediff.com/dirsrch/default.asp?MT={searchTerms}",
+ "UTF-8",
+ NULL,
+ 37,
+};
+
+const PrepopulatedEngine rednano = {
+ L"Rednano",
+ L"rednano.sg",
+ L"http://rednano.sg/favicon.ico",
+ L"http://rednano.sg/sfe/lwi.action?querystring={searchTerms}",
+ "UTF-8",
+ NULL,
+ 41,
+};
+
+const PrepopulatedEngine sanook = {
+ L"\x0e2a\x0e19\x0e38\x0e01!",
+ L"sanook.com",
+ L"http://search.sanook.com/favicon.ico",
+ L"http://search.sanook.com/search.php?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 100,
+};
+
+const PrepopulatedEngine sapo = {
+ L"SAPO",
+ L"sapo.pt",
+ L"http://imgs.sapo.pt/images/sapo.ico",
+ L"http://pesquisa.sapo.pt/?q={searchTerms}",
+ "UTF-8",
+ L"http://pesquisa.sapo.pt/livesapo?q={searchTerms}",
+ 77,
+};
+
+const PrepopulatedEngine search_ch = {
+ L"search.ch",
+ L"search.ch",
+ L"http://www.search.ch/favicon.ico",
+ L"http://www.search.ch/?q={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 51,
+};
+
+const PrepopulatedEngine sensis = {
+ L"sensis.com.au",
+ L"sensis.com.au",
+ L"http://www.sensis.com.au/favicon.ico",
+ L"http://www.sensis.com.au/search.do?find={searchTerms}",
+ "UTF-8",
+ NULL,
+ 32,
+};
+
+const PrepopulatedEngine sesam = {
+ L"Sesam",
+ L"sesam.no",
+ L"http://sesam.no/images/favicon.gif",
+ L"http://sesam.no/search/?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 74,
+};
+
+const PrepopulatedEngine seznam = {
+ L"Seznam",
+ L"seznam.cz",
+ L"http://1.im.cz/szn/img/favicon.ico",
+ L"http://search.seznam.cz/?q={searchTerms}",
+ "UTF-8",
+ L"http:///suggest.fulltext.seznam.cz/?dict=fulltext_ff&phrase={searchTerms}&"
+ L"encoding={inputEncoding}&response_encoding=utf-8",
+ 25,
+};
+
+const PrepopulatedEngine sogou = {
+ L"\x641c\x72d7",
+ L"sogou.com",
+ L"http://www.sogou.com/favicon.ico",
+ L"http://www.sogou.com/web?query={searchTerms}",
+ "GB2312",
+ NULL,
+ 20,
+};
+
+const PrepopulatedEngine soso = {
+ L"\x641c\x641c",
+ L"soso.com",
+ L"http://www.soso.com/favicon.ico",
+ L"http://www.soso.com/q?w={searchTerms}",
+ "GB2312",
+ NULL,
+ 22,
+};
+
+const PrepopulatedEngine spray = {
+ L"Spray",
+ L"spray.se",
+ L"http://www.eniro.se/favicon.ico",
+ L"http://www.eniro.se/query?ax=spray&search_word={searchTerms}&what=web",
+ "ISO-8859-1",
+ NULL,
+ 99,
+};
+
+const PrepopulatedEngine szm = {
+ L"SZM.sk",
+ L"szm.sk",
+ L"http://szm.sk/favicon.ico",
+ L"http://szm.sk/search/?co=1&q={searchTerms}",
+ "windows-1250",
+ NULL,
+ 86,
+};
+
+const PrepopulatedEngine t_online = {
+ L"T-Online",
+ L"suche.t-online.de",
+ L"http://suche.t-online.de/favicon.ico",
+ L"http://suche.t-online.de/fast-cgi/tsc?sr=chrome&q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 49,
+};
+
+const PrepopulatedEngine tango = {
+ L"Tango",
+ L"tango.hu",
+ L"http://tango.hu/favicon.ico",
+ L"http://tango.hu/search.php?q={searchTerms}",
+ "windows-1250",
+ NULL,
+ 58,
+};
+
+const PrepopulatedEngine tapuz = {
+ L"\x05ea\x05e4\x05d5\x05d6 \x05d0\x05e0\x05e9\x05d9\x05dd",
+ L"tapuz.co.il",
+ L"http://www.tapuz.co.il/favicon.ico",
+ L"http://www.tapuz.co.il/search/search.asp?q={searchTerms}",
+ "windows-1255",
+ NULL,
+ 57,
+};
+
+const PrepopulatedEngine terra_ar = {
+ L"Terra Argentina",
+ L"terra.com.ar",
+ L"http://buscar.terra.com.ar/favicon.ico",
+ L"http://buscar.terra.com.ar/Default.aspx?query={searchTerms}&source=Search",
+ "ISO-8859-1",
+ NULL,
+ 90,
+};
+
+const PrepopulatedEngine terra_ec = {
+ L"Terra Ecuador",
+ L"terra.com.ec",
+ L"http://buscador.terra.com.ec/favicon.ico",
+ L"http://buscador.terra.com.ec/Default.aspx?query={searchTerms}&"
+ L"source=Search",
+ "ISO-8859-1",
+ NULL,
+ 90,
+};
+
+const PrepopulatedEngine terra_es = {
+ L"Terra",
+ L"terra.es",
+ L"http://buscador.terra.es/favicon.ico",
+ L"http://buscador.terra.es/Default.aspx?query={searchTerms}&source=Search",
+ "ISO-8859-1",
+ NULL,
+ 90,
+};
+
+const PrepopulatedEngine terra_mx = {
+ L"Terra",
+ L"terra.com.mx",
+ L"http://buscador.terra.com.mx/favicon.ico",
+ L"http://buscador.terra.com.mx/Default.aspx?query={searchTerms}&"
+ L"source=Search",
+ "ISO-8859-1",
+ NULL,
+ 90,
+};
+
+const PrepopulatedEngine terra_pe = {
+ L"Terra",
+ L"terra.com.pe",
+ L"http://buscador.terra.com.pe/favicon.ico",
+ L"http://buscador.terra.com.pe/Default.aspx?query={searchTerms}&"
+ L"source=Search",
+ "ISO-8859-1",
+ NULL,
+ 90,
+};
+
+const PrepopulatedEngine toile = {
+ L"La Toile du Qu" L"\x00e9" L"bec",
+ L"toile.com",
+ L"http://static.search.canoe.ca/s-toile/img/favicon_toile.ico",
+ L"http://www.toile.com/search?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 36,
+};
+
+const PrepopulatedEngine tut = {
+ L"TUT.BY",
+ L"tut.by",
+ L"http://www.tut.by/favicon.ico",
+ L"http://search.tut.by/?query={searchTerms}",
+ "windows-1251",
+ NULL,
+ 17,
+};
+
+const PrepopulatedEngine uol = {
+ L"UOL Busca",
+ L"busca.uol.com.br",
+ L"http://busca.uol.com.br/favicon.ico",
+ L"http://busca.uol.com.br/www/index.html?q={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 82,
+};
+
+const PrepopulatedEngine vinden = {
+ L"Vinden.nl",
+ L"vinden.nl",
+ L"http://www.vinden.nl/favicon.ico",
+ L"http://www.vinden.nl/?q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 31,
+};
+
+const PrepopulatedEngine virgilio = {
+ L"Virgilio",
+ L"virgilio.alice.it",
+ L"http://ricerca.alice.it/favicon.ico",
+ L"http://ricerca.alice.it/ricerca?qs={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 62,
+};
+
+const PrepopulatedEngine voila = {
+ L"Voila",
+ L"voila.fr",
+ L"http://search.ke.voila.fr/favicon.ico",
+ L"http://rws.search.ke.voila.fr/RW/S/opensearch_voila?rdata={searchTerms}",
+ "ISO-8859-1",
+ L"http://search.ke.voila.fr/fr/cmplopensearch/xml/fullxml?"
+ L"rdata={searchTerms}",
+ 47,
+};
+
+const PrepopulatedEngine walla = {
+ L"\x05d5\x05d5\x05d0\x05dc\x05d4!",
+ L"walla.co.il",
+ L"http://www.walla.co.il/favicon.ico",
+ L"http://search.walla.co.il/?e=hew&q={searchTerms}",
+ "windows-1255",
+ NULL,
+ 55,
+};
+
+const PrepopulatedEngine web_de = {
+ L"WEB.DE",
+ L"web.de",
+ L"http://img.ui-portal.de/search/img/webde/favicon.ico",
+ L"http://suche.web.de/search/web/?su={searchTerms}",
+ "ISO-8859-1",
+ NULL,
+ 50,
+};
+
+const PrepopulatedEngine wp = {
+ L"Wirtualna Polska",
+ L"wp.pl",
+ L"http://szukaj.wp.pl/favicon.ico",
+ L"http://szukaj.wp.pl/szukaj.html?szukaj={searchTerms}",
+ "ISO-8859-2",
+ NULL,
+ 76,
+};
+
+const PrepopulatedEngine yagua = {
+ L"Yagua.com",
+ L"yagua.com",
+ L"http://yagua.paraguay.com/favicon.ico",
+ L"http://yagua.paraguay.com/buscador.php?q={searchTerms}&cs={inputEncoding}",
+ "ISO-8859-1",
+ NULL,
+ 94,
+};
+
+const PrepopulatedEngine yahoo = {
+ L"Yahoo!",
+ L"yahoo.com",
+ L"http://search.yahoo.com/favicon.ico",
+ L"http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}",
+ "UTF-8",
+ L"http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}",
+ 2,
+};
+
+// For regional Yahoo variants without region-specific suggestion service,
+// suggestion is disabled. For some of them, we might consider
+// using a fallback (e.g. de for at/ch, ca or fr for qc, en for nl, no, hk).
+const PrepopulatedEngine yahoo_ar = {
+ L"Yahoo! Argentina",
+ L"ar.yahoo.com",
+ L"http://ar.search.yahoo.com/favicon.ico",
+ L"http://ar.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://ar-sayt.ff.search.yahoo.com/gossip-ar-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_at = {
+ L"Yahoo! Suche",
+ L"at.yahoo.com",
+ L"http://at.search.yahoo.com/favicon.ico",
+ L"http://at.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_au = {
+ L"Yahoo!7",
+ L"au.yahoo.com",
+ L"http://au.search.yahoo.com/favicon.ico",
+ L"http://au.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://aue-sayt.ff.search.yahoo.com/gossip-au-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_br = {
+ L"Yahoo! Brasil",
+ L"br.yahoo.com",
+ L"http://br.search.yahoo.com/favicon.ico",
+ L"http://br.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://br-sayt.ff.search.yahoo.com/gossip-br-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_ca = {
+ L"Yahoo! Canada",
+ L"ca.yahoo.com",
+ L"http://ca.search.yahoo.com/favicon.ico",
+ L"http://ca.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://gossip.ca.yahoo.com/gossip-ca-sayt?output=fxjsonp&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_ch = {
+ L"Yahoo! Suche",
+ L"ch.yahoo.com",
+ L"http://ch.search.yahoo.com/favicon.ico",
+ L"http://ch.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_cl = {
+ L"Yahoo! Chile",
+ L"cl.yahoo.com",
+ L"http://cl.search.yahoo.com/favicon.ico",
+ L"http://cl.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_cn = {
+ L"\x4e2d\x56fd\x96c5\x864e",
+ L"cn.yahoo.com",
+ L"http://search.cn.yahoo.com/favicon.ico",
+ L"http://search.cn.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "GB2312",
+ // http://cn.yahoo.com/cnsuggestion/suggestion.inc.php?of=fxjson&query=
+ // returns in a proprietary format ('|' delimeted word list).
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_co = {
+ L"Yahoo! Colombia",
+ L"co.yahoo.com",
+ L"http://co.search.yahoo.com/favicon.ico",
+ L"http://co.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_de = {
+ L"Yahoo! Deutschland",
+ L"de.yahoo.com",
+ L"http://de.search.yahoo.com/favicon.ico",
+ L"http://de.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://de-sayt.ff.search.yahoo.com/gossip-de-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_dk = {
+ L"Yahoo! Danmark",
+ L"dk.yahoo.com",
+ L"http://dk.search.yahoo.com/favicon.ico",
+ L"http://dk.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_es = {
+ L"Yahoo! Espa" L"\x00f1" L"a",
+ L"es.yahoo.com",
+ L"http://es.search.yahoo.com/favicon.ico",
+ L"http://es.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://es-sayt.ff.search.yahoo.com/gossip-es-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_fi = {
+ L"Yahoo!-haku",
+ L"fi.yahoo.com",
+ L"http://fi.search.yahoo.com/favicon.ico",
+ L"http://fi.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_fr = {
+ L"Yahoo! France",
+ L"fr.yahoo.com",
+ L"http://fr.search.yahoo.com/favicon.ico",
+ L"http://fr.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://fr-sayt.ff.search.yahoo.com/gossip-fr-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_hk = {
+ L"Yahoo! Hong Kong",
+ L"hk.yahoo.com",
+ L"http://hk.search.yahoo.com/favicon.ico",
+ L"http://hk.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ // http://history.hk.search.yahoo.com/ac/ac_msearch.php?query={searchTerms}
+ // returns a JSON with key-value pairs. Setting parameters (ot, of, output)
+ // to fxjson, json, or js doesn't help.
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_id = {
+ L"Yahoo! Indonesia",
+ L"id.yahoo.com",
+ L"http://id.search.yahoo.com/favicon.ico",
+ L"http://id.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://id-sayt.ff.search.yahoo.com/gossip-id-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_in = {
+ L"Yahoo! India",
+ L"in.yahoo.com",
+ L"http://in.search.yahoo.com/favicon.ico",
+ L"http://in.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://in-sayt.ff.search.yahoo.com/gossip-in-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_it = {
+ L"Yahoo! Italia",
+ L"it.yahoo.com",
+ L"http://it.search.yahoo.com/favicon.ico",
+ L"http://it.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://it-sayt.ff.search.yahoo.com/gossip-it-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_jp = {
+ L"Yahoo! JAPAN",
+ L"yahoo.co.jp",
+ L"http://search.yahoo.co.jp/favicon.ico",
+ L"http://search.yahoo.co.jp/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_kr = {
+ L"\xc57c\xd6c4! \xcf54\xb9ac\xc544",
+ L"kr.yahoo.com",
+ L"http://kr.search.yahoo.com/favicon.ico",
+ L"http://kr.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://kr.atc.search.yahoo.com/atcx.php?property=main&ot=fxjson&"
+ L"ei=utf8&eo=utf8&command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_malaysia = {
+ L"Yahoo! Malaysia",
+ L"malaysia.yahoo.com",
+ L"http://malaysia.search.yahoo.com/favicon.ico",
+ L"http://malaysia.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://my-sayt.ff.search.yahoo.com/gossip-my-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_mx = {
+ L"Yahoo! M\x00e9xico",
+ L"mx.yahoo.com",
+ L"http://mx.search.yahoo.com/favicon.ico",
+ L"http://mx.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://gossip.mx.yahoo.com/gossip-mx-sayt?output=fxjsonp&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_nl = {
+ L"Yahoo! Nederland",
+ L"nl.yahoo.com",
+ L"http://nl.search.yahoo.com/favicon.ico",
+ L"http://nl.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_no = {
+ L"Yahoo! Norge",
+ L"no.yahoo.com",
+ L"http://no.search.yahoo.com/favicon.ico",
+ L"http://no.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_nz = {
+ L"Yahoo!Xtra",
+ L"nz.yahoo.com",
+ L"http://nz.search.yahoo.com/favicon.ico",
+ L"http://nz.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://aue-sayt.ff.search.yahoo.com/gossip-nz-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_pe = {
+ L"Yahoo! Per\x00fa",
+ L"pe.yahoo.com",
+ L"http://pe.search.yahoo.com/favicon.ico",
+ L"http://pe.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_ph = {
+ L"Yahoo! Philippines",
+ L"ph.yahoo.com",
+ L"http://ph.search.yahoo.com/favicon.ico",
+ L"http://ph.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://ph-sayt.ff.search.yahoo.com/gossip-ph-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_qc = {
+ L"Yahoo! Qu" L"\x00e9" L"bec",
+ L"qc.yahoo.com",
+ L"http://qc.search.yahoo.com/favicon.ico",
+ L"http://qc.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ NULL,
+ 5, // Can't be 2 as this has to appear in the Canada list alongside yahoo_ca.
+};
+
+const PrepopulatedEngine yahoo_ru = {
+ L"Yahoo! \x043f\x043e-\x0440\x0443\x0441\x0441\x043a\x0438",
+ L"ru.yahoo.com",
+ L"http://ru.search.yahoo.com/favicon.ico",
+ L"http://ru.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_sg = {
+ L"Yahoo! Singapore",
+ L"sg.yahoo.com",
+ L"http://sg.search.yahoo.com/favicon.ico",
+ L"http://sg.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://sg-sayt.ff.search.yahoo.com/gossip-sg-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_th = {
+ L"Yahoo! \x0e1b\x0e23\x0e30\x0e40\x0e17\x0e28\x0e44\x0e17\x0e22",
+ L"th.yahoo.com",
+ L"http://th.search.yahoo.com/favicon.ico",
+ L"http://th.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://th-sayt.ff.search.yahoo.com/gossip-th-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_tw = {
+ L"Yahoo!\x5947\x6469",
+ L"tw.yahoo.com",
+ L"http://tw.search.yahoo.com/favicon.ico",
+ L"http://tw.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ // "http://tw.yahoo.com/ac/ac_search.php?eo=utf8&of=js&prop=web&query="
+ // returns a JSON file prepended with 'fxjson={'.
+ NULL,
+ 2,
+};
+
+const PrepopulatedEngine yahoo_uk = {
+ L"Yahoo! UK & Ireland",
+ L"uk.yahoo.com",
+ L"http://uk.search.yahoo.com/favicon.ico",
+ L"http://uk.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://uk-sayt.ff.search.yahoo.com/gossip-uk-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_ve = {
+ L"Yahoo! Venezuela",
+ L"ve.yahoo.com",
+ L"http://ve.search.yahoo.com/favicon.ico",
+ L"http://ve.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yahoo_vn = {
+ L"Yahoo! Vi\x1ec7t Nam",
+ L"vn.yahoo.com",
+ L"http://vn.search.yahoo.com/favicon.ico",
+ L"http://vn.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ L"p={searchTerms}",
+ "UTF-8",
+ L"http://vn-sayt.ff.search.yahoo.com/gossip-vn-sayt?output=fxjson&"
+ L"command={searchTerms}",
+ 2,
+};
+
+const PrepopulatedEngine yam = {
+ L"\u5929\u7a7a",
+ L"yam.com",
+ L"http://www.yam.com/i/8/sky.ico",
+ L"http://search.yam.com/wps?k={searchTerms}",
+ "Big5",
+ NULL,
+ 23,
+};
+
+const PrepopulatedEngine yamli = {
+ L"Yamli",
+ L"yamli.com",
+ L"http://www.yamli.com/favicon.ico",
+ L"http://www.yamli.com/#q={searchTerms}",
+ "UTF-8",
+ NULL,
+ 11,
+};
+
+const PrepopulatedEngine yandex_ru = {
+ L"\x042f\x043d\x0434\x0435\x043a\x0441",
+ L"yandex.ru",
+ L"http://yandex.ru/favicon.ico",
+ L"http://yandex.ru/yandsearch?text={searchTerms}",
+ "UTF-8",
+ L"http://suggest.yandex.net/suggest-ff.cgi?part={searchTerms}",
+ 15,
+};
+
+const PrepopulatedEngine yandex_ua = {
+ L"\x042f\x043d\x0434\x0435\x043a\x0441",
+ L"yandex.ua",
+ L"http://yandex.ua/favicon.ico",
+ L"http://yandex.ua/yandsearch?text={searchTerms}",
+ "UTF-8",
+ L"http://suggest.yandex.net/suggest-ff.cgi?part={searchTerms}",
+ 15,
+};
+
+const PrepopulatedEngine zoznam = {
+ L"Zoznam",
+ L"zoznam.sk",
+ L"http://zoznam.sk/favicon.ico",
+ L"http://zoznam.sk/hladaj.fcgi?s={searchTerms}",
+ "windows-1250",
+ NULL,
+ 85,
+};
+
+// Lists of engines per country ////////////////////////////////////////////////
+
+// Put these in order with most interesting/important first. The default will
+// be the first engine.
+
+// Default (for countries with no better engine set)
+const PrepopulatedEngine* engines_default[] = { &google, &yahoo, &live, };
+
+// United Arab Emirates
+const PrepopulatedEngine* engines_AE[] =
+ { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Albania
+const PrepopulatedEngine* engines_AL[] =
+ { &google, &yahoo, &live_en_XA, &live_ar_XA, };
+
+// Argentina
+const PrepopulatedEngine* engines_AR[] =
+ { &google, &msn_es_AR, &altavista_ar, &terra_ar, &yahoo_ar, };
+
+// Austria
+const PrepopulatedEngine* engines_AT[] = { &google, &yahoo_at, &msn_de_AT, };
+
+// Australia
+const PrepopulatedEngine* engines_AU[] =
+ { &google, &yahoo_au, &msn_en_AU, &sensis, };
+
+// Bosnia and Herzegovina
+const PrepopulatedEngine* engines_BA[] =
+ { &google, &pogodak_ba, &yahoo, &live, };
+
+// Belgium
+const PrepopulatedEngine* engines_BE[] =
+ { &google, &yahoo, &msn_nl_BE, &msn_fr_BE, };
+
+// Bulgaria
+// The commented-out entry for "dir" below is for dir.bg, &which we don't
+// currently support because it uses POST instead of GET for its searches.
+// See http://b/1196285
+const PrepopulatedEngine* engines_BG[] =
+ { &google, &/*dir,*/ yahoo, &jabse, &live_bg_BG, };
+
+// Bahrain
+const PrepopulatedEngine* engines_BH[] =
+ { &google, &maktoob, &yamli, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Brunei
+const PrepopulatedEngine* engines_BN[] =
+ { &google, &yahoo_malaysia, &msn_en_MY, };
+
+// Bolivia
+const PrepopulatedEngine* engines_BO[] =
+ { &google, &altavista, &msn_es_XL, &yahoo, &ask_es, };
+
+// Brazil
+const PrepopulatedEngine* engines_BR[] =
+ { &google, &msn_pt_BR, &yahoo_br, &aonde, &gigabusca, &uol, };
+
+// Belarus
+const PrepopulatedEngine* engines_BY[] =
+ { &google, &yandex_ru, &rambler, &yahoo, &tut, };
+
+// Belize
+const PrepopulatedEngine* engines_BZ[] = { &google, &yahoo, &live, &aol, };
+
+// Canada
+const PrepopulatedEngine* engines_CA[] =
+ { &google, &msn_en_CA, &msn_fr_CA, &yahoo_ca, &yahoo_qc, &toile, };
+
+// Switzerland
+const PrepopulatedEngine* engines_CH[] =
+ { &google, &search_ch, &yahoo_ch, &msn_de_CH, &msn_fr_CH, &bluewin, };
+
+// Chile
+const PrepopulatedEngine* engines_CL[] =
+ { &google, &yahoo_cl, &altavista, &msn_es_CL, };
+
+// China
+const PrepopulatedEngine* engines_CN[] =
+ { &google, &baidu, &yahoo_cn, &sogou, &soso, };
+
+// Colombia
+const PrepopulatedEngine* engines_CO[] =
+ { &google, &msn_es_CO, &ask_es, &altavista, &conexcol, &yahoo_co, };
+
+// Costa Rica
+const PrepopulatedEngine* engines_CR[] =
+ { &google, &msn_es_XL, &yahoo, &altavista, &aol, &lycos_es, };
+
+// Czech Republic
+const PrepopulatedEngine* engines_CZ[] =
+ { &google, &seznam, &centrum_cz, &atlas_cz, &live_cs_CZ, };
+
+// Germany
+const PrepopulatedEngine* engines_DE[] =
+ { &google, &msn_de_DE, &yahoo_de, &t_online, &ask_de, &web_de, };
+
+// Denmark
+const PrepopulatedEngine* engines_DK[] =
+ { &google, &jubii, &msn_da_DK, &yahoo_dk, &eniro_dk, };
+
+// Dominican Republic
+const PrepopulatedEngine* engines_DO[] =
+ { &google, &msn_es_XL, &yahoo, &altavista, &go, &aol, };
+
+// Algeria
+const PrepopulatedEngine* engines_DZ[] =
+ { &google, &yahoo, &yamli, &msn_en_XA, &msn_ar_XA, &araby, };
+
+// Ecuador
+const PrepopulatedEngine* engines_EC[] =
+ { &google, &msn_es_XL, &yahoo, &terra_ec, };
+
+// Estonia
+const PrepopulatedEngine* engines_EE[] =
+ { &google, &neti, &delfi_ee, &yahoo, &live_et_EE, };
+
+// Egypt
+const PrepopulatedEngine* engines_EG[] =
+ { &google, &masrawy, &yahoo, &maktoob, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Spain
+const PrepopulatedEngine* engines_ES[] =
+ { &google, &msn_es_ES, &yahoo_es, &terra_es, &ozu, &altavista_es, };
+
+// Faroe Islands
+const PrepopulatedEngine* engines_FO[] =
+ { &google, &jubii, &msn_da_DK, &yahoo_dk, &eniro_dk, };
+
+// Finland
+const PrepopulatedEngine* engines_FI[] =
+ { &google, &msn_fi_FI, &yahoo_fi, &eniro_fi, &fonecta_02_fi, };
+
+// France
+const PrepopulatedEngine* engines_FR[] =
+ { &google, &voila, &yahoo_fr, &msn_fr_FR, &orange, &aol_fr, };
+
+// Greece
+const PrepopulatedEngine* engines_GR[] =
+ { &google, &yahoo, &forthnet, &in, &live_el_GR };
+
+// Guatemala
+const PrepopulatedEngine* engines_GT[] =
+ { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, &go, };
+
+// Hong Kong
+const PrepopulatedEngine* engines_HK[] =
+ { &google, &yahoo_hk, &msn_zh_HK, &sogou, &baidu, };
+
+// Honduras
+const PrepopulatedEngine* engines_HN[] =
+ { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, };
+
+// Croatia
+const PrepopulatedEngine* engines_HR[] =
+ { &google, &yahoo, &pogodak_hr, &live_hr_HR, };
+
+// Hungary
+const PrepopulatedEngine* engines_HU[] = { &google, &tango, &ok, &live_hu_HU, };
+
+// Indonesia
+const PrepopulatedEngine* engines_ID[] = { &google, &yahoo_id, &live_en_ID, };
+
+// Ireland
+const PrepopulatedEngine* engines_IE[] = { &google, &yahoo_uk, &msn_en_IE, };
+
+// Israel
+const PrepopulatedEngine* engines_IL[] =
+ { &google, &walla, &nana10, &tapuz, &msn_he_IL, };
+
+// India
+const PrepopulatedEngine* engines_IN[] =
+ { &google, &yahoo_in, &msn_en_IN, &rediff, &guruji, };
+
+// Iraq
+const PrepopulatedEngine* engines_IQ[] =
+ { &google, &maktoob, &yamli, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Iran
+const PrepopulatedEngine* engines_IR[] = { &google, };
+
+// Iceland
+const PrepopulatedEngine* engines_IS[] = { &google, &leit, &embla, &finna, };
+
+// Italy
+const PrepopulatedEngine* engines_IT[] =
+ { &google, &virgilio, &yahoo_it, &libero, &ask_it, &live_it_IT, };
+
+// Jamaica
+const PrepopulatedEngine* engines_JM[] =
+ { &google, &jamaicalive, &yahoo, &live, &go, &aol, };
+
+// Jordan
+const PrepopulatedEngine* engines_JO[] =
+ { &google, &maktoob, &yamli, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Japan
+const PrepopulatedEngine* engines_JP[] =
+ { &google, &yahoo_jp, &msn_ja_JP, &biglobe, &goo, &nifty, };
+
+// Kenya
+const PrepopulatedEngine* engines_KE[] = { &google, &yahoo, &msn, };
+
+// Kuwait
+const PrepopulatedEngine* engines_KW[] =
+ { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// South Korea
+const PrepopulatedEngine* engines_KR[] =
+ { &google, &naver, &daum, &yahoo_kr, &nate, &empas, };
+
+// Lebanon
+const PrepopulatedEngine* engines_LB[] =
+ { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Liechtenstein
+const PrepopulatedEngine* engines_LI[] =
+ { &google, &msn_de_DE, &yahoo_de, &t_online, &ask_de, &web_de, };
+
+// Lithuania
+const PrepopulatedEngine* engines_LT[] =
+ { &google, &delfi_lt, &yahoo, &yandex_ru, &live_lt_LT, };
+
+// Luxembourg
+const PrepopulatedEngine* engines_LU[] =
+ { &google, &voila, &yahoo_fr, &msn_fr_FR, &orange, &aol_fr, };
+
+// Latvia
+const PrepopulatedEngine* engines_LV[] =
+ { &google, &delfi_lv, &yahoo, &yandex_ru, &latne, };
+
+// Libya
+const PrepopulatedEngine* engines_LY[] =
+ { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Morocco
+const PrepopulatedEngine* engines_MA[] =
+ { &google, &yamli, &araby, &yahoo, &msn_en_XA, &msn_ar_XA, };
+
+// Monaco
+const PrepopulatedEngine* engines_MC[] =
+ { &google, &voila, &yahoo_fr, &msn_fr_FR, &orange, &aol_fr, };
+
+// Macedonia
+const PrepopulatedEngine* engines_MK[] = { &google, &pogodok, &yahoo, &live, };
+
+// Mexico
+const PrepopulatedEngine* engines_MX[] =
+ { &google, &msn_es_MX, &yahoo_mx, &ask_es, &altavista_mx, &terra_mx, };
+
+// Malaysia
+const PrepopulatedEngine* engines_MY[] =
+ { &google, &yahoo_malaysia, &msn_en_MY, };
+
+// Nicaragua
+const PrepopulatedEngine* engines_NI[] =
+ { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, };
+
+// Netherlands
+const PrepopulatedEngine* engines_NL[] =
+ { &google, &ilse, &msn_nl_NL, &yahoo_nl, &lycos_nl, &vinden, };
+
+// Norway
+const PrepopulatedEngine* engines_NO[] =
+ { &google, &msn_nb_NO, &abcsok, &yahoo_no, &kvasir, &sesam, };
+
+// New Zealand
+const PrepopulatedEngine* engines_NZ[] = { &google, &yahoo_nz, &live_en_NZ, };
+
+// Oman
+const PrepopulatedEngine* engines_OM[] =
+ { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Panama
+const PrepopulatedEngine* engines_PA[] =
+ { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, &lycos_es, };
+
+// Peru
+const PrepopulatedEngine* engines_PE[] =
+ { &google, &msn_es_XL, &yahoo_pe, &terra_pe, &adonde, &ohperu, };
+
+// Philippines
+const PrepopulatedEngine* engines_PH[] = { &google, &yahoo_ph, &msn_en_PH, };
+
+// Pakistan
+const PrepopulatedEngine* engines_PK[] = { &google, &yahoo, &msn, };
+
+// Puerto Rico
+const PrepopulatedEngine* engines_PR[] =
+ { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, &mywebsearch, };
+
+// Poland
+const PrepopulatedEngine* engines_PL[] = { &google, &onet, &wp, &live_pl_PL, };
+
+// Portugal
+const PrepopulatedEngine* engines_PT[] =
+ { &google, &sapo, &yahoo, &live_pt_PT, &netindex, &aeiou, };
+
+// Paraguay
+const PrepopulatedEngine* engines_PY[] =
+ { &google, &msn_es_XL, &yahoo, &lycos_es, &yagua, &go, };
+
+// Qatar
+const PrepopulatedEngine* engines_QA[] =
+ { &google, &maktoob, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Romania
+const PrepopulatedEngine* engines_RO[] = { &google, &yahoo, &live_ro_RO, };
+
+// Serbia/Montenegro
+const PrepopulatedEngine* engines_RS_ME[] =
+ { &google, &yahoo, &krstarica, &pogodak_rs, &aladin, &live, };
+
+// Russia
+const PrepopulatedEngine* engines_RU[] =
+ { &google, &yandex_ru, &rambler, &mail_ru, &yahoo_ru, &live_ru_RU, };
+
+// Saudi Arabia
+const PrepopulatedEngine* engines_SA[] =
+ { &google, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, &maktoob, };
+
+// Sweden
+const PrepopulatedEngine* engines_SE[] =
+ { &google, &eniro_se, &msn_sv_SE, &altavista_se, &spray, };
+
+// Singapore
+const PrepopulatedEngine* engines_SG[] =
+ { &google, &yahoo_sg, &msn_en_SG, &rednano, };
+
+// Slovenia
+const PrepopulatedEngine* engines_SI[] =
+ { &google, &najdi, &yahoo, &matkurja, &live_sl_SI, };
+
+// Slovakia
+const PrepopulatedEngine* engines_SK[] =
+ { &google, &zoznam, &centrum_sk, &atlas_sk, &szm, &live_sk_SK, };
+
+// El Salvador
+const PrepopulatedEngine* engines_SV[] =
+ { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, &go, };
+
+// Syria
+const PrepopulatedEngine* engines_SY[] =
+ { &google, &yahoo, &maktoob, &yamli, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// Thailand
+const PrepopulatedEngine* engines_TH[] =
+ { &google, &sanook, &yahoo_th, &live_th_TH, };
+
+// Tunisia
+const PrepopulatedEngine* engines_TN[] =
+ { &google, &maktoob, &yamli, &yahoo, &msn_en_XA, &msn_ar_XA, };
+
+// Turkey
+const PrepopulatedEngine* engines_TR[] =
+ { &google, &msn_tr_TR, &yahoo, &mynet, };
+
+// Trinidad and Tobago
+const PrepopulatedEngine* engines_TT[] = { &google, &live, &yahoo, &go, &aol, };
+
+// Taiwan
+const PrepopulatedEngine* engines_TW[] = { &google, &yahoo_tw, &yam, };
+
+// Ukraine
+const PrepopulatedEngine* engines_UA[] =
+ { &google, &meta, &yandex_ua, &bigmir, &rambler, };
+
+// United Kingdom
+const PrepopulatedEngine* engines_UK[] =
+ { &google, &yahoo_uk, &msn_en_GB, &ask_uk, };
+
+// United States
+const PrepopulatedEngine* engines_US[] =
+ { &google, &yahoo, &live_en_US, &aol, &ask, };
+
+// Uruguay
+const PrepopulatedEngine* engines_UY[] =
+ { &google, &msn_es_XL, &yahoo, &go, &lycos_es, };
+
+// Venezuela
+const PrepopulatedEngine* engines_VE[] =
+ { &google, &msn_es_XL, &yahoo_ve, &altavista, };
+
+// Vietnam
+const PrepopulatedEngine* engines_VN[] = { &google, &yahoo_vn, };
+
+// Yemen
+const PrepopulatedEngine* engines_YE[] =
+ { &google, &yahoo, &maktoob, &yamli, &araby, &msn_en_XA, &msn_ar_XA, };
+
+// South Africa
+const PrepopulatedEngine* engines_ZA[] =
+ { &google, &yahoo, &msn_en_ZA, &mweb, &iafrica, };
+
+// Zimbabwe
+const PrepopulatedEngine* engines_ZW[] = { &google, &yahoo, &msn, };
+
+// GeoID mappings //////////////////////////////////////////////////////////////
+
+LONG GetCurrentGeoID() {
+ // TODO(pkasting): http://b/1225276 Much of this should live in a utility
+ // function somewhere.
+ typedef GEOID (WINAPI *GetUserGeoIDFunction)(GEOCLASS);
+ const HMODULE kernel32_handle = GetModuleHandle(L"kernel32.dll");
+ if (!kernel32_handle) {
+ NOTREACHED();
+ return GEOID_NOT_AVAILABLE;
+ }
+ const GetUserGeoIDFunction GetUserGeoIDPtr =
+ reinterpret_cast<GetUserGeoIDFunction>(GetProcAddress(kernel32_handle,
+ "GetUserGeoID"));
+ return GetUserGeoIDPtr ?
+ ((*GetUserGeoIDPtr)(GEOCLASS_NATION)) : GEOID_NOT_AVAILABLE;
+}
+
+int GetGeoIDFromPrefs(PrefService* prefs) {
+ // See if the user overrode the GeoID on the command line.
+ CommandLine parsed_command_line;
+ const std::wstring geoID(
+ parsed_command_line.GetSwitchValue(switches::kGeoID));
+ if (!geoID.empty())
+ return _wtoi(geoID.c_str());
+
+ // Cache first run GeoID value in prefs, and use it afterwards. This ensures
+ // that just because the user moves around, we won't automatically make major
+ // changes to their available search providers, which would feel surprising.
+ if (!prefs)
+ return GetCurrentGeoID();
+ if (!prefs->HasPrefPath(prefs::kGeoIDAtInstall))
+ prefs->SetInteger(prefs::kGeoIDAtInstall, GetCurrentGeoID());
+ return prefs->GetInteger(prefs::kGeoIDAtInstall);
+}
+
+void GetPrepopulationSetFromGeoID(PrefService* prefs,
+ const PrepopulatedEngine*** engines,
+ size_t* num_engines) {
+ // NOTE: This function should ALWAYS set its outparams.
+
+ // If you add a new geo id make sure and update the unit test for coverage.
+
+ // GeoIDs are from http://msdn.microsoft.com/en-us/library/ms776390.aspx .
+ // Country codes and names are from http://www.geonames.org/countries/ .
+ switch (GetGeoIDFromPrefs(prefs)) {
+
+#define UNHANDLED_COUNTRY(id, code)\
+ case id:
+#define END_UNHANDLED_COUNTRIES(code)\
+ *engines = engines_##code;\
+ *num_engines = arraysize(engines_##code);\
+ return;
+#define DECLARE_COUNTRY(id, code)\
+ UNHANDLED_COUNTRY(id, code)\
+ END_UNHANDLED_COUNTRIES(code)
+
+ // Countries with their own, dedicated engine set.
+ DECLARE_COUNTRY(0x4, DZ) // Algeria
+ DECLARE_COUNTRY(0x6, AL) // Albania
+ DECLARE_COUNTRY(0xB, AR) // Argentina
+ DECLARE_COUNTRY(0xC, AU) // Australia
+ DECLARE_COUNTRY(0xE, AT) // Austria
+ DECLARE_COUNTRY(0x11, BH) // Bahrain
+ DECLARE_COUNTRY(0x15, BE) // Belgium
+ DECLARE_COUNTRY(0x18, BZ) // Belize
+ DECLARE_COUNTRY(0x19, BA) // Bosnia and Herzegovina
+ DECLARE_COUNTRY(0x1A, BO) // Bolivia
+ DECLARE_COUNTRY(0x1D, BY) // Belarus
+ DECLARE_COUNTRY(0x20, BR) // Brazil
+ DECLARE_COUNTRY(0x23, BG) // Bulgaria
+ DECLARE_COUNTRY(0x25, BN) // Brunei
+ DECLARE_COUNTRY(0x27, CA) // Canada
+ DECLARE_COUNTRY(0x2D, CN) // China
+ DECLARE_COUNTRY(0x2E, CL) // Chile
+ DECLARE_COUNTRY(0x33, CO) // Colombia
+ DECLARE_COUNTRY(0x36, CR) // Costa Rica
+ DECLARE_COUNTRY(0x3D, DK) // Denmark
+ DECLARE_COUNTRY(0x41, DO) // Dominican Republic
+ DECLARE_COUNTRY(0x42, EC) // Ecuador
+ DECLARE_COUNTRY(0x43, EG) // Egypt
+ DECLARE_COUNTRY(0x44, IE) // Ireland
+ DECLARE_COUNTRY(0x46, EE) // Estonia
+ DECLARE_COUNTRY(0x48, SV) // El Salvador
+ DECLARE_COUNTRY(0x4B, CZ) // Czech Republic
+ DECLARE_COUNTRY(0x4D, FI) // Finland
+ DECLARE_COUNTRY(0x51, FO) // Faroe Islands
+ DECLARE_COUNTRY(0x54, FR) // France
+ DECLARE_COUNTRY(0x5E, DE) // Germany
+ DECLARE_COUNTRY(0x62, GR) // Greece
+ DECLARE_COUNTRY(0x63, GT) // Guatemala
+ DECLARE_COUNTRY(0x68, HK) // Hong Kong
+ DECLARE_COUNTRY(0x6A, HN) // Honduras
+ DECLARE_COUNTRY(0x6C, HR) // Croatia
+ DECLARE_COUNTRY(0x6D, HU) // Hungary
+ DECLARE_COUNTRY(0x6E, IS) // Iceland
+ DECLARE_COUNTRY(0x6F, ID) // Indonesia
+ DECLARE_COUNTRY(0x71, IN) // India
+ DECLARE_COUNTRY(0x74, IR) // Iran
+ DECLARE_COUNTRY(0x75, IL) // Israel
+ DECLARE_COUNTRY(0x76, IT) // Italy
+ DECLARE_COUNTRY(0x79, IQ) // Iraq
+ DECLARE_COUNTRY(0x7A, JP) // Japan
+ DECLARE_COUNTRY(0x7C, JM) // Jamaica
+ DECLARE_COUNTRY(0x7E, JO) // Jordan
+ DECLARE_COUNTRY(0x81, KE) // Kenya
+ DECLARE_COUNTRY(0x86, KR) // South Korea
+ DECLARE_COUNTRY(0x88, KW) // Kuwait
+ DECLARE_COUNTRY(0x8B, LB) // Lebanon
+ DECLARE_COUNTRY(0x8C, LV) // Latvia
+ DECLARE_COUNTRY(0x8D, LT) // Lithuania
+ DECLARE_COUNTRY(0x8F, SK) // Slovakia
+ DECLARE_COUNTRY(0x91, LI) // Liechtenstein
+ DECLARE_COUNTRY(0x93, LU) // Luxembourg
+ DECLARE_COUNTRY(0x94, LY) // Libya
+ DECLARE_COUNTRY(0x9E, MC) // Monaco
+ DECLARE_COUNTRY(0x9F, MA) // Morocco
+ DECLARE_COUNTRY(0xA4, OM) // Oman
+ DECLARE_COUNTRY(0xA6, MX) // Mexico
+ DECLARE_COUNTRY(0xA7, MY) // Malaysia
+ DECLARE_COUNTRY(0xB0, NL) // Netherlands
+ DECLARE_COUNTRY(0xB1, NO) // Norway
+ DECLARE_COUNTRY(0xB6, NI) // Nicaragua
+ DECLARE_COUNTRY(0xB7, NZ) // New Zealand
+ DECLARE_COUNTRY(0xB9, PY) // Paraguay
+ DECLARE_COUNTRY(0xBB, PE) // Peru
+ DECLARE_COUNTRY(0xBE, PK) // Pakistan
+ DECLARE_COUNTRY(0xBF, PL) // Poland
+ DECLARE_COUNTRY(0xC0, PA) // Panama
+ DECLARE_COUNTRY(0xC1, PT) // Portugal
+ DECLARE_COUNTRY(0xC5, QA) // Qatar
+ DECLARE_COUNTRY(0xC8, RO) // Romania
+ DECLARE_COUNTRY(0xC9, PH) // Philippines
+ DECLARE_COUNTRY(0xCA, PR) // Puerto Rico
+ DECLARE_COUNTRY(0xCB, RU) // Russia
+ DECLARE_COUNTRY(0xCD, SA) // Saudi Arabia
+ DECLARE_COUNTRY(0xD1, ZA) // South Africa
+ DECLARE_COUNTRY(0xD4, SI) // Slovenia
+ DECLARE_COUNTRY(0xD7, SG) // Singapore
+ DECLARE_COUNTRY(0xD9, ES) // Spain
+ DECLARE_COUNTRY(0xDD, SE) // Sweden
+ DECLARE_COUNTRY(0xDE, SY) // Syria
+ DECLARE_COUNTRY(0xDF, CH) // Switzerland
+ DECLARE_COUNTRY(0xE0, AE) // United Arab Emirates
+ DECLARE_COUNTRY(0xE1, TT) // Trinidad and Tobago
+ DECLARE_COUNTRY(0xE3, TH) // Thailand
+ DECLARE_COUNTRY(0xEA, TN) // Tunisia
+ DECLARE_COUNTRY(0xEB, TR) // Turkey
+ DECLARE_COUNTRY(0xED, TW) // Taiwan
+ DECLARE_COUNTRY(0xF1, UA) // Ukraine
+ DECLARE_COUNTRY(0xF2, UK) // United Kingdom
+ DECLARE_COUNTRY(0xF4, US) // United States
+ DECLARE_COUNTRY(0xF6, UY) // Uruguay
+ DECLARE_COUNTRY(0xF9, VE) // Venezuela
+ DECLARE_COUNTRY(0xFB, VN) // Vietnam
+ DECLARE_COUNTRY(0x105, YE) // Yemen
+ DECLARE_COUNTRY(0x108, ZW) // Zimbabwe
+ DECLARE_COUNTRY(0x10D, RS_ME) // Serbia/Montenegro
+ DECLARE_COUNTRY(0x4CA2, MK) // Macedonia
+
+ // Countries using the "Australia" engine set.
+ UNHANDLED_COUNTRY(0x130, XX) // Ashmore and Cartier Islands
+ UNHANDLED_COUNTRY(0x135, CX) // Christmas Island
+ UNHANDLED_COUNTRY(0x137, CC) // Cocos Islands
+ UNHANDLED_COUNTRY(0x139, XX) // Coral Sea Islands
+ UNHANDLED_COUNTRY(0x145, HM) // Heard Island and McDonald Islands
+ UNHANDLED_COUNTRY(0x150, NF) // Norfolk Island
+ END_UNHANDLED_COUNTRIES(AU)
+
+ // Countries using the "China" engine set.
+ UNHANDLED_COUNTRY(0x97, MO) // Macao
+ END_UNHANDLED_COUNTRIES(CN)
+
+ // Countries using the "Denmark" engine set.
+ UNHANDLED_COUNTRY(0x5D, GL) // Greenland
+ END_UNHANDLED_COUNTRIES(DK)
+
+ // Countries using the "Spain" engine set.
+ UNHANDLED_COUNTRY(0x8, AD) // Andorra
+ END_UNHANDLED_COUNTRIES(ES)
+
+ // Countries using the "France" engine set.
+ UNHANDLED_COUNTRY(0x1C, BJ) // Benin
+ UNHANDLED_COUNTRY(0x26, BI) // Burundi
+ UNHANDLED_COUNTRY(0x29, TD) // Chad
+ UNHANDLED_COUNTRY(0x2B, CG) // Congo - Brazzaville
+ UNHANDLED_COUNTRY(0x2C, CD) // Congo - Kinshasa
+ UNHANDLED_COUNTRY(0x31, CM) // Cameroon
+ UNHANDLED_COUNTRY(0x37, CF) // Central African Republic
+ UNHANDLED_COUNTRY(0x3E, DJ) // Djibouti
+ UNHANDLED_COUNTRY(0x57, GA) // Gabon
+ UNHANDLED_COUNTRY(0x64, GN) // Guinea
+ UNHANDLED_COUNTRY(0x67, HT) // Haiti
+ UNHANDLED_COUNTRY(0x77, CI) // Ivory Coast
+ UNHANDLED_COUNTRY(0x9D, ML) // Mali
+ UNHANDLED_COUNTRY(0xAD, NE) // Niger
+ UNHANDLED_COUNTRY(0xC6, RE) // Reunion
+ UNHANDLED_COUNTRY(0xCE, PM) // Saint Pierre and Miquelon
+ UNHANDLED_COUNTRY(0xD2, SN) // Senegal
+ UNHANDLED_COUNTRY(0xE8, TG) // Togo
+ UNHANDLED_COUNTRY(0xF5, BF) // Burkina Faso
+ UNHANDLED_COUNTRY(0x136, XX) // Clipperton Island
+ UNHANDLED_COUNTRY(0x13D, GF) // French Guiana
+ UNHANDLED_COUNTRY(0x13E, PF) // French Polynesia
+ UNHANDLED_COUNTRY(0x13F, TF) // French Southern Territories
+ UNHANDLED_COUNTRY(0x141, GP) // Guadeloupe
+ UNHANDLED_COUNTRY(0x14A, MQ) // Martinique
+ UNHANDLED_COUNTRY(0x14B, YT) // Mayotte
+ UNHANDLED_COUNTRY(0x14E, NC) // New Caledonia
+ UNHANDLED_COUNTRY(0x160, WF) // Wallis and Futuna
+ END_UNHANDLED_COUNTRIES(FR)
+
+ // Countries using the "Greece" engine set.
+ UNHANDLED_COUNTRY(0x3B, CY) // Cyprus
+ END_UNHANDLED_COUNTRIES(GR)
+
+ // Countries using the "Italy" engine set.
+ UNHANDLED_COUNTRY(0xD6, SM) // San Marino
+ UNHANDLED_COUNTRY(0xFD, VA) // Vatican
+ END_UNHANDLED_COUNTRIES(IT)
+
+ // Countries using the "Netherlands" engine set.
+ UNHANDLED_COUNTRY(0x12E, AW) // Aruba
+ UNHANDLED_COUNTRY(0x14D, AN) // Netherlands Antilles
+ END_UNHANDLED_COUNTRIES(NL)
+
+ // Countries using the "Norway" engine set.
+ UNHANDLED_COUNTRY(0x7D, SJ) // [Svalbard and] Jan Mayen
+ UNHANDLED_COUNTRY(0xDC, SJ) // Svalbard [and Jan Mayen]
+ UNHANDLED_COUNTRY(0x132, BV) // Bouvet Island
+ END_UNHANDLED_COUNTRIES(NO)
+
+ // Countries using the "New Zealand" engine set.
+ UNHANDLED_COUNTRY(0x138, CK) // Cook Islands
+ UNHANDLED_COUNTRY(0x14F, NU) // Niue
+ UNHANDLED_COUNTRY(0x15B, TK) // Tokelau
+ END_UNHANDLED_COUNTRIES(NZ)
+
+ // Countries using the "Portugal" engine set.
+ UNHANDLED_COUNTRY(0x39, CV) // Cape Verde
+ UNHANDLED_COUNTRY(0xA8, MZ) // Mozambique
+ UNHANDLED_COUNTRY(0xC4, GW) // Guinea-Bissau
+ UNHANDLED_COUNTRY(0xE9, ST) // Sao Tome and Principe
+ UNHANDLED_COUNTRY(0x6F60E7, TL) // East Timor
+ END_UNHANDLED_COUNTRIES(PT)
+
+ // Countries using the "Russia" engine set.
+ UNHANDLED_COUNTRY(0x5, AZ) // Azerbaijan
+ UNHANDLED_COUNTRY(0x7, AM) // Armenia
+ UNHANDLED_COUNTRY(0x82, KG) // Kyrgyzstan
+ UNHANDLED_COUNTRY(0x89, KZ) // Kazakhstan
+ UNHANDLED_COUNTRY(0xE4, TJ) // Tajikistan
+ UNHANDLED_COUNTRY(0xEE, TM) // Turkmenistan
+ UNHANDLED_COUNTRY(0xF7, UZ) // Uzbekistan
+ END_UNHANDLED_COUNTRIES(RU)
+
+ // Countries using the "Saudi Arabia" engine set.
+ UNHANDLED_COUNTRY(0xA2, MR) // Mauritania
+ UNHANDLED_COUNTRY(0xB8, PS) // Palestinian Territory
+ UNHANDLED_COUNTRY(0xDB, SD) // Sudan
+ END_UNHANDLED_COUNTRIES(SA)
+
+ // Countries using the "United Kingdom" engine set.
+ UNHANDLED_COUNTRY(0x14, BM) // Bermuda
+ UNHANDLED_COUNTRY(0x5A, GI) // Gibraltar
+ UNHANDLED_COUNTRY(0x72, IO) // British Indian Ocean Territory
+ UNHANDLED_COUNTRY(0xA3, MT) // Malta
+ UNHANDLED_COUNTRY(0x12F, XX) // Ascension Island
+ UNHANDLED_COUNTRY(0x133, KY) // Cayman Islands
+ UNHANDLED_COUNTRY(0x134, XX) // Channel Islands
+ UNHANDLED_COUNTRY(0x13A, XX) // Diego Garcia
+ UNHANDLED_COUNTRY(0x13B, FK) // Falkland Islands
+ UNHANDLED_COUNTRY(0x144, GG) // Guernsey
+ UNHANDLED_COUNTRY(0x148, JE) // Jersey
+ UNHANDLED_COUNTRY(0x14C, MS) // Montserrat
+ UNHANDLED_COUNTRY(0x153, PN) // Pitcairn Islands
+ UNHANDLED_COUNTRY(0x156, GS) // South Georgia and the South Sandwich
+ // Islands
+ UNHANDLED_COUNTRY(0x157, SH) // Saint Helena
+ UNHANDLED_COUNTRY(0x15C, XX) // Tristan da Cunha
+ UNHANDLED_COUNTRY(0x15D, TC) // Turks and Caicos Islands
+ UNHANDLED_COUNTRY(0x15F, VG) // British Virgin Islands
+ UNHANDLED_COUNTRY(0x3B16, IM) // Isle of Man
+ END_UNHANDLED_COUNTRIES(UK)
+
+ // Countries using the "United States" engine set.
+ UNHANDLED_COUNTRY(0xA, AS) // American Samoa
+ UNHANDLED_COUNTRY(0x7F, XX) // Johnston Atoll
+ UNHANDLED_COUNTRY(0xFC, VI) // U.S. Virgin Islands
+ UNHANDLED_COUNTRY(0x102, XX) // Wake Island
+ UNHANDLED_COUNTRY(0x131, XX) // Baker Island
+ UNHANDLED_COUNTRY(0x142, GU) // Guam
+ UNHANDLED_COUNTRY(0x146, XX) // Howland Island
+ UNHANDLED_COUNTRY(0x147, XX) // Jarvis Island
+ UNHANDLED_COUNTRY(0x149, XX) // Kingman Reef
+ UNHANDLED_COUNTRY(0x151, MP) // Northern Mariana Islands
+ UNHANDLED_COUNTRY(0x152, XX) // Palmyra Atoll
+ UNHANDLED_COUNTRY(0x154, XX) // Rota Island
+ UNHANDLED_COUNTRY(0x155, XX) // Saipan
+ UNHANDLED_COUNTRY(0x15A, XX) // Tinian Island
+ UNHANDLED_COUNTRY(0x52FA, XX) // Midway Islands
+ END_UNHANDLED_COUNTRIES(US)
+
+ // Countries using the "default" engine set.
+ UNHANDLED_COUNTRY(0x2, AG) // Antigua and Barbuda
+ UNHANDLED_COUNTRY(0x3, AF) // Afghanistan
+ UNHANDLED_COUNTRY(0x9, AO) // Angola
+ UNHANDLED_COUNTRY(0x12, BB) // Barbados
+ UNHANDLED_COUNTRY(0x13, BW) // Botswana
+ UNHANDLED_COUNTRY(0x16, BS) // Bahamas
+ UNHANDLED_COUNTRY(0x17, BD) // Bangladesh
+ UNHANDLED_COUNTRY(0x1B, MM) // Myanmar
+ UNHANDLED_COUNTRY(0x1E, SB) // Solomon Islands
+ UNHANDLED_COUNTRY(0x22, BT) // Bhutan
+ UNHANDLED_COUNTRY(0x28, KH) // Cambodia
+ UNHANDLED_COUNTRY(0x2A, LK) // Sri Lanka
+ UNHANDLED_COUNTRY(0x32, KM) // Comoros
+ UNHANDLED_COUNTRY(0x38, CU) // Cuba
+ UNHANDLED_COUNTRY(0x3F, DM) // Dominica
+ UNHANDLED_COUNTRY(0x45, GQ) // Equatorial Guinea
+ UNHANDLED_COUNTRY(0x47, ER) // Eritrea
+ UNHANDLED_COUNTRY(0x49, ET) // Ethiopia
+ UNHANDLED_COUNTRY(0x4E, FJ) // Fiji
+ UNHANDLED_COUNTRY(0x50, FM) // Micronesia
+ UNHANDLED_COUNTRY(0x56, GM) // Gambia
+ UNHANDLED_COUNTRY(0x58, GE) // Georgia
+ UNHANDLED_COUNTRY(0x59, GH) // Ghana
+ UNHANDLED_COUNTRY(0x5B, GD) // Grenada
+ UNHANDLED_COUNTRY(0x65, GY) // Guyana
+ UNHANDLED_COUNTRY(0x83, KP) // North Korea
+ UNHANDLED_COUNTRY(0x85, KI) // Kiribati
+ UNHANDLED_COUNTRY(0x8A, LA) // Laos
+ UNHANDLED_COUNTRY(0x8E, LR) // Liberia
+ UNHANDLED_COUNTRY(0x92, LS) // Lesotho
+ UNHANDLED_COUNTRY(0x95, MG) // Madagascar
+ UNHANDLED_COUNTRY(0x98, MD) // Moldova
+ UNHANDLED_COUNTRY(0x9A, MN) // Mongolia
+ UNHANDLED_COUNTRY(0x9C, MW) // Malawi
+ UNHANDLED_COUNTRY(0xA0, MU) // Mauritius
+ UNHANDLED_COUNTRY(0xA5, MV) // Maldives
+ UNHANDLED_COUNTRY(0xAE, VU) // Vanuatu
+ UNHANDLED_COUNTRY(0xAF, NG) // Nigeria
+ UNHANDLED_COUNTRY(0xB2, NP) // Nepal
+ UNHANDLED_COUNTRY(0xB4, NR) // Nauru
+ UNHANDLED_COUNTRY(0xB5, SR) // Suriname
+ UNHANDLED_COUNTRY(0xC2, PG) // Papua New Guinea
+ UNHANDLED_COUNTRY(0xC3, PW) // Palau
+ UNHANDLED_COUNTRY(0xC7, MH) // Marshall Islands
+ UNHANDLED_COUNTRY(0xCC, RW) // Rwanda
+ UNHANDLED_COUNTRY(0xCF, KN) // Saint Kitts and Nevis
+ UNHANDLED_COUNTRY(0xD0, SC) // Seychelles
+ UNHANDLED_COUNTRY(0xD5, SL) // Sierra Leone
+ UNHANDLED_COUNTRY(0xD8, SO) // Somalia
+ UNHANDLED_COUNTRY(0xDA, LC) // Saint Lucia
+ UNHANDLED_COUNTRY(0xE7, TO) // Tonga
+ UNHANDLED_COUNTRY(0xEC, TV) // Tuvalu
+ UNHANDLED_COUNTRY(0xEF, TZ) // Tanzania
+ UNHANDLED_COUNTRY(0xF0, UG) // Uganda
+ UNHANDLED_COUNTRY(0xF8, VC) // Saint Vincent and the
+ // Grenadines
+ UNHANDLED_COUNTRY(0xFE, NA) // Namibia
+ UNHANDLED_COUNTRY(0x103, WS) // Samoa
+ UNHANDLED_COUNTRY(0x104, SZ) // Swaziland
+ UNHANDLED_COUNTRY(0x107, ZM) // Zambia
+ UNHANDLED_COUNTRY(0x12C, AI) // Anguilla
+ UNHANDLED_COUNTRY(0x12D, AQ) // Antarctica
+ UNHANDLED_COUNTRY(0x143, XX) // Guantanamo Bay
+ UNHANDLED_COUNTRY(GEOID_NOT_AVAILABLE, XX) // Unknown location
+ default: // Unhandled location
+ END_UNHANDLED_COUNTRIES(default)
+ }
+}
+
+} // namespace
+
+namespace TemplateURLPrepopulateData {
+
+void RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterIntegerPref(prefs::kGeoIDAtInstall, -1);
+}
+
+int GetDataVersion() {
+ return 19; // Increment this if you change the above data in ways that mean
+ // users with existing data should get a new version.
+}
+
+void GetPrepopulatedEngines(PrefService* prefs,
+ std::vector<TemplateURL*>* t_urls,
+ size_t* default_search_provider_index) {
+ // TODO(pkasting): http://b/1225464 GeoID is not available on Win2k. We'll
+ // need to do something else there.
+ const PrepopulatedEngine** engines;
+ size_t num_engines;
+ GetPrepopulationSetFromGeoID(prefs, &engines, &num_engines);
+ *default_search_provider_index = 0;
+
+ for (size_t i = 0; i < num_engines; ++i) {
+ TemplateURL* new_turl = new TemplateURL();
+ new_turl->SetURL(engines[i]->search_url, 0, 0);
+ if (engines[i]->favicon_url)
+ new_turl->SetFavIconURL(GURL(engines[i]->favicon_url));
+ if (engines[i]->suggest_url)
+ new_turl->SetSuggestionsURL(engines[i]->suggest_url, 0, 0);
+ new_turl->set_short_name(engines[i]->name);
+ if (engines[i]->keyword == NULL)
+ new_turl->set_autogenerate_keyword(true);
+ else
+ new_turl->set_keyword(engines[i]->keyword);
+ new_turl->set_show_in_default_list(true);
+ new_turl->set_safe_for_autoreplace(true);
+ new_turl->set_date_created(Time());
+ std::vector<std::string> turl_encodings;
+ turl_encodings.push_back(engines[i]->encoding);
+ new_turl->set_input_encodings(turl_encodings);
+ new_turl->set_prepopulate_id(engines[i]->id);
+ t_urls->push_back(new_turl);
+ }
+}
+
+} // namespace TemplateURLPrepopulateData
diff --git a/chrome/browser/template_url_prepopulate_data.h b/chrome/browser/template_url_prepopulate_data.h
new file mode 100644
index 0000000..9bc3a70
--- /dev/null
+++ b/chrome/browser/template_url_prepopulate_data.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TEMPLATE_URL_PREPOPULATE_DATA_H__
+#define CHROME_BROWSER_TEMPLATE_URL_PREPOPULATE_DATA_H__
+
+#include <vector>
+
+class PrefService;
+class TemplateURL;
+
+namespace TemplateURLPrepopulateData {
+
+void RegisterUserPrefs(PrefService* prefs);
+
+// Returns the current version of the prepopulate data, so callers can know when
+// they need to re-merge.
+int GetDataVersion();
+
+// Loads the set of TemplateURLs from the prepopulate data. Ownership of the
+// TemplateURLs is passed to the caller. On return,
+// |default_search_provider_index| is set to the index of the default search
+// provider.
+void GetPrepopulatedEngines(PrefService* prefs,
+ std::vector<TemplateURL*>* t_urls,
+ size_t* default_search_provider_index);
+
+} // namespace TemplateURLPrepopulateData
+
+#endif // CHROME_BROWSER_TEMPLATE_URL_PREPOPULATE_DATA_H__
+
diff --git a/chrome/browser/template_url_prepopulate_data_unittest.cc b/chrome/browser/template_url_prepopulate_data_unittest.cc
new file mode 100644
index 0000000..14c6abb
--- /dev/null
+++ b/chrome/browser/template_url_prepopulate_data_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_prepopulate_data.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/scoped_vector.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+typedef testing::Test TemplateURLPrepopulateDataTest;
+
+// Verifies the set of prepopulate data doesn't contain entries with duplicate
+// ids.
+TEST_F(TemplateURLPrepopulateDataTest, UniqueIDs) {
+ // GEO ids.
+ int ids[] = { 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC,
+ 0xE, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x20, 0x22, 0x23, 0x25, 0x26,
+ 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32,
+ 0x33, 0x36, 0x37, 0x38, 0x39, 0x3B, 0x3D, 0x3E, 0x3F, 0x41,
+ 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4B, 0x4D,
+ 0x4E, 0x50, 0x51, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
+ 0x5D, 0x5E, 0x62, 0x63, 0x64, 0x65, 0x67, 0x68, 0x6A, 0x6C,
+ 0x6D, 0x6E, 0x6F, 0x71, 0x72, 0x74, 0x75, 0x76, 0x77, 0x79,
+ 0x7A, 0x7C, 0x7D, 0x7E, 0x7F, 0x81, 0x82, 0x83, 0x85, 0x86,
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x91, 0x92,
+ 0x93, 0x94, 0x95, 0x97, 0x98, 0x9A, 0x9C, 0x9D, 0x9E, 0x9F,
+ 0xA0, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xAD, 0xAE,
+ 0xAF, 0xB0, 0xB1, 0xB2, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
+ 0xBB, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6,
+ 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0,
+ 0xD1, 0xD2, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB,
+ 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE3, 0xE4, 0xE7, 0xE8,
+ 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2,
+ 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFB, 0xFC, 0xFD, 0xFE,
+ 0x102, 0x103, 0x104, 0x105, 0x107, 0x108, 0x10D, 0x12C, 0x12D,
+ 0x12E, 0x12F, 0x130, 0x131, 0x132, 0x133, 0x134, 0x135, 0x136,
+ 0x137, 0x138, 0x139, 0x13A, 0x13B, 0x13D, 0x13E, 0x13F, 0x141,
+ 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A,
+ 0x14B, 0x14C, 0x14D, 0x14E, 0x14F, 0x150, 0x151, 0x152, 0x153,
+ 0x154, 0x155, 0x156, 0x157, 0x15A, 0x15B, 0x15C, 0x15D, 0x15F,
+ 0x160, 0x3B16, 0x4CA2, 0x52FA, 0x6F60E7, -1 };
+ TestingProfile profile;
+ for (size_t i = 0; i < arraysize(ids); ++i) {
+ profile.GetPrefs()->SetInteger(prefs::kGeoIDAtInstall, ids[i]);
+ ScopedVector<TemplateURL> urls;
+ size_t url_count;
+ TemplateURLPrepopulateData::GetPrepopulatedEngines(
+ profile.GetPrefs(), &(urls.get()), &url_count);
+ std::set<int> unique_ids;
+ for (size_t turl_i = 0; turl_i < urls.size(); ++turl_i) {
+ ASSERT_TRUE(unique_ids.find(urls[turl_i]->prepopulate_id()) ==
+ unique_ids.end());
+ unique_ids.insert(urls[turl_i]->prepopulate_id());
+ }
+ }
+}
diff --git a/chrome/browser/template_url_unittest.cc b/chrome/browser/template_url_unittest.cc
new file mode 100644
index 0000000..d5d745f
--- /dev/null
+++ b/chrome/browser/template_url_unittest.cc
@@ -0,0 +1,386 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/string_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/rlz/rlz.h"
+#include "chrome/browser/template_url.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TemplateURLTest : public testing::Test {
+ public:
+ virtual void TearDown() {
+ delete TemplateURLRef::google_base_url_;
+ TemplateURLRef::google_base_url_ = NULL;
+ }
+
+ void CheckSuggestBaseURL(const wchar_t* base_url,
+ const wchar_t* base_suggest_url) const {
+ delete TemplateURLRef::google_base_url_;
+ TemplateURLRef::google_base_url_ = new std::wstring(base_url);
+ EXPECT_STREQ(base_suggest_url,
+ TemplateURLRef::GoogleBaseSuggestURLValue().c_str());
+ }
+};
+
+TEST_F(TemplateURLTest, Defaults) {
+ TemplateURL url;
+ ASSERT_FALSE(url.show_in_default_list());
+ ASSERT_FALSE(url.safe_for_autoreplace());
+ ASSERT_EQ(0, url.prepopulate_id());
+}
+
+TEST_F(TemplateURLTest, TestValidWithComplete) {
+ TemplateURLRef ref(L"{searchTerms}", 0, 0);
+ ASSERT_TRUE(ref.IsValid());
+}
+
+TEST_F(TemplateURLTest, URLRefTestSearchTerms) {
+ TemplateURL t_url;
+ TemplateURLRef ref(L"http://foo{searchTerms}", 0, 0);
+ ASSERT_TRUE(ref.IsValid());
+
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = ref.ReplaceSearchTerms(t_url, L"search",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ ASSERT_TRUE(result.is_valid());
+ ASSERT_EQ("http://foosearch/", result.spec());
+}
+
+TEST_F(TemplateURLTest, URLRefTestCount) {
+ TemplateURL t_url;
+ TemplateURLRef ref(L"http://foo{searchTerms}{count?}", 0, 0);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = ref.ReplaceSearchTerms(t_url, L"X",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ ASSERT_TRUE(result.is_valid());
+ ASSERT_EQ("http://foox/", result.spec());
+}
+
+TEST_F(TemplateURLTest, URLRefTestCount2) {
+ TemplateURL t_url;
+ TemplateURLRef ref(L"http://foo{searchTerms}{count}", 0, 0);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = ref.ReplaceSearchTerms(t_url, L"X",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ ASSERT_TRUE(result.is_valid());
+ ASSERT_EQ("http://foox10/", result.spec());
+}
+
+TEST_F(TemplateURLTest, URLRefTestIndices) {
+ TemplateURL t_url;
+ TemplateURLRef ref(L"http://foo{searchTerms}x{startIndex?}y{startPage?}",
+ 1, 2);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = ref.ReplaceSearchTerms(t_url, L"X",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ ASSERT_TRUE(result.is_valid());
+ ASSERT_EQ("http://fooxxy/", result.spec());
+}
+
+TEST_F(TemplateURLTest, URLRefTestIndices2) {
+ TemplateURL t_url;
+ TemplateURLRef ref(L"http://foo{searchTerms}x{startIndex}y{startPage}", 1, 2);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = ref.ReplaceSearchTerms(t_url, L"X",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ ASSERT_TRUE(result.is_valid());
+ ASSERT_EQ("http://fooxx1y2/", result.spec());
+}
+
+TEST_F(TemplateURLTest, URLRefTestEncoding) {
+ TemplateURL t_url;
+ TemplateURLRef ref(
+ L"http://foo{searchTerms}x{inputEncoding?}y{outputEncoding?}a", 1, 2);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = ref.ReplaceSearchTerms(t_url, L"X",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ ASSERT_TRUE(result.is_valid());
+ ASSERT_EQ("http://fooxxutf-8ya/", result.spec());
+}
+
+TEST_F(TemplateURLTest, InputEncodingBeforeSearchTerm) {
+ TemplateURL t_url;
+ TemplateURLRef ref(
+ L"http://foox{inputEncoding?}a{searchTerms}y{outputEncoding?}b", 1, 2);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = ref.ReplaceSearchTerms(t_url, L"X",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ ASSERT_TRUE(result.is_valid());
+ ASSERT_EQ("http://fooxutf-8axyb/", result.spec());
+}
+
+TEST_F(TemplateURLTest, URLRefTestEncoding2) {
+ TemplateURL t_url;
+ TemplateURLRef ref(
+ L"http://foo{searchTerms}x{inputEncoding}y{outputEncoding}a", 1, 2);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = ref.ReplaceSearchTerms(t_url, L"X",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ ASSERT_TRUE(result.is_valid());
+ ASSERT_EQ("http://fooxxutf-8yutf-8a/", result.spec());
+}
+
+TEST_F(TemplateURLTest, URLRefTermToWide) {
+ struct ToWideCase {
+ const char* encoded_search_term;
+ const wchar_t* expected_decoded_term;
+ } to_wide_cases[] = {
+ {"hello+world", L"hello world"},
+ // Test some big-5 input.
+ {"%a7A%A6%6e+to+you", L"\x4f60\x597d to you"},
+ // Test some UTF-8 input. We should fall back to this when the encoding
+ // doesn't look like big-5. We have a '5' in the middle, which is an invalid
+ // Big-5 trailing byte.
+ {"%e4%bd%a05%e5%a5%bd+to+you", L"\x4f60\x35\x597d to you"},
+ // Undecodable input should stay escaped.
+ {"%91%01+abcd", L"%91%01 abcd"},
+ };
+
+ TemplateURL t_url;
+
+ // Set one input encoding: big-5. This is so we can test fallback to UTF-8.
+ std::vector<std::string> encodings;
+ encodings.push_back("big-5");
+ t_url.set_input_encodings(encodings);
+
+ TemplateURLRef ref(L"http://foo?q={searchTerms}", 1, 2);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+
+ for (int i = 0; i < arraysize(to_wide_cases); i++) {
+ std::wstring result = ref.SearchTermToWide(t_url,
+ to_wide_cases[i].encoded_search_term);
+
+ EXPECT_EQ(std::wstring(to_wide_cases[i].expected_decoded_term), result);
+ }
+}
+
+TEST_F(TemplateURLTest, SetFavIcon) {
+ TemplateURL url;
+ GURL favicon_url("http://favicon.url");
+ url.SetFavIconURL(favicon_url);
+ ASSERT_EQ(1, url.image_refs().size());
+ ASSERT_TRUE(favicon_url == url.GetFavIconURL());
+
+ GURL favicon_url2("http://favicon2.url");
+ url.SetFavIconURL(favicon_url2);
+ ASSERT_EQ(1, url.image_refs().size());
+ ASSERT_TRUE(favicon_url2 == url.GetFavIconURL());
+}
+
+TEST_F(TemplateURLTest, DisplayURLToURLRef) {
+ struct TestData {
+ const std::wstring url;
+ const std::wstring expected_result;
+ } data[] = {
+ { L"http://foo{searchTerms}x{inputEncoding}y{outputEncoding}a",
+ L"http://foo%sx{inputEncoding}y{outputEncoding}a" },
+ { L"http://X",
+ L"http://X" },
+ { L"http://foo{searchTerms",
+ L"http://foo{searchTerms" },
+ { L"http://foo{searchTerms}{language}",
+ L"http://foo%s{language}" },
+ };
+ for (int i = 0; i < arraysize(data); ++i) {
+ TemplateURLRef ref(data[i].url, 1, 2);
+ EXPECT_EQ(data[i].expected_result, ref.DisplayURL());
+ EXPECT_EQ(data[i].url,
+ TemplateURLRef::DisplayURLToURLRef(ref.DisplayURL()));
+ }
+}
+
+TEST_F(TemplateURLTest, ReplaceSearchTerms) {
+ struct TestData {
+ const std::wstring url;
+ const std::string expected_result;
+ } data[] = {
+ { L"http://foo/{language}{searchTerms}{inputEncoding}",
+ "http://foo/{language}XUTF-8" },
+ { L"http://foo/{language}{inputEncoding}{searchTerms}",
+ "http://foo/{language}UTF-8X" },
+ { L"http://foo/{searchTerms}{language}{inputEncoding}",
+ "http://foo/X{language}UTF-8" },
+ { L"http://foo/{searchTerms}{inputEncoding}{language}",
+ "http://foo/XUTF-8{language}" },
+ { L"http://foo/{inputEncoding}{searchTerms}{language}",
+ "http://foo/UTF-8X{language}" },
+ { L"http://foo/{inputEncoding}{language}{searchTerms}",
+ "http://foo/UTF-8{language}X" },
+ { L"http://foo/{language}a{searchTerms}a{inputEncoding}a",
+ "http://foo/{language}aXaUTF-8a" },
+ { L"http://foo/{language}a{inputEncoding}a{searchTerms}a",
+ "http://foo/{language}aUTF-8aXa" },
+ { L"http://foo/{searchTerms}a{language}a{inputEncoding}a",
+ "http://foo/Xa{language}aUTF-8a" },
+ { L"http://foo/{searchTerms}a{inputEncoding}a{language}a",
+ "http://foo/XaUTF-8a{language}a" },
+ { L"http://foo/{inputEncoding}a{searchTerms}a{language}a",
+ "http://foo/UTF-8aXa{language}a" },
+ { L"http://foo/{inputEncoding}a{language}a{searchTerms}a",
+ "http://foo/UTF-8a{language}aXa" },
+ };
+ TemplateURL turl;
+ turl.add_input_encoding("UTF-8");
+ for (int i = 0; i < arraysize(data); ++i) {
+ TemplateURLRef ref(data[i].url, 1, 2);
+ EXPECT_TRUE(ref.IsValid());
+ EXPECT_TRUE(ref.SupportsReplacement());
+ std::string expected_result = data[i].expected_result;
+ ReplaceSubstringsAfterOffset(&expected_result, 0, "{language}",
+ WideToASCII(g_browser_process->GetApplicationLocale()));
+ GURL result = ref.ReplaceSearchTerms(turl, L"X",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ EXPECT_TRUE(result.is_valid());
+ EXPECT_EQ(expected_result, result.spec());
+ }
+}
+
+
+// Tests replacing search terms in various encodings and making sure the
+// generated URL matches the expected value.
+TEST_F(TemplateURLTest, ReplaceArbitrarySearchTerms) {
+ struct TestData {
+ const std::string encoding;
+ const std::wstring search_term;
+ const std::wstring url;
+ const std::string expected_result;
+ } data[] = {
+ { "BIG5", L"\x60BD", L"http://foo/{searchTerms}{inputEncoding}",
+ "http://foo/%B1~BIG5" },
+ { "UTF-8", L"blah", L"http://foo/{searchTerms}{inputEncoding}",
+ "http://foo/blahUTF-8" },
+ };
+ for (int i = 0; i < arraysize(data); ++i) {
+ TemplateURL turl;
+ turl.add_input_encoding(data[i].encoding);
+ TemplateURLRef ref(data[i].url, 1, 2);
+ GURL result = ref.ReplaceSearchTerms(turl, data[i].search_term,
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ EXPECT_TRUE(result.is_valid());
+ EXPECT_EQ(data[i].expected_result, result.spec());
+ }
+}
+
+TEST_F(TemplateURLTest, Suggestions) {
+ struct TestData {
+ const int accepted_suggestion;
+ const std::wstring original_query_for_suggestion;
+ const std::string expected_result;
+ } data[] = {
+ { TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring(),
+ "http://bar/foo?q=foobar" },
+ { TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, L"foo",
+ "http://bar/foo?q=foobar" },
+ { TemplateURLRef::NO_SUGGESTION_CHOSEN, std::wstring(),
+ "http://bar/foo?aq=f&q=foobar" },
+ { TemplateURLRef::NO_SUGGESTION_CHOSEN, L"foo",
+ "http://bar/foo?aq=f&q=foobar" },
+ { 0, std::wstring(), "http://bar/foo?aq=0&oq=&q=foobar" },
+ { 1, L"foo", "http://bar/foo?aq=1&oq=foo&q=foobar" },
+ };
+ TemplateURL turl;
+ turl.add_input_encoding("UTF-8");
+ TemplateURLRef ref(L"http://bar/foo?{google:acceptedSuggestion}"
+ L"{google:originalQueryForSuggestion}q={searchTerms}", 1, 2);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+ for (int i = 0; i < arraysize(data); ++i) {
+ GURL result = ref.ReplaceSearchTerms(turl, L"foobar",
+ data[i].accepted_suggestion, data[i].original_query_for_suggestion);
+ EXPECT_TRUE(result.is_valid());
+ EXPECT_EQ(data[i].expected_result, result.spec());
+ }
+}
+
+TEST_F(TemplateURLTest, RLZ) {
+ std::wstring rlz_string;
+ RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz_string);
+
+ TemplateURL t_url;
+ TemplateURLRef ref(L"http://bar/{google:RLZ}{searchTerms}", 1, 2);
+ ASSERT_TRUE(ref.IsValid());
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = ref.ReplaceSearchTerms(t_url, L"x",
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring());
+ ASSERT_TRUE(result.is_valid());
+ // TODO(levin): fix this!
+ // ASSERT_EQ("http://bar/" + WideToUTF8(rlz_string) + "x", result.spec());
+}
+
+TEST_F(TemplateURLTest, HostAndSearchTermKey) {
+ struct TestData {
+ const std::wstring url;
+ const std::string host;
+ const std::string path;
+ const std::string search_term_key;
+ } data[] = {
+ { L"http://blah/?foo=bar&q={searchTerms}&b=x", "blah", "/", "q"},
+
+ // No query key should result in empty values.
+ { L"http://blah/{searchTerms}", "", "", ""},
+
+ // No term should result in empty values.
+ { L"http://blah/", "", "", ""},
+
+ // Multiple terms should result in empty values.
+ { L"http://blah/?q={searchTerms}&x={searchTerms}", "", "", ""},
+
+ // Term in the host shouldn't match.
+ { L"http://{searchTerms}", "", "", ""},
+
+ { L"http://blah/?q={searchTerms}", "blah", "/", "q"},
+
+ // Single term with extra chars in value should match.
+ { L"http://blah/?q=stock:{searchTerms}", "blah", "/", "q"},
+
+ };
+
+ TemplateURL t_url;
+ for (int i = 0; i < arraysize(data); ++i) {
+ t_url.SetURL(data[i].url, 0, 0);
+ EXPECT_EQ(data[i].host, t_url.url()->GetHost());
+ EXPECT_EQ(data[i].path, t_url.url()->GetPath());
+ EXPECT_EQ(data[i].search_term_key, t_url.url()->GetSearchTermKey());
+ }
+}
+
+TEST_F(TemplateURLTest, GoogleBaseSuggestURL) {
+ static const struct {
+ const wchar_t* const base_url;
+ const wchar_t* const base_suggest_url;
+ } data[] = {
+ { L"http://google.com/", L"http://clients1.google.com/complete/", },
+ { L"http://www.google.com/", L"http://clients1.google.com/complete/", },
+ { L"http://www.google.co.uk/", L"http://clients1.google.co.uk/complete/", },
+ { L"http://www.google.com.by/",
+ L"http://clients1.google.com.by/complete/", },
+ { L"http://google.com/intl/xx/", L"http://clients1.google.com/complete/", },
+ };
+
+ for (int i = 0; i < arraysize(data); ++i)
+ CheckSuggestBaseURL(data[i].base_url, data[i].base_suggest_url);
+}
+
+TEST_F(TemplateURLTest, Keyword) {
+ TemplateURL t_url;
+ t_url.SetURL(L"http://www.google.com/search", 0, 0);
+ EXPECT_FALSE(t_url.autogenerate_keyword());
+ t_url.set_keyword(L"foo");
+ EXPECT_EQ(L"foo", t_url.keyword());
+ t_url.set_autogenerate_keyword(true);
+ EXPECT_TRUE(t_url.autogenerate_keyword());
+ EXPECT_EQ(L"google.com", t_url.keyword());
+ t_url.set_keyword(L"foo");
+ EXPECT_FALSE(t_url.autogenerate_keyword());
+ EXPECT_EQ(L"foo", t_url.keyword());
+}
diff --git a/chrome/browser/views/clear_browsing_data.cc b/chrome/browser/views/clear_browsing_data.cc
index 2bdd1f2..b71bf99 100644
--- a/chrome/browser/views/clear_browsing_data.cc
+++ b/chrome/browser/views/clear_browsing_data.cc
@@ -6,7 +6,7 @@
#include "chrome/app/locales/locale_settings.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/views/standard_layout.h"
#include "chrome/common/l10n_util.h"
#include "chrome/views/background.h"
diff --git a/chrome/browser/views/edit_keyword_controller.cc b/chrome/browser/views/edit_keyword_controller.cc
index 86f1cd0..4eb913f 100644
--- a/chrome/browser/views/edit_keyword_controller.cc
+++ b/chrome/browser/views/edit_keyword_controller.cc
@@ -7,8 +7,8 @@
#include "base/string_util.h"
#include "chrome/app/theme/theme_resources.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/url_fixer_upper.h"
#include "chrome/browser/user_metrics.h"
#include "chrome/browser/views/keyword_editor_view.h"
diff --git a/chrome/browser/views/first_run_bubble.cc b/chrome/browser/views/first_run_bubble.cc
index 25b01db..ac6678a 100644
--- a/chrome/browser/views/first_run_bubble.cc
+++ b/chrome/browser/views/first_run_bubble.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/options_window.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/views/standard_layout.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"
diff --git a/chrome/browser/views/keyword_editor_view.cc b/chrome/browser/views/keyword_editor_view.cc
index e4acaa6..be35283 100644
--- a/chrome/browser/views/keyword_editor_view.cc
+++ b/chrome/browser/views/keyword_editor_view.cc
@@ -12,8 +12,8 @@
#include "chrome/app/theme/theme_resources.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/user_metrics.h"
#include "chrome/browser/views/edit_keyword_controller.h"
#include "chrome/browser/views/standard_layout.h"
diff --git a/chrome/browser/views/keyword_editor_view.h b/chrome/browser/views/keyword_editor_view.h
index c2135a4..879ed24 100644
--- a/chrome/browser/views/keyword_editor_view.h
+++ b/chrome/browser/views/keyword_editor_view.h
@@ -9,7 +9,7 @@
#include <map>
#include "base/logging.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/views/dialog_delegate.h"
#include "chrome/views/native_button.h"
#include "chrome/views/table_view.h"
diff --git a/chrome/browser/views/keyword_editor_view_unittest.cc b/chrome/browser/views/keyword_editor_view_unittest.cc
index 4d04a07..1bbb43c 100644
--- a/chrome/browser/views/keyword_editor_view_unittest.cc
+++ b/chrome/browser/views/keyword_editor_view_unittest.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/views/keyword_editor_view.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc
index 8c727b7..cad8583 100644
--- a/chrome/browser/views/location_bar_view.cc
+++ b/chrome/browser/views/location_bar_view.cc
@@ -13,9 +13,9 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/info_bubble.h"
#include "chrome/browser/views/first_run_bubble.h"
diff --git a/chrome/browser/views/options/general_page_view.cc b/chrome/browser/views/options/general_page_view.cc
index a7964f6..d506fdc 100644
--- a/chrome/browser/views/options/general_page_view.cc
+++ b/chrome/browser/views/options/general_page_view.cc
@@ -15,10 +15,10 @@
#include "chrome/browser/dom_ui/new_tab_ui.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/session_startup_pref.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/shell_integration.h"
+#include "chrome/browser/session_startup_pref.h"
+#include "chrome/browser/template_url.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/browser/url_fixer_upper.h"
#include "chrome/browser/views/keyword_editor_view.h"
#include "chrome/browser/views/options/options_group_view.h"
diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc
index 7791289..3232ec4 100644
--- a/chrome/browser/views/tabs/tab_strip.cc
+++ b/chrome/browser/views/tabs/tab_strip.cc
@@ -1470,17 +1470,8 @@ void TabStrip::StartResizeLayoutAnimation() {
}
void TabStrip::StartInsertTabAnimation(int index) {
- // Don't shock users by letting all tabs move when they are focused
- // on the tab-strip. Wait for later, when they aren't looking.
- int last_tab_index = GetTabCount() - 2;
- if (last_tab_index > 0) {
- Tab* last_tab = GetTabAt(last_tab_index);
- available_width_for_tabs_ = std::min(
- GetAvailableWidthForTabs(last_tab) + last_tab->width(),
- width() - (kNewTabButtonHOffset + newtab_button_size_.width()));
- } else {
- available_width_for_tabs_ = -1;
- }
+ // The TabStrip can now use its entire width to lay out Tabs.
+ available_width_for_tabs_ = -1;
if (active_animation_.get())
active_animation_->Stop();
active_animation_.reset(new InsertTabAnimation(this, index));
diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc
index a3f8e55..d736ac4 100644
--- a/chrome/browser/webdata/web_data_service.cc
+++ b/chrome/browser/webdata/web_data_service.cc
@@ -10,7 +10,7 @@
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/password_manager/ie7_password.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/template_url.h"
#include "chrome/common/chrome_constants.h"
#include "webkit/glue/password_form.h"
#include "webkit/glue/autofill_form.h"
diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc
index af78244..5998282 100644
--- a/chrome/browser/webdata/web_database.cc
+++ b/chrome/browser/webdata/web_database.cc
@@ -15,7 +15,7 @@
#include "base/values.h"
#include "chrome/browser/history/history_database.h"
#include "chrome/browser/password_manager/encryptor.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/template_url.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/scoped_vector.h"
#include "webkit/glue/password_form.h"
diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h
index 54ec840..19059ee 100644
--- a/chrome/browser/webdata/web_database.h
+++ b/chrome/browser/webdata/web_database.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "chrome/browser/meta_table_helper.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/template_url.h"
#include "chrome/common/sqlite_utils.h"
#include "skia/include/SkBitmap.h"
#include "webkit/glue/autofill_form.h"
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc
index 8842e40..349b803 100644
--- a/chrome/browser/webdata/web_database_unittest.cc
+++ b/chrome/browser/webdata/web_database_unittest.cc
@@ -7,7 +7,7 @@
#include "base/string_util.h"
#include "base/time.h"
#include "base/values.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/template_url.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/stl_util-inl.h"
diff --git a/chrome/chrome.xcodeproj/project.pbxproj b/chrome/chrome.xcodeproj/project.pbxproj
index 364e272..4596bf2 100644
--- a/chrome/chrome.xcodeproj/project.pbxproj
+++ b/chrome/chrome.xcodeproj/project.pbxproj
@@ -287,6 +287,8 @@
E45075F70F150C0C003BE099 /* session_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = E45075F60F150C0C003BE099 /* session_id.cc */; };
E45075FA0F150C28003BE099 /* spellcheck_worditerator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9220E9D4839009A6919 /* spellcheck_worditerator.cc */; };
E45075FF0F150C84003BE099 /* ssl_error_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9280E9D4839009A6919 /* ssl_error_info.cc */; };
+ E45076010F150C9D003BE099 /* template_url.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9420E9D4839009A6919 /* template_url.cc */; };
+ E45076180F150DD2003BE099 /* template_url_model.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9460E9D4839009A6919 /* template_url_model.cc */; };
E450761A0F150DE9003BE099 /* url_fetcher.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9510E9D4839009A6919 /* url_fetcher.cc */; };
E45076200F150E0C003BE099 /* web_database.cc in Sources */ = {isa = PBXBuildFile; fileRef = E450761E0F150E0C003BE099 /* web_database.cc */; };
E45076850F1530CD003BE099 /* pref_service.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFBEA0E9D4C9F009A6919 /* pref_service.cc */; };
@@ -319,6 +321,7 @@
E4F324600EE5D011002533CE /* url_database.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFA130E9D48F7009A6919 /* url_database.cc */; };
E4F324650EE5D082002533CE /* sdch_dictionary_fetcher.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFA720E9D4981009A6919 /* sdch_dictionary_fetcher.cc */; };
E4F3247A0EE5D17E002533CE /* referrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = E4F324790EE5D17E002533CE /* referrer.cc */; };
+ E4F324860EE5D26F002533CE /* template_url_parser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9490E9D4839009A6919 /* template_url_parser.cc */; };
E4F324950EE5D758002533CE /* extension_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = E4F324420EE5CE94002533CE /* extension_unittest.cc */; };
E4F324980EE5D7DE002533CE /* snippet_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFA060E9D48F7009A6919 /* snippet_unittest.cc */; };
E4F3256E0EE82C83002533CE /* chrome_paths.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFB8F0E9D4C9F009A6919 /* chrome_paths.cc */; };
@@ -329,9 +332,6 @@
E4F3258C0EE83767002533CE /* libgoogleurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D7BFF6E0E9D540F009A6919 /* libgoogleurl.a */; };
E4F325C80EE83A45002533CE /* ipc_fuzzing_tests.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFBAD0E9D4C9F009A6919 /* ipc_fuzzing_tests.cc */; };
E4F325D10EE83B71002533CE /* ipc_tests.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFBBE0E9D4C9F009A6919 /* ipc_tests.cc */; };
- 9A1EE0F9187ACE2DCB8512E1 /* template_url.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3CCF8AA8A56FF8FE59F0C299 /* template_url.cc */; };
- C39F08C4FFD9C2F98384F56B /* template_url_model.cc in Sources */ = {isa = PBXBuildFile; fileRef = EA72C084DB3FC0FC595E525E /* template_url_model.cc */; };
- B9BF55F87A4BB2FD366B6DDC /* template_url_parser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 28AA584AB2ECFB33C7C7FD8A /* template_url_parser.cc */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -1189,12 +1189,17 @@
4D7BF93F0E9D4839009A6919 /* task_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = task_manager.h; sourceTree = "<group>"; };
4D7BF9400E9D4839009A6919 /* task_manager_resource_providers.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = task_manager_resource_providers.cc; sourceTree = "<group>"; };
4D7BF9410E9D4839009A6919 /* task_manager_resource_providers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = task_manager_resource_providers.h; sourceTree = "<group>"; };
+ 4D7BF9420E9D4839009A6919 /* template_url.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url.cc; sourceTree = "<group>"; };
4D7BF9430E9D4839009A6919 /* template_url.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url.h; sourceTree = "<group>"; };
+ 4D7BF9440E9D4839009A6919 /* template_url_fetcher.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_fetcher.cc; sourceTree = "<group>"; };
4D7BF9450E9D4839009A6919 /* template_url_fetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url_fetcher.h; sourceTree = "<group>"; };
+ 4D7BF9460E9D4839009A6919 /* template_url_model.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_model.cc; sourceTree = "<group>"; };
4D7BF9470E9D4839009A6919 /* template_url_model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url_model.h; sourceTree = "<group>"; };
4D7BF9480E9D4839009A6919 /* template_url_model_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_model_unittest.cc; sourceTree = "<group>"; };
+ 4D7BF9490E9D4839009A6919 /* template_url_parser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_parser.cc; sourceTree = "<group>"; };
4D7BF94A0E9D4839009A6919 /* template_url_parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url_parser.h; sourceTree = "<group>"; };
4D7BF94B0E9D4839009A6919 /* template_url_parser_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_parser_unittest.cc; sourceTree = "<group>"; };
+ 4D7BF94C0E9D4839009A6919 /* template_url_prepopulate_data.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_prepopulate_data.cc; sourceTree = "<group>"; };
4D7BF94D0E9D4839009A6919 /* template_url_prepopulate_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url_prepopulate_data.h; sourceTree = "<group>"; };
4D7BF94E0E9D4839009A6919 /* template_url_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_unittest.cc; sourceTree = "<group>"; };
4D7BF94F0E9D4839009A6919 /* toolbar_model.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = toolbar_model.cc; sourceTree = "<group>"; };
@@ -1734,9 +1739,6 @@
E4F324420EE5CE94002533CE /* extension_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = extension_unittest.cc; sourceTree = "<group>"; };
E4F324780EE5D17E002533CE /* referrer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = referrer.h; sourceTree = "<group>"; };
E4F324790EE5D17E002533CE /* referrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = referrer.cc; sourceTree = "<group>"; };
- 3CCF8AA8A56FF8FE59F0C299 /* template_url.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = template_url.cc; path = browser/search_engines/template_url.cc; sourceTree = SOURCE_ROOT; };
- EA72C084DB3FC0FC595E525E /* template_url_model.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = template_url_model.cc; path = browser/search_engines/template_url_model.cc; sourceTree = SOURCE_ROOT; };
- 28AA584AB2ECFB33C7C7FD8A /* template_url_parser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = template_url_parser.cc; path = browser/search_engines/template_url_parser.cc; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -1944,9 +1946,6 @@
4D7BFDD00E9D527E009A6919 /* Frameworks */,
4D7BFB090E9D4BA1009A6919 /* Projects */,
4D7BF3070E9D477E009A6919 /* Products */,
- 3CCF8AA8A56FF8FE59F0C299 /* template_url.cc */,
- EA72C084DB3FC0FC595E525E /* template_url_model.cc */,
- 28AA584AB2ECFB33C7C7FD8A /* template_url_parser.cc */,
);
sourceTree = "<group>";
};
@@ -2220,12 +2219,17 @@
4D7BF93F0E9D4839009A6919 /* task_manager.h */,
4D7BF9400E9D4839009A6919 /* task_manager_resource_providers.cc */,
4D7BF9410E9D4839009A6919 /* task_manager_resource_providers.h */,
+ 4D7BF9420E9D4839009A6919 /* template_url.cc */,
4D7BF9430E9D4839009A6919 /* template_url.h */,
+ 4D7BF9440E9D4839009A6919 /* template_url_fetcher.cc */,
4D7BF9450E9D4839009A6919 /* template_url_fetcher.h */,
+ 4D7BF9460E9D4839009A6919 /* template_url_model.cc */,
4D7BF9470E9D4839009A6919 /* template_url_model.h */,
4D7BF9480E9D4839009A6919 /* template_url_model_unittest.cc */,
+ 4D7BF9490E9D4839009A6919 /* template_url_parser.cc */,
4D7BF94A0E9D4839009A6919 /* template_url_parser.h */,
4D7BF94B0E9D4839009A6919 /* template_url_parser_unittest.cc */,
+ 4D7BF94C0E9D4839009A6919 /* template_url_prepopulate_data.cc */,
4D7BF94D0E9D4839009A6919 /* template_url_prepopulate_data.h */,
4D640D1A0EAE87BD00EBCFC0 /* template_url_prepopulate_data_unittest.cc */,
4D7BF94E0E9D4839009A6919 /* template_url_unittest.cc */,
@@ -3730,9 +3734,9 @@
E45075FF0F150C84003BE099 /* ssl_error_info.cc in Sources */,
E4F3245D0EE5CFDF002533CE /* starred_url_database.cc in Sources */,
E45075EE0F150ABA003BE099 /* sync_resource_handler.cc in Sources */,
- 9A1EE0F9187ACE2DCB8512E1 /* template_url.cc in Sources */,
- C39F08C4FFD9C2F98384F56B /* template_url_model.cc in Sources */,
- B9BF55F87A4BB2FD366B6DDC /* template_url_parser.cc in Sources */,
+ E45076010F150C9D003BE099 /* template_url.cc in Sources */,
+ E45076180F150DD2003BE099 /* template_url_model.cc in Sources */,
+ E4F324860EE5D26F002533CE /* template_url_parser.cc in Sources */,
4D7BFA320E9D4912009A6919 /* text_database.cc in Sources */,
4D7BFA370E9D4915009A6919 /* text_database_manager.cc in Sources */,
4D7BFA390E9D4918009A6919 /* thumbnail_database.cc in Sources */,
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 2d622a7..37e6c17 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -12,8 +12,8 @@
#include "chrome/browser/browser_prefs.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/sessions/session_service.h"
+#include "chrome/browser/template_url_model.h"
#include "chrome/common/pref_service.h"
class TestingProfile : public Profile {
diff --git a/chrome/test/unit/unit_tests.scons b/chrome/test/unit/unit_tests.scons
index 9a06328..7d0c68a 100644
--- a/chrome/test/unit/unit_tests.scons
+++ b/chrome/test/unit/unit_tests.scons
@@ -213,10 +213,10 @@ if env.Bit('windows'):
'$CHROME_DIR/browser/sessions/tab_restore_service_unittest.cc',
'$CHROME_DIR/browser/site_instance_unittest.cc',
'$CHROME_DIR/browser/tabs/tab_strip_model_unittest.cc',
- '$CHROME_DIR/browser/search_engines/template_url_model_unittest.cc',
- '$CHROME_DIR/browser/search_engines/template_url_parser_unittest.cc',
- '$CHROME_DIR/browser/search_engines/template_url_prepopulate_data_unittest.cc',
- '$CHROME_DIR/browser/search_engines/template_url_unittest.cc',
+ '$CHROME_DIR/browser/template_url_model_unittest.cc',
+ '$CHROME_DIR/browser/template_url_parser_unittest.cc',
+ '$CHROME_DIR/browser/template_url_prepopulate_data_unittest.cc',
+ '$CHROME_DIR/browser/template_url_unittest.cc',
'$CHROME_DIR/browser/url_fixer_upper_unittest.cc',
'$CHROME_DIR/browser/views/bookmark_editor_view_unittest.cc',
'$CHROME_DIR/browser/views/keyword_editor_view_unittest.cc',
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index 6b1a977..f00154e 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -687,19 +687,19 @@
>
</File>
<File
- RelativePath="..\..\browser\search_engines\template_url_model_unittest.cc"
+ RelativePath="..\..\browser\template_url_model_unittest.cc"
>
</File>
<File
- RelativePath="..\..\browser\search_engines\template_url_parser_unittest.cc"
+ RelativePath="..\..\browser\template_url_parser_unittest.cc"
>
</File>
<File
- RelativePath="..\..\browser\search_engines\template_url_prepopulate_data_unittest.cc"
+ RelativePath="..\..\browser\template_url_prepopulate_data_unittest.cc"
>
</File>
<File
- RelativePath="..\..\browser\search_engines\template_url_unittest.cc"
+ RelativePath="..\..\browser\template_url_unittest.cc"
>
</File>
<File