| Index: content/browser/download/download_query.cc
|
| diff --git a/content/browser/download/download_query.cc b/content/browser/download/download_query.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..20ad559276bc71cf3909f3bc0fe02f4e56a7bd89
|
| --- /dev/null
|
| +++ b/content/browser/download/download_query.cc
|
| @@ -0,0 +1,355 @@
|
| +// Copyright (c) 2011 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 "content/browser/download/download_query.h"
|
| +
|
| +#include <algorithm>
|
| +#include <set>
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/stl_util.h"
|
| +#include "base/string16.h"
|
| +#include "base/string_split.h"
|
| +#include "base/utf_string_conversions.h"
|
| +#include "unicode/regex.h"
|
| +#include "content/browser/download/download_item.h"
|
| +
|
| +namespace download_util {
|
| +
|
| +// The FieldInterfaces allow us to keep the templateyness out of the header.
|
| +
|
| +// Filter fields can be used to filter DownloadVector out of the result set.
|
| +class DownloadQuery::FilterFieldInterface {
|
| + public:
|
| + virtual ~FilterFieldInterface() {}
|
| + virtual bool Valid() = 0;
|
| + virtual bool Matches(const DownloadItem& item) const = 0;
|
| +};
|
| +
|
| +// Sort fields are used by DownloadComparator to sort DownloadVector.
|
| +class SortFieldInterface {
|
| + public:
|
| + virtual ~SortFieldInterface() {}
|
| +
|
| + virtual DownloadQuery::SortFieldDirection direction() const = 0;
|
| +
|
| + // Return 0 when left's field is equivalent to right's field, -1 when left <
|
| + // right, or 1 when left > right.
|
| + virtual int Compare(const DownloadItem& left,
|
| + const DownloadItem& right) const = 0;
|
| +};
|
| +
|
| +namespace {
|
| +
|
| +typedef std::vector<SortFieldInterface*> SortFieldVector;
|
| +
|
| +// Functor passed to std::sort to sort DownloadVector.
|
| +class DownloadComparator {
|
| + public:
|
| + DownloadComparator(const SortFieldVector& terms)
|
| + : terms_(terms) {
|
| + }
|
| +
|
| + // Returns true if |left| sorts before |right|.
|
| + bool operator() (const DownloadItem* left, const DownloadItem* right);
|
| +
|
| + private:
|
| + const SortFieldVector& terms_;
|
| +
|
| + // std::sort requires this class to be copyable.
|
| +};
|
| +
|
| +bool DownloadComparator::operator() (const DownloadItem* left,
|
| + const DownloadItem* right) {
|
| + for (SortFieldVector::const_iterator term = terms_.begin();
|
| + term != terms_.end(); ++term) {
|
| + int comparison = (*term)->Compare(*left, *right);
|
| + if (comparison != 0)
|
| + return ((*term)->direction() == DownloadQuery::ASCENDING) == (comparison < 0);
|
| + }
|
| + if (left->id() != right->id())
|
| + return left->id() < right->id();
|
| + CHECK_NE(left->db_handle(), right->db_handle());
|
| + return left->db_handle() < right->db_handle();
|
| +}
|
| +
|
| +static int get_start_time(const DownloadItem& item) {
|
| + return (item.start_time() - base::Time::UnixEpoch()).InMilliseconds();
|
| +}
|
| +
|
| +static int get_end_time(const DownloadItem& item) {
|
| + return 0; // TODO(benjhayden): endTime
|
| +}
|
| +
|
| +static bool get_danger_accepted(const DownloadItem& item) {
|
| + return (item.safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED);
|
| +}
|
| +
|
| +static string16 get_filename(const DownloadItem& item) {
|
| + return item.full_path().LossyDisplayName();
|
| +}
|
| +
|
| +template <typename ValueType_>
|
| +class FilterField : public DownloadQuery::FilterFieldInterface {
|
| + public:
|
| + typedef ValueType_ ValueType;
|
| + explicit FilterField(const ValueType& value) : value_(value) {}
|
| + virtual ~FilterField() {}
|
| + virtual bool Valid() OVERRIDE { return true; }
|
| +
|
| + protected:
|
| + const ValueType& value() const { return value_; }
|
| +
|
| + private:
|
| + ValueType value_;
|
| +};
|
| +
|
| +template <typename StringType>
|
| +std::string ToUTF8(const StringType& s);
|
| +
|
| +template<> std::string ToUTF8(const std::string& s) {
|
| + return s;
|
| +}
|
| +
|
| +template<> std::string ToUTF8(const string16& s) {
|
| + return UTF16ToUTF8(s);
|
| +}
|
| +
|
| +template <typename StringType>
|
| +class FilterFieldRegex : public FilterField<StringType> {
|
| + public:
|
| + explicit FilterFieldRegex(const StringType& value)
|
| + : FilterField<StringType>(value) {
|
| + }
|
| + virtual ~FilterFieldRegex() {}
|
| + using FilterField<StringType>::value;
|
| + virtual bool Valid() OVERRIDE {
|
| + UParseError re_err;
|
| + UErrorCode re_status = U_ZERO_ERROR;
|
| + pattern_.reset(icu::RegexPattern::compile(
|
| + icu::UnicodeString::fromUTF8(ToUTF8(value())),
|
| + re_err, re_status));
|
| + return U_SUCCESS(re_status);
|
| + }
|
| +
|
| + protected:
|
| + bool RegexMatches(const StringType& text) const {
|
| + UErrorCode status = U_ZERO_ERROR;
|
| + scoped_ptr<icu::RegexMatcher> matcher(pattern_->matcher(
|
| + icu::UnicodeString::fromUTF8(ToUTF8(text)), status));
|
| + return U_SUCCESS(status) &&
|
| + matcher->find(0, status);
|
| + }
|
| +
|
| + private:
|
| + scoped_ptr<icu::RegexPattern> pattern_;
|
| +};
|
| +
|
| +template <typename ValueType>
|
| +class SortField : public SortFieldInterface {
|
| + public:
|
| + explicit SortField(DownloadQuery::SortFieldDirection direction)
|
| + : direction_(direction) {
|
| + }
|
| + virtual ~SortField() {}
|
| +
|
| + virtual DownloadQuery::SortFieldDirection direction() const {
|
| + return direction_;
|
| + }
|
| +
|
| + virtual ValueType GetField(const DownloadItem& item) const = 0;
|
| +
|
| + virtual int Compare(const DownloadItem& left,
|
| + const DownloadItem& right) const OVERRIDE {
|
| + ValueType left_value = GetField(left), right_value = GetField(right);
|
| + if (left_value > right_value) return 1;
|
| + if (left_value < right_value) return -1;
|
| + if (left_value == right_value) return 0;
|
| + NOTREACHED();
|
| + return 0;
|
| + }
|
| +
|
| + private:
|
| + DownloadQuery::SortFieldDirection direction_;
|
| +};
|
| +
|
| +#define LAMBDA(__name, __base, __method, __expr, __ctor_arg_type, __ctor_arg) ({ \
|
| + class __name : public __base { \
|
| + public: \
|
| + explicit __name(__ctor_arg_type x) : __base(x) {} \
|
| + virtual __method(const DownloadItem& item) const OVERRIDE { \
|
| + return __expr; \
|
| + } \
|
| + }; \
|
| + new __name(__ctor_arg); \
|
| + })
|
| +
|
| +SortFieldInterface* GetSortField(DownloadQuery::SortFieldName name,
|
| + DownloadQuery::SortFieldDirection direction) {
|
| + switch (name) {
|
| +#define SORT_FIELD(__name, __type, __expr) \
|
| + case DownloadQuery::SORT_FIELD_ ## __name: return LAMBDA( \
|
| + SortField ## __name, SortField<__type>, __type GetField, __expr, \
|
| + DownloadQuery::SortFieldDirection, direction)
|
| + SORT_FIELD(START_TIME, int, get_start_time(item));
|
| + SORT_FIELD(URL, std::string, item.original_url().spec());
|
| + SORT_FIELD(FILENAME, string16, get_filename(item));
|
| + SORT_FIELD(DANGER, DownloadItem::DangerType, item.GetDangerType());
|
| + SORT_FIELD(DANGER_ACCEPTED, bool, get_danger_accepted(item));
|
| + SORT_FIELD(STATE, DownloadItem::DownloadState, item.state());
|
| + SORT_FIELD(PAUSED, bool, item.is_paused());
|
| + SORT_FIELD(MIME, std::string, item.mime_type());
|
| + SORT_FIELD(END_TIME, int, get_end_time(item));
|
| + SORT_FIELD(BYTES_RECEIVED, int, item.received_bytes());
|
| + SORT_FIELD(TOTAL_BYTES, int, item.total_bytes());
|
| + SORT_FIELD(FILE_SIZE, int, 0); // TODO
|
| + SORT_FIELD(ERROR, int, 0); // TODO
|
| +#undef SORT_FIELD
|
| + default: return NULL;
|
| + }
|
| +}
|
| +
|
| +} // anonymous namespace
|
| +
|
| +DownloadQuery::DownloadQuery()
|
| + : limit_(kuint32max) {
|
| +}
|
| +
|
| +DownloadQuery::~DownloadQuery() {
|
| + STLDeleteElements(&filter_fields_);
|
| +}
|
| +
|
| +bool DownloadQuery::AddFilter(FilterFieldInterface* field) {
|
| + if (!field->Valid()) {
|
| + delete field;
|
| + return false;
|
| + }
|
| + filter_fields_.push_back(field);
|
| + return true;
|
| +}
|
| +
|
| +#define START_FILTER_FIELDS(__type) \
|
| + template<> bool DownloadQuery::Filter(DownloadQuery::FilterFieldName name, \
|
| + const __type& _value) { \
|
| + typedef __type ValueType; \
|
| + switch (static_cast<int>(name)) {
|
| +#define FILTER_FIELD(__name, __expr) \
|
| + case FILTER_FIELD_ ## __name: return AddFilter( \
|
| + LAMBDA(FilterField ## __name, FilterField<ValueType>, bool Matches, \
|
| + __expr, const ValueType&, _value));
|
| +#define FILTER_FIELD_REGEX(__name, __expr) \
|
| + case FILTER_FIELD_ ## __name ## _REGEX: return AddFilter(LAMBDA( \
|
| + FilterField ## __name ## _REGEX, FilterFieldRegex<ValueType>, \
|
| + bool Matches, RegexMatches(__expr), const ValueType&, _value));
|
| +#define END_FILTER_FIELDS \
|
| + } \
|
| + return false; \
|
| + }
|
| +
|
| +START_FILTER_FIELDS(int)
|
| + FILTER_FIELD(START_TIME, get_start_time(item))
|
| + FILTER_FIELD(END_TIME, get_end_time(item))
|
| + FILTER_FIELD(BYTES_RECEIVED, item.received_bytes())
|
| + FILTER_FIELD(TOTAL_BYTES, item.total_bytes())
|
| + FILTER_FIELD(STARTED_BEFORE, get_start_time(item) < value())
|
| + FILTER_FIELD(STARTED_AFTER, get_start_time(item) > value())
|
| + FILTER_FIELD(ENDED_BEFORE, get_end_time(item) < value())
|
| + FILTER_FIELD(ENDED_AFTER, get_end_time(item) > value())
|
| + FILTER_FIELD(TOTAL_BYTES_GREATER, item.total_bytes() > value())
|
| + FILTER_FIELD(TOTAL_BYTES_LESS, item.total_bytes() < value())
|
| + FILTER_FIELD(FILE_SIZE_GREATER, false) // TODO
|
| + FILTER_FIELD(FILE_SIZE_LESS, false) // TODO
|
| + FILTER_FIELD(FILE_SIZE, 0) // TODO
|
| + FILTER_FIELD(ERROR, 0) // TODO
|
| +END_FILTER_FIELDS
|
| +
|
| +START_FILTER_FIELDS(bool)
|
| + FILTER_FIELD(DANGER_ACCEPTED, get_danger_accepted(item))
|
| + FILTER_FIELD(PAUSED, item.is_paused())
|
| +END_FILTER_FIELDS
|
| +
|
| +START_FILTER_FIELDS(std::string)
|
| + FILTER_FIELD(URL, item.original_url().spec() == value())
|
| + FILTER_FIELD_REGEX(URL, item.original_url().spec())
|
| + FILTER_FIELD(MIME, item.mime_type() == value())
|
| +END_FILTER_FIELDS
|
| +
|
| +START_FILTER_FIELDS(string16)
|
| + FILTER_FIELD(QUERY, item.MatchesQuery(value()))
|
| + FILTER_FIELD(FILENAME, get_filename(item) == value())
|
| + FILTER_FIELD_REGEX(FILENAME, get_filename(item))
|
| +END_FILTER_FIELDS
|
| +
|
| +START_FILTER_FIELDS(base::Callback<bool(const DownloadItem& item)>)
|
| + FILTER_FIELD(FILTER, value().Run(item))
|
| +END_FILTER_FIELDS
|
| +
|
| +START_FILTER_FIELDS(DownloadItem::DangerType)
|
| + FILTER_FIELD(DANGER, item.GetDangerType() == value())
|
| +END_FILTER_FIELDS
|
| +
|
| +START_FILTER_FIELDS(DownloadItem::DownloadState)
|
| + FILTER_FIELD(STATE, item.state() == value())
|
| +END_FILTER_FIELDS
|
| +
|
| +#undef START_FILTER_FIELDS
|
| +#undef FILTER_FIELD
|
| +#undef END_FILTER_FIELDS
|
| +
|
| +void DownloadQuery::Sort(DownloadQuery::SortFieldName name, DownloadQuery::SortFieldDirection direction) {
|
| + order_by_fields_.push_back(OrderTerm(name, direction));
|
| +}
|
| +
|
| +bool DownloadQuery::Matches(const DownloadItem& item) const {
|
| + for (FilterFieldVector::const_iterator filter_field = filter_fields_.begin();
|
| + filter_field != filter_fields_.end(); ++filter_field) {
|
| + if (!(*filter_field)->Matches(item))
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +template <typename InputIterator>
|
| +void DownloadQuery::Search(InputIterator iter, const InputIterator last,
|
| + DownloadQuery::DownloadVector* results) const {
|
| + results->clear();
|
| + for (; iter != last; ++iter) {
|
| + if (Matches(**iter))
|
| + results->push_back(*iter);
|
| + }
|
| + if (!order_by_fields_.empty()) {
|
| + SortFieldVector order_terms;
|
| + for (OrderTermVector::const_iterator iter = order_by_fields_.begin();
|
| + iter != order_by_fields_.end(); ++iter) {
|
| + SortFieldInterface* sort_field = GetSortField(iter->name, iter->direction);
|
| + if (sort_field)
|
| + order_terms.push_back(sort_field);
|
| + }
|
| + std::partial_sort(results->begin(),
|
| + results->begin() + std::min(limit_, results->size()),
|
| + results->end(),
|
| + DownloadComparator(order_terms));
|
| + STLDeleteElements(&order_terms);
|
| + }
|
| + if (results->size() > limit_)
|
| + results->resize(limit_);
|
| +}
|
| +
|
| +template void DownloadQuery::Search(
|
| + std::set<DownloadItem*>::const_iterator iter,
|
| + const std::set<DownloadItem*>::const_iterator last,
|
| + DownloadQuery::DownloadVector* results) const;
|
| +template void DownloadQuery::Search(
|
| + std::vector<DownloadItem*>::const_iterator iter,
|
| + const std::vector<DownloadItem*>::const_iterator last,
|
| + DownloadQuery::DownloadVector* results) const;
|
| +template void DownloadQuery::Search(
|
| + std::vector<DownloadItem*>::iterator iter,
|
| + const std::vector<DownloadItem*>::iterator last,
|
| + DownloadQuery::DownloadVector* results) const;
|
| +
|
| +} // namespace download_util
|
| +
|
|
|