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