15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/download/download_query.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/case_conversion.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/string_search.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/prefs/pref_service.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/pref_names.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/content_browser_client.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_item.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/re2/re2/re2.h"
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::DownloadDangerType;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::DownloadItem;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Templatized base::Value::GetAs*().
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <typename T> bool GetAs(const base::Value& in, T* out);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<> bool GetAs(const base::Value& in, bool* out) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return in.GetAsBoolean(out);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<> bool GetAs(const base::Value& in, int* out) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return in.GetAsInteger(out);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<> bool GetAs(const base::Value& in, std::string* out) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return in.GetAsString(out);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)template<> bool GetAs(const base::Value& in, base::string16* out) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return in.GetAsString(out);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template<> bool GetAs(const base::Value& in, std::vector<base::string16>* out) {
54558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  out->clear();
55558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  const base::ListValue* list = NULL;
56558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!in.GetAsList(&list))
57558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return false;
58558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for (size_t i = 0; i < list->GetSize(); ++i) {
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 element;
60558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (!list->GetString(i, &element)) {
61558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      out->clear();
62558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      return false;
63558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
64558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    out->push_back(element);
65558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
66558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return true;
67558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The next several functions are helpers for making Callbacks that access
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadItem fields.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochstatic bool MatchesQuery(
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<base::string16>& query_terms,
74558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    const DownloadItem& item) {
75558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK(!query_terms.empty());
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 url_raw(base::UTF8ToUTF16(item.GetOriginalUrl().spec()));
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 url_formatted = url_raw;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (item.GetBrowserContext()) {
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Profile* profile = Profile::FromBrowserContext(item.GetBrowserContext());
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_formatted = net::FormatUrl(
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        item.GetOriginalUrl(),
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        profile->GetPrefs()->GetString(prefs::kAcceptLanguages));
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 path(item.GetTargetFilePath().LossyDisplayName());
85558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<base::string16>::const_iterator it = query_terms.begin();
87558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch       it != query_terms.end(); ++it) {
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 term = base::i18n::ToLower(*it);
89558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (!base::i18n::StringSearchIgnoringCaseAndAccents(
90558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            term, url_raw, NULL, NULL) &&
91558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        !base::i18n::StringSearchIgnoringCaseAndAccents(
92558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            term, url_formatted, NULL, NULL) &&
93558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        !base::i18n::StringSearchIgnoringCaseAndAccents(
94558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            term, path, NULL, NULL)) {
95558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      return false;
96558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
97558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
98558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return true;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int64 GetStartTimeMsEpoch(const DownloadItem& item) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (item.GetStartTime() - base::Time::UnixEpoch()).InMilliseconds();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static int64 GetEndTimeMsEpoch(const DownloadItem& item) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (item.GetEndTime() - base::Time::UnixEpoch()).InMilliseconds();
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string TimeToISO8601(const base::Time& t) {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Time::Exploded exploded;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  t.UTCExplode(&exploded);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf(
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      exploded.day_of_month, exploded.hour, exploded.minute, exploded.second,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      exploded.millisecond);
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static std::string GetStartTime(const DownloadItem& item) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return TimeToISO8601(item.GetStartTime());
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static std::string GetEndTime(const DownloadItem& item) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return TimeToISO8601(item.GetEndTime());
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool GetDangerAccepted(const DownloadItem& item) {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (item.GetDangerType() ==
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static bool GetExists(const DownloadItem& item) {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !item.GetFileExternallyRemoved();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)static base::string16 GetFilename(const DownloadItem& item) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This filename will be compared with strings that could be passed in by the
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // user, who only sees LossyDisplayNames.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetTargetFilePath().LossyDisplayName();
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::string GetFilenameUTF8(const DownloadItem& item) {
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::UTF16ToUTF8(GetFilename(item));
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::string GetUrl(const DownloadItem& item) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetOriginalUrl().spec();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static DownloadItem::DownloadState GetState(const DownloadItem& item) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetState();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static DownloadDangerType GetDangerType(const DownloadItem& item) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetDangerType();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int GetReceivedBytes(const DownloadItem& item) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetReceivedBytes();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int GetTotalBytes(const DownloadItem& item) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetTotalBytes();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::string GetMimeType(const DownloadItem& item) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetMimeType();
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool IsPaused(const DownloadItem& item) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.IsPaused();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum ComparisonType {LT, EQ, GT};
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |item| matches the filter specified by |value|, |cmptype|,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and |accessor|. |accessor| is conceptually a function that takes a
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadItem and returns one of its fields, which is then compared to
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |value|.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename ValueType>
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool FieldMatches(
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ValueType& value,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ComparisonType cmptype,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Callback<ValueType(const DownloadItem&)>& accessor,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DownloadItem& item) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (cmptype) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case LT: return accessor.Run(item) < value;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case EQ: return accessor.Run(item) == value;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GT: return accessor.Run(item) > value;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper for building a Callback to FieldMatches<>().
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <typename ValueType> DownloadQuery::FilterCallback BuildFilter(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Value& value, ComparisonType cmptype,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ValueType (*accessor)(const DownloadItem&)) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ValueType cpp_value;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetAs(value, &cpp_value)) return DownloadQuery::FilterCallback();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::Bind(&FieldMatches<ValueType>, cpp_value, cmptype,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::Bind(accessor));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |accessor.Run(item)| matches |pattern|.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool FindRegex(
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RE2* pattern,
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Callback<std::string(const DownloadItem&)>& accessor,
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DownloadItem& item) {
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return RE2::PartialMatch(accessor.Run(item), *pattern);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper for building a Callback to FindRegex().
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadQuery::FilterCallback BuildRegexFilter(
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Value& regex_value,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string (*accessor)(const DownloadItem&)) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string regex_str;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetAs(regex_value, &regex_str)) return DownloadQuery::FilterCallback();
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<RE2> pattern(new RE2(regex_str));
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!pattern->ok()) return DownloadQuery::FilterCallback();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::Bind(&FindRegex, base::Owned(pattern.release()),
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::Bind(accessor));
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a ComparisonType to indicate whether a field in |left| is less than,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// greater than or equal to the same field in |right|.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename ValueType>
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ComparisonType Compare(
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Callback<ValueType(const DownloadItem&)>& accessor,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DownloadItem& left, const DownloadItem& right) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ValueType left_value = accessor.Run(left);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ValueType right_value = accessor.Run(right);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (left_value > right_value) return GT;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (left_value < right_value) return LT;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(left_value, right_value);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EQ;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // anonymous namespace
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadQuery::DownloadQuery()
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : limit_(kuint32max) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadQuery::~DownloadQuery() {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AddFilter() pushes a new FilterCallback to filters_. Most FilterCallbacks are
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callbacks to FieldMatches<>(). Search() iterates over given DownloadItems,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// discarding items for which any filter returns false. A DownloadQuery may have
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// zero or more FilterCallbacks.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadQuery::AddFilter(const DownloadQuery::FilterCallback& value) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (value.is_null()) return false;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filters_.push_back(value);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadQuery::AddFilter(DownloadItem::DownloadState state) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddFilter(base::Bind(&FieldMatches<DownloadItem::DownloadState>, state, EQ,
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&GetState)));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadQuery::AddFilter(DownloadDangerType danger) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddFilter(base::Bind(&FieldMatches<DownloadDangerType>, danger, EQ,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&GetDangerType)));
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadQuery::AddFilter(DownloadQuery::FilterType type,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const base::Value& value) {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_BYTES_RECEIVED:
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, EQ, &GetReceivedBytes));
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_DANGER_ACCEPTED:
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<bool>(value, EQ, &GetDangerAccepted));
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case FILTER_EXISTS:
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return AddFilter(BuildFilter<bool>(value, EQ, &GetExists));
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_FILENAME:
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return AddFilter(BuildFilter<base::string16>(value, EQ, &GetFilename));
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_FILENAME_REGEX:
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildRegexFilter(value, &GetFilenameUTF8));
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_MIME:
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, EQ, &GetMimeType));
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_PAUSED:
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<bool>(value, EQ, &IsPaused));
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_QUERY: {
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::vector<base::string16> query_terms;
287558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      return GetAs(value, &query_terms) &&
288558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch             (query_terms.empty() ||
289558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch              AddFilter(base::Bind(&MatchesQuery, query_terms)));
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case FILTER_ENDED_AFTER:
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, GT, &GetEndTime));
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case FILTER_ENDED_BEFORE:
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, LT, &GetEndTime));
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case FILTER_END_TIME:
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, EQ, &GetEndTime));
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_STARTED_AFTER:
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, GT, &GetStartTime));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_STARTED_BEFORE:
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, LT, &GetStartTime));
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_START_TIME:
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, EQ, &GetStartTime));
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_TOTAL_BYTES:
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, EQ, &GetTotalBytes));
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_TOTAL_BYTES_GREATER:
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, GT, &GetTotalBytes));
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_TOTAL_BYTES_LESS:
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, LT, &GetTotalBytes));
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_URL:
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, EQ, &GetUrl));
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_URL_REGEX:
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildRegexFilter(value, &GetUrl));
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadQuery::Matches(const DownloadItem& item) const {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (FilterCallbackVector::const_iterator filter = filters_.begin();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        filter != filters_.end(); ++filter) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!filter->Run(item))
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AddSorter() creates a Sorter and pushes it onto sorters_. A Sorter is a
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// direction and a Callback to Compare<>(). After filtering, Search() makes a
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator functor from the sorters_ and passes the
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator to std::partial_sort. std::partial_sort calls the
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator with different pairs of DownloadItems.  DownloadComparator
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// iterates over the sorters until a callback returns ComparisonType LT or GT.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator returns true or false depending on that ComparisonType and
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the sorter's direction in order to indicate to std::partial_sort whether the
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// left item is after or before the right item. If all sorters return EQ, then
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator compares GetId. A DownloadQuery may have zero or more
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sorters, but there is one DownloadComparator per call to Search().
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct DownloadQuery::Sorter {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef base::Callback<ComparisonType(
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const DownloadItem&, const DownloadItem&)> SortType;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template<typename ValueType>
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static Sorter Build(DownloadQuery::SortDirection adirection,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         ValueType (*accessor)(const DownloadItem&)) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Sorter(adirection, base::Bind(&Compare<ValueType>,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(accessor)));
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Sorter(DownloadQuery::SortDirection adirection,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const SortType& asorter)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : direction(adirection),
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorter(asorter) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~Sorter() {}
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadQuery::SortDirection direction;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SortType sorter;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DownloadQuery::DownloadComparator {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit DownloadComparator(const DownloadQuery::SorterVector& terms)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : terms_(terms) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if |left| sorts before |right|.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool operator() (const DownloadItem* left, const DownloadItem* right);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DownloadQuery::SorterVector& terms_;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // std::sort requires this class to be copyable.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadQuery::DownloadComparator::operator() (
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DownloadItem* left, const DownloadItem* right) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (DownloadQuery::SorterVector::const_iterator term = terms_.begin();
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       term != terms_.end(); ++term) {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (term->sorter.Run(*left, *right)) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case LT: return term->direction == DownloadQuery::ASCENDING;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case GT: return term->direction == DownloadQuery::DESCENDING;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case EQ: break;  // break the switch but not the loop
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_NE(left->GetId(), right->GetId());
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return left->GetId() < right->GetId();
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadQuery::AddSorter(DownloadQuery::SortType type,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              DownloadQuery::SortDirection direction) {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case SORT_END_TIME:
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sorters_.push_back(Sorter::Build<int64>(direction, &GetEndTimeMsEpoch));
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_START_TIME:
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<int64>(direction, &GetStartTimeMsEpoch));
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_URL:
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<std::string>(direction, &GetUrl));
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_FILENAME:
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sorters_.push_back(
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          Sorter::Build<base::string16>(direction, &GetFilename));
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_DANGER:
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<DownloadDangerType>(
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          direction, &GetDangerType));
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_DANGER_ACCEPTED:
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<bool>(direction, &GetDangerAccepted));
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case SORT_EXISTS:
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sorters_.push_back(Sorter::Build<bool>(direction, &GetExists));
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_STATE:
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<DownloadItem::DownloadState>(
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          direction, &GetState));
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_PAUSED:
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<bool>(direction, &IsPaused));
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_MIME:
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<std::string>(direction, &GetMimeType));
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_BYTES_RECEIVED:
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<int>(direction, &GetReceivedBytes));
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_TOTAL_BYTES:
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<int>(direction, &GetTotalBytes));
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadQuery::FinishSearch(DownloadQuery::DownloadVector* results) const {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!sorters_.empty())
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::partial_sort(results->begin(),
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      results->begin() + std::min(limit_, results->size()),
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      results->end(),
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      DownloadComparator(sorters_));
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (results->size() > limit_)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    results->resize(limit_);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
443