| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/browser/download/download_query.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #include <set> |
| 9 #include <string> |
| 10 #include <vector> |
| 11 |
| 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/stl_util.h" |
| 14 #include "base/string16.h" |
| 15 #include "base/string_split.h" |
| 16 #include "base/utf_string_conversions.h" |
| 17 #include "unicode/regex.h" |
| 18 #include "content/browser/download/download_item.h" |
| 19 |
| 20 namespace download_util { |
| 21 |
| 22 // The FieldInterfaces allow us to keep the templateyness out of the header. |
| 23 |
| 24 // Filter fields can be used to filter DownloadVector out of the result set. |
| 25 class DownloadQuery::FilterFieldInterface { |
| 26 public: |
| 27 virtual ~FilterFieldInterface() {} |
| 28 virtual bool Valid() = 0; |
| 29 virtual bool Matches(const DownloadItem& item) const = 0; |
| 30 }; |
| 31 |
| 32 // Sort fields are used by DownloadComparator to sort DownloadVector. |
| 33 class SortFieldInterface { |
| 34 public: |
| 35 virtual ~SortFieldInterface() {} |
| 36 |
| 37 virtual DownloadQuery::SortFieldDirection direction() const = 0; |
| 38 |
| 39 // Return 0 when left's field is equivalent to right's field, -1 when left < |
| 40 // right, or 1 when left > right. |
| 41 virtual int Compare(const DownloadItem& left, |
| 42 const DownloadItem& right) const = 0; |
| 43 }; |
| 44 |
| 45 namespace { |
| 46 |
| 47 typedef std::vector<SortFieldInterface*> SortFieldVector; |
| 48 |
| 49 // Functor passed to std::sort to sort DownloadVector. |
| 50 class DownloadComparator { |
| 51 public: |
| 52 DownloadComparator(const SortFieldVector& terms) |
| 53 : terms_(terms) { |
| 54 } |
| 55 |
| 56 // Returns true if |left| sorts before |right|. |
| 57 bool operator() (const DownloadItem* left, const DownloadItem* right); |
| 58 |
| 59 private: |
| 60 const SortFieldVector& terms_; |
| 61 |
| 62 // std::sort requires this class to be copyable. |
| 63 }; |
| 64 |
| 65 bool DownloadComparator::operator() (const DownloadItem* left, |
| 66 const DownloadItem* right) { |
| 67 for (SortFieldVector::const_iterator term = terms_.begin(); |
| 68 term != terms_.end(); ++term) { |
| 69 int comparison = (*term)->Compare(*left, *right); |
| 70 if (comparison != 0) |
| 71 return ((*term)->direction() == DownloadQuery::ASCENDING) == (comparison <
0); |
| 72 } |
| 73 if (left->id() != right->id()) |
| 74 return left->id() < right->id(); |
| 75 CHECK_NE(left->db_handle(), right->db_handle()); |
| 76 return left->db_handle() < right->db_handle(); |
| 77 } |
| 78 |
| 79 static int get_start_time(const DownloadItem& item) { |
| 80 return (item.start_time() - base::Time::UnixEpoch()).InMilliseconds(); |
| 81 } |
| 82 |
| 83 static int get_end_time(const DownloadItem& item) { |
| 84 return 0; // TODO(benjhayden): endTime |
| 85 } |
| 86 |
| 87 static bool get_danger_accepted(const DownloadItem& item) { |
| 88 return (item.safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED); |
| 89 } |
| 90 |
| 91 static string16 get_filename(const DownloadItem& item) { |
| 92 return item.full_path().LossyDisplayName(); |
| 93 } |
| 94 |
| 95 template <typename ValueType_> |
| 96 class FilterField : public DownloadQuery::FilterFieldInterface { |
| 97 public: |
| 98 typedef ValueType_ ValueType; |
| 99 explicit FilterField(const ValueType& value) : value_(value) {} |
| 100 virtual ~FilterField() {} |
| 101 virtual bool Valid() OVERRIDE { return true; } |
| 102 |
| 103 protected: |
| 104 const ValueType& value() const { return value_; } |
| 105 |
| 106 private: |
| 107 ValueType value_; |
| 108 }; |
| 109 |
| 110 template <typename StringType> |
| 111 std::string ToUTF8(const StringType& s); |
| 112 |
| 113 template<> std::string ToUTF8(const std::string& s) { |
| 114 return s; |
| 115 } |
| 116 |
| 117 template<> std::string ToUTF8(const string16& s) { |
| 118 return UTF16ToUTF8(s); |
| 119 } |
| 120 |
| 121 template <typename StringType> |
| 122 class FilterFieldRegex : public FilterField<StringType> { |
| 123 public: |
| 124 explicit FilterFieldRegex(const StringType& value) |
| 125 : FilterField<StringType>(value) { |
| 126 } |
| 127 virtual ~FilterFieldRegex() {} |
| 128 using FilterField<StringType>::value; |
| 129 virtual bool Valid() OVERRIDE { |
| 130 UParseError re_err; |
| 131 UErrorCode re_status = U_ZERO_ERROR; |
| 132 pattern_.reset(icu::RegexPattern::compile( |
| 133 icu::UnicodeString::fromUTF8(ToUTF8(value())), |
| 134 re_err, re_status)); |
| 135 return U_SUCCESS(re_status); |
| 136 } |
| 137 |
| 138 protected: |
| 139 bool RegexMatches(const StringType& text) const { |
| 140 UErrorCode status = U_ZERO_ERROR; |
| 141 scoped_ptr<icu::RegexMatcher> matcher(pattern_->matcher( |
| 142 icu::UnicodeString::fromUTF8(ToUTF8(text)), status)); |
| 143 return U_SUCCESS(status) && |
| 144 matcher->find(0, status); |
| 145 } |
| 146 |
| 147 private: |
| 148 scoped_ptr<icu::RegexPattern> pattern_; |
| 149 }; |
| 150 |
| 151 template <typename ValueType> |
| 152 class SortField : public SortFieldInterface { |
| 153 public: |
| 154 explicit SortField(DownloadQuery::SortFieldDirection direction) |
| 155 : direction_(direction) { |
| 156 } |
| 157 virtual ~SortField() {} |
| 158 |
| 159 virtual DownloadQuery::SortFieldDirection direction() const { |
| 160 return direction_; |
| 161 } |
| 162 |
| 163 virtual ValueType GetField(const DownloadItem& item) const = 0; |
| 164 |
| 165 virtual int Compare(const DownloadItem& left, |
| 166 const DownloadItem& right) const OVERRIDE { |
| 167 ValueType left_value = GetField(left), right_value = GetField(right); |
| 168 if (left_value > right_value) return 1; |
| 169 if (left_value < right_value) return -1; |
| 170 if (left_value == right_value) return 0; |
| 171 NOTREACHED(); |
| 172 return 0; |
| 173 } |
| 174 |
| 175 private: |
| 176 DownloadQuery::SortFieldDirection direction_; |
| 177 }; |
| 178 |
| 179 #define LAMBDA(__name, __base, __method, __expr, __ctor_arg_type, __ctor_arg) ({
\ |
| 180 class __name : public __base { \ |
| 181 public: \ |
| 182 explicit __name(__ctor_arg_type x) : __base(x) {} \ |
| 183 virtual __method(const DownloadItem& item) const OVERRIDE { \ |
| 184 return __expr; \ |
| 185 } \ |
| 186 }; \ |
| 187 new __name(__ctor_arg); \ |
| 188 }) |
| 189 |
| 190 SortFieldInterface* GetSortField(DownloadQuery::SortFieldName name, |
| 191 DownloadQuery::SortFieldDirection direction) { |
| 192 switch (name) { |
| 193 #define SORT_FIELD(__name, __type, __expr) \ |
| 194 case DownloadQuery::SORT_FIELD_ ## __name: return LAMBDA( \ |
| 195 SortField ## __name, SortField<__type>, __type GetField, __expr, \ |
| 196 DownloadQuery::SortFieldDirection, direction) |
| 197 SORT_FIELD(START_TIME, int, get_start_time(item)); |
| 198 SORT_FIELD(URL, std::string, item.original_url().spec()); |
| 199 SORT_FIELD(FILENAME, string16, get_filename(item)); |
| 200 SORT_FIELD(DANGER, DownloadItem::DangerType, item.GetDangerType()); |
| 201 SORT_FIELD(DANGER_ACCEPTED, bool, get_danger_accepted(item)); |
| 202 SORT_FIELD(STATE, DownloadItem::DownloadState, item.state()); |
| 203 SORT_FIELD(PAUSED, bool, item.is_paused()); |
| 204 SORT_FIELD(MIME, std::string, item.mime_type()); |
| 205 SORT_FIELD(END_TIME, int, get_end_time(item)); |
| 206 SORT_FIELD(BYTES_RECEIVED, int, item.received_bytes()); |
| 207 SORT_FIELD(TOTAL_BYTES, int, item.total_bytes()); |
| 208 SORT_FIELD(FILE_SIZE, int, 0); // TODO |
| 209 SORT_FIELD(ERROR, int, 0); // TODO |
| 210 #undef SORT_FIELD |
| 211 default: return NULL; |
| 212 } |
| 213 } |
| 214 |
| 215 } // anonymous namespace |
| 216 |
| 217 DownloadQuery::DownloadQuery() |
| 218 : limit_(kuint32max) { |
| 219 } |
| 220 |
| 221 DownloadQuery::~DownloadQuery() { |
| 222 STLDeleteElements(&filter_fields_); |
| 223 } |
| 224 |
| 225 bool DownloadQuery::AddFilter(FilterFieldInterface* field) { |
| 226 if (!field->Valid()) { |
| 227 delete field; |
| 228 return false; |
| 229 } |
| 230 filter_fields_.push_back(field); |
| 231 return true; |
| 232 } |
| 233 |
| 234 #define START_FILTER_FIELDS(__type) \ |
| 235 template<> bool DownloadQuery::Filter(DownloadQuery::FilterFieldName name, \ |
| 236 const __type& _value) { \ |
| 237 typedef __type ValueType; \ |
| 238 switch (static_cast<int>(name)) { |
| 239 #define FILTER_FIELD(__name, __expr) \ |
| 240 case FILTER_FIELD_ ## __name: return AddFilter( \ |
| 241 LAMBDA(FilterField ## __name, FilterField<ValueType>, bool Matches, \ |
| 242 __expr, const ValueType&, _value)); |
| 243 #define FILTER_FIELD_REGEX(__name, __expr) \ |
| 244 case FILTER_FIELD_ ## __name ## _REGEX: return AddFilter(LAMBDA( \ |
| 245 FilterField ## __name ## _REGEX, FilterFieldRegex<ValueType>, \ |
| 246 bool Matches, RegexMatches(__expr), const ValueType&, _value)); |
| 247 #define END_FILTER_FIELDS \ |
| 248 } \ |
| 249 return false; \ |
| 250 } |
| 251 |
| 252 START_FILTER_FIELDS(int) |
| 253 FILTER_FIELD(START_TIME, get_start_time(item)) |
| 254 FILTER_FIELD(END_TIME, get_end_time(item)) |
| 255 FILTER_FIELD(BYTES_RECEIVED, item.received_bytes()) |
| 256 FILTER_FIELD(TOTAL_BYTES, item.total_bytes()) |
| 257 FILTER_FIELD(STARTED_BEFORE, get_start_time(item) < value()) |
| 258 FILTER_FIELD(STARTED_AFTER, get_start_time(item) > value()) |
| 259 FILTER_FIELD(ENDED_BEFORE, get_end_time(item) < value()) |
| 260 FILTER_FIELD(ENDED_AFTER, get_end_time(item) > value()) |
| 261 FILTER_FIELD(TOTAL_BYTES_GREATER, item.total_bytes() > value()) |
| 262 FILTER_FIELD(TOTAL_BYTES_LESS, item.total_bytes() < value()) |
| 263 FILTER_FIELD(FILE_SIZE_GREATER, false) // TODO |
| 264 FILTER_FIELD(FILE_SIZE_LESS, false) // TODO |
| 265 FILTER_FIELD(FILE_SIZE, 0) // TODO |
| 266 FILTER_FIELD(ERROR, 0) // TODO |
| 267 END_FILTER_FIELDS |
| 268 |
| 269 START_FILTER_FIELDS(bool) |
| 270 FILTER_FIELD(DANGER_ACCEPTED, get_danger_accepted(item)) |
| 271 FILTER_FIELD(PAUSED, item.is_paused()) |
| 272 END_FILTER_FIELDS |
| 273 |
| 274 START_FILTER_FIELDS(std::string) |
| 275 FILTER_FIELD(URL, item.original_url().spec() == value()) |
| 276 FILTER_FIELD_REGEX(URL, item.original_url().spec()) |
| 277 FILTER_FIELD(MIME, item.mime_type() == value()) |
| 278 END_FILTER_FIELDS |
| 279 |
| 280 START_FILTER_FIELDS(string16) |
| 281 FILTER_FIELD(QUERY, item.MatchesQuery(value())) |
| 282 FILTER_FIELD(FILENAME, get_filename(item) == value()) |
| 283 FILTER_FIELD_REGEX(FILENAME, get_filename(item)) |
| 284 END_FILTER_FIELDS |
| 285 |
| 286 START_FILTER_FIELDS(base::Callback<bool(const DownloadItem& item)>) |
| 287 FILTER_FIELD(FILTER, value().Run(item)) |
| 288 END_FILTER_FIELDS |
| 289 |
| 290 START_FILTER_FIELDS(DownloadItem::DangerType) |
| 291 FILTER_FIELD(DANGER, item.GetDangerType() == value()) |
| 292 END_FILTER_FIELDS |
| 293 |
| 294 START_FILTER_FIELDS(DownloadItem::DownloadState) |
| 295 FILTER_FIELD(STATE, item.state() == value()) |
| 296 END_FILTER_FIELDS |
| 297 |
| 298 #undef START_FILTER_FIELDS |
| 299 #undef FILTER_FIELD |
| 300 #undef END_FILTER_FIELDS |
| 301 |
| 302 void DownloadQuery::Sort(DownloadQuery::SortFieldName name, DownloadQuery::SortF
ieldDirection direction) { |
| 303 order_by_fields_.push_back(OrderTerm(name, direction)); |
| 304 } |
| 305 |
| 306 bool DownloadQuery::Matches(const DownloadItem& item) const { |
| 307 for (FilterFieldVector::const_iterator filter_field = filter_fields_.begin(); |
| 308 filter_field != filter_fields_.end(); ++filter_field) { |
| 309 if (!(*filter_field)->Matches(item)) |
| 310 return false; |
| 311 } |
| 312 return true; |
| 313 } |
| 314 |
| 315 template <typename InputIterator> |
| 316 void DownloadQuery::Search(InputIterator iter, const InputIterator last, |
| 317 DownloadQuery::DownloadVector* results) const { |
| 318 results->clear(); |
| 319 for (; iter != last; ++iter) { |
| 320 if (Matches(**iter)) |
| 321 results->push_back(*iter); |
| 322 } |
| 323 if (!order_by_fields_.empty()) { |
| 324 SortFieldVector order_terms; |
| 325 for (OrderTermVector::const_iterator iter = order_by_fields_.begin(); |
| 326 iter != order_by_fields_.end(); ++iter) { |
| 327 SortFieldInterface* sort_field = GetSortField(iter->name, iter->direction)
; |
| 328 if (sort_field) |
| 329 order_terms.push_back(sort_field); |
| 330 } |
| 331 std::partial_sort(results->begin(), |
| 332 results->begin() + std::min(limit_, results->size()), |
| 333 results->end(), |
| 334 DownloadComparator(order_terms)); |
| 335 STLDeleteElements(&order_terms); |
| 336 } |
| 337 if (results->size() > limit_) |
| 338 results->resize(limit_); |
| 339 } |
| 340 |
| 341 template void DownloadQuery::Search( |
| 342 std::set<DownloadItem*>::const_iterator iter, |
| 343 const std::set<DownloadItem*>::const_iterator last, |
| 344 DownloadQuery::DownloadVector* results) const; |
| 345 template void DownloadQuery::Search( |
| 346 std::vector<DownloadItem*>::const_iterator iter, |
| 347 const std::vector<DownloadItem*>::const_iterator last, |
| 348 DownloadQuery::DownloadVector* results) const; |
| 349 template void DownloadQuery::Search( |
| 350 std::vector<DownloadItem*>::iterator iter, |
| 351 const std::vector<DownloadItem*>::iterator last, |
| 352 DownloadQuery::DownloadVector* results) const; |
| 353 |
| 354 } // namespace download_util |
| 355 |
| OLD | NEW |