| Index: chrome/browser/download/download_query.cc
|
| diff --git a/chrome/browser/download/download_query.cc b/chrome/browser/download/download_query.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dca924a2d8945ff3f6b6910e7a00ec52d18b8052
|
| --- /dev/null
|
| +++ b/chrome/browser/download/download_query.cc
|
| @@ -0,0 +1,365 @@
|
| +// 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 "chrome/browser/download/download_query.h"
|
| +
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/stl_util-inl.h"
|
| +#include "base/string_split.h"
|
| +#include "base/values.h"
|
| +#include "unicode/regex.h"
|
| +#include "chrome/browser/download/download_item.h"
|
| +
|
| +namespace {
|
| +typedef std::vector<std::string> Strings;
|
| +typedef std::vector<DownloadItem*> DownloadItems;
|
| +
|
| +struct SimpleDownloadItem {
|
| + static const char STATE_IN_PROGRESS[];
|
| + static const char STATE_COMPLETE[];
|
| + static const char STATE_INTERRUPTED[];
|
| + static const char DANGER_SAFE[];
|
| + static const char DANGER_FILE[];
|
| + static const char DANGER_URL[];
|
| +
|
| + explicit SimpleDownloadItem(DownloadItem* download)
|
| + : item(download) {
|
| + CHECK(item);
|
| + }
|
| +
|
| + int id() const { return item->id(); }
|
| + std::string url() const { return item->original_url().spec(); }
|
| + std::string filename() const {
|
| + return item->GetFileNameToReportUser().value();
|
| + }
|
| + std::string danger() const { return DangerString(item->GetDangerType()); }
|
| + bool dangerAccepted() const {
|
| + return item->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED;
|
| + }
|
| + std::string state() const { return StateString(item->state()); }
|
| + bool paused() const { return item->is_paused(); }
|
| + std::string mime() const { return item->mime_type(); }
|
| + int startTime() const {
|
| + return (item->start_time() - base::Time::UnixEpoch()).InMilliseconds();
|
| + }
|
| + int endTime() const { return -1; }
|
| + int bytesReceived() const { return item->received_bytes(); }
|
| + int totalBytes() const { return item->total_bytes(); }
|
| + int fileSize() const { return -1; }
|
| + int error() const { return 0; }
|
| +
|
| + DictionaryValue* ToJSON() const;
|
| +
|
| + static std::string DangerString(DownloadItem::DangerType danger) {
|
| + switch (danger) {
|
| + case DownloadItem::NOT_DANGEROUS: return DANGER_SAFE;
|
| + case DownloadItem::DANGEROUS_FILE: return DANGER_FILE;
|
| + case DownloadItem::DANGEROUS_URL: return DANGER_URL;
|
| + case DownloadItem::DANGEROUS_TYPE_MAX:
|
| + default:
|
| + NOTREACHED();
|
| + return "";
|
| + }
|
| + }
|
| +
|
| + static std::string StateString(DownloadItem::DownloadState state) {
|
| + switch (state) {
|
| + case DownloadItem::IN_PROGRESS: return STATE_IN_PROGRESS;
|
| + case DownloadItem::COMPLETE: return STATE_COMPLETE;
|
| + case DownloadItem::INTERRUPTED: // fall through
|
| + case DownloadItem::CANCELLED: return STATE_INTERRUPTED;
|
| + case DownloadItem::REMOVING:
|
| + case DownloadItem::MAX_DOWNLOAD_STATE:
|
| + default:
|
| + NOTREACHED();
|
| + return "";
|
| + }
|
| + }
|
| +
|
| + DownloadItem* item;
|
| + // Allow copy and assign.
|
| +};
|
| +
|
| +typedef std::vector<SimpleDownloadItem*> SimpleItems;
|
| +
|
| +// Functor passed to std::sort to sort SimpleDownloadItems.
|
| +class DownloadComparator {
|
| + public:
|
| + DownloadComparator(std::string* error_msg, Strings* order_terms)
|
| + : error_msg_(error_msg),
|
| + order_terms_(order_terms) {
|
| + }
|
| +
|
| + bool operator() (const SimpleDownloadItem* left,
|
| + const SimpleDownloadItem* right);
|
| + private:
|
| + static const char kDash = '-';
|
| +
|
| + template <typename FieldType> bool CompareField(
|
| + std::string term,
|
| + std::string field,
|
| + FieldType left,
|
| + FieldType right,
|
| + bool* matched_term,
|
| + bool* cmp) const;
|
| +
|
| + std::string* error_msg_;
|
| + Strings* order_terms_;
|
| + // std::sort requires this class to be copyable.
|
| +};
|
| +
|
| +using download_util::DownloadQuery;
|
| +
|
| +class DownloadSearch : DownloadQuery {
|
| + public:
|
| + DownloadSearch(const DownloadQuery& query, DownloadItems* items);
|
| + ~DownloadSearch() {}
|
| +
|
| + bool IsWellFormed(std::string* error_msg);
|
| + bool Matches(const SimpleDownloadItem& item);
|
| +
|
| + SimpleItems::const_iterator begin() const { return simple_items_.begin(); }
|
| + SimpleItems::const_iterator end() const { return simple_items_.end(); }
|
| +
|
| + bool ReachedLimit(int num_results) {
|
| + return has_limit_ && (num_results >= limit_);
|
| + }
|
| +
|
| + private:
|
| + std::string error_msg_;
|
| + Strings order_terms_;
|
| + SimpleItems simple_items_;
|
| + STLElementDeleter<SimpleItems> delete_simple_items_;
|
| + Strings query_terms_;
|
| + scoped_ptr<icu::RegexPattern> filename_pattern_;
|
| + scoped_ptr<icu::RegexPattern> url_pattern_;
|
| + DownloadComparator comparator_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DownloadSearch);
|
| +};
|
| +
|
| +DictionaryValue* SimpleDownloadItem::ToJSON() const {
|
| + DictionaryValue* json = new DictionaryValue();
|
| +#define FIELD(name, type) \
|
| + json->Set ## type(#name, name());
|
| +#include "chrome/browser/download/simple_download_item_fields.h"
|
| +#undef FIELD
|
| + return json;
|
| +}
|
| +
|
| +bool DownloadComparator::operator() (
|
| + const SimpleDownloadItem* left,
|
| + const SimpleDownloadItem* right) {
|
| + CHECK(left);
|
| + CHECK(right);
|
| + Strings::iterator order_term,
|
| + last_order_term = order_terms_->end();
|
| + for (order_term = order_terms_->begin();
|
| + order_term != last_order_term; ++order_term) {
|
| + bool matched_term = false;
|
| + bool cmp = false;
|
| +#define Integer int
|
| +#define Boolean bool
|
| +#define String std::string
|
| +#define FIELD(name, type) \
|
| + if (CompareField(*order_term, #name, left->name(), right->name(), \
|
| + &matched_term, &cmp)) return cmp; \
|
| + if (matched_term) continue;
|
| +#include "chrome/browser/download/simple_download_item_fields.h"
|
| +#undef FIELD
|
| +#undef String
|
| +#undef Boolean
|
| +#undef Integer
|
| + *error_msg_ += " " + *order_term;
|
| + order_terms_->erase(order_term);
|
| + }
|
| + CHECK_NE(left->id(), right->id());
|
| + return left->id() < right->id();
|
| +}
|
| +
|
| +// Return true and set cmp if matched_term and left != right.
|
| +template <typename FieldType>
|
| +bool DownloadComparator::CompareField(
|
| + std::string term,
|
| + std::string field,
|
| + FieldType left,
|
| + FieldType right,
|
| + bool* matched_term,
|
| + bool* cmp) const {
|
| + bool diff = (left != right);
|
| + if (term == field) {
|
| + *matched_term = true;
|
| + if (diff) *cmp = (left < right);
|
| + }
|
| + if (term == kDash + field) {
|
| + *matched_term = true;
|
| + if (diff) *cmp = (left > right);
|
| + }
|
| + return diff && *matched_term;
|
| +}
|
| +
|
| +// NOTE These string constants must match those in
|
| +// chrome/common/extensions/api/extension_api.json
|
| +const char SimpleDownloadItem::STATE_IN_PROGRESS[] = "in progress";
|
| +const char SimpleDownloadItem::STATE_COMPLETE[] = "complete";
|
| +const char SimpleDownloadItem::STATE_INTERRUPTED[] = "interrupted";
|
| +const char SimpleDownloadItem::DANGER_SAFE[] = "safe";
|
| +const char SimpleDownloadItem::DANGER_FILE[] = "file";
|
| +const char SimpleDownloadItem::DANGER_URL[] = "url";
|
| +
|
| +DownloadSearch::DownloadSearch(
|
| + const DownloadQuery& query, DownloadItems* items)
|
| + : DownloadQuery(query),
|
| + delete_simple_items_(&simple_items_),
|
| + comparator_(&error_msg_, &order_terms_) {
|
| + if (has_query_) {
|
| + base::SplitString(query_, ' ', &query_terms_); // TODO handle quopri
|
| + }
|
| + if (has_filenameRegex_) {
|
| + UParseError regex_error; // TODO do these need to outlive the pattern?
|
| + UErrorCode regex_status = U_ZERO_ERROR;
|
| + filename_pattern_.reset(icu::RegexPattern::compile(
|
| + icu::UnicodeString::fromUTF8(filenameRegex_),
|
| + regex_error, regex_status));
|
| + if (!U_SUCCESS(regex_status)) {
|
| + error_msg_ = "bad filenameRegex";
|
| + return;
|
| + }
|
| + }
|
| + if (has_urlRegex_) {
|
| + UParseError regex_error;
|
| + UErrorCode regex_status = U_ZERO_ERROR;
|
| + url_pattern_.reset(icu::RegexPattern::compile(
|
| + icu::UnicodeString::fromUTF8(urlRegex_),
|
| + regex_error, regex_status));
|
| + if (!U_SUCCESS(regex_status)) {
|
| + error_msg_ = "bad urlRegex";
|
| + return;
|
| + }
|
| + }
|
| + for (DownloadItems::const_iterator iter = items->begin();
|
| + iter != items->end(); ++iter) {
|
| + if (*iter != NULL) {
|
| + if (!filter_func_.is_null() && !filter_func_.Run(*iter)) continue;
|
| + simple_items_.push_back(new SimpleDownloadItem(*iter));
|
| + }
|
| + }
|
| + if (has_orderBy_ && (1 < simple_items_.size())) {
|
| + base::SplitString(orderBy_, ' ', &order_terms_);
|
| + std::sort(simple_items_.begin(), simple_items_.end(), comparator_);
|
| + }
|
| +}
|
| +
|
| +bool DownloadSearch::IsWellFormed(std::string* error_msg) {
|
| + if (error_msg != NULL) *error_msg = error_msg_;
|
| + return error_msg_.empty();
|
| +}
|
| +
|
| +bool DownloadSearch::Matches(const SimpleDownloadItem& item) {
|
| +#define FIELD(name, unused_type) \
|
| + if (has_ ## name ## _ && (item.name() != name ## _)) return false;
|
| +#include "chrome/browser/download/simple_download_item_fields.h"
|
| +#undef FIELD
|
| + if (has_state_enum_ && (item.item->state() != state_enum_)) return false;
|
| + if (has_danger_enum_ && (item.item->GetDangerType() != danger_enum_))
|
| + return false;
|
| + if (has_startedBefore_ && (item.startTime() > startedBefore_)) return false;
|
| + if (has_startedAfter_ && (item.startTime() < startedAfter_)) return false;
|
| + if (has_endedBefore_ && (item.endTime() > endedBefore_)) return false;
|
| + if (has_endedAfter_ && (item.endTime() < endedAfter_)) return false;
|
| + if (has_totalBytesGreater_ && (item.totalBytes() < totalBytesGreater_))
|
| + return false;
|
| + if (has_totalBytesLess_ && (item.totalBytes() > totalBytesLess_))
|
| + return false;
|
| + Strings::const_iterator query_term_iter,
|
| + query_term_end = query_terms_.end();
|
| + for (query_term_iter = query_terms_.begin();
|
| + query_term_iter != query_term_end; ++query_term_iter) {
|
| + std::string query_term = *query_term_iter;
|
| + if ((std::string::npos == item.filename().find(query_term)) &&
|
| + (std::string::npos == item.url().find(query_term))) {
|
| + return false;
|
| + }
|
| + }
|
| + if (filename_pattern_.get() != NULL) {
|
| + UErrorCode status = U_ZERO_ERROR;
|
| + scoped_ptr<icu::RegexMatcher> filename_matcher(filename_pattern_->matcher(
|
| + icu::UnicodeString::fromUTF8(item.filename()), status));
|
| + if (U_FAILURE(status)) {
|
| + return false;
|
| + }
|
| + if (!filename_matcher->find(0, status)) return false;
|
| + }
|
| + if (url_pattern_.get() != NULL) {
|
| + UErrorCode status = U_ZERO_ERROR;
|
| + scoped_ptr<icu::RegexMatcher> url_matcher(url_pattern_->matcher(
|
| + icu::UnicodeString::fromUTF8(item.url()), status));
|
| + if (U_FAILURE(status)) {
|
| + return false;
|
| + }
|
| + if (!url_matcher->find(0, status)) return false;
|
| + }
|
| + return true;
|
| +}
|
| +} // anonymous namespace
|
| +
|
| +namespace download_util {
|
| +
|
| +DownloadQuery::DownloadQuery() {
|
| + has_state_enum_ = false;
|
| + has_danger_enum_ = false;
|
| +#define FIELD(name, type) \
|
| + has_ ## name ## _ = false;
|
| +#include "chrome/browser/download/download_query_fields.h"
|
| +#undef FIELD
|
| +}
|
| +
|
| +DownloadQuery::DownloadQuery(const DictionaryValue& json) {
|
| + has_state_enum_ = false;
|
| + has_danger_enum_ = false;
|
| +#define FIELD(name, type) \
|
| + has_ ## name ## _ = json.Get ## type(#name, &name ## _);
|
| +#include "chrome/browser/download/download_query_fields.h"
|
| +#undef FIELD
|
| +}
|
| +
|
| +DownloadQuery* DownloadQuery::filter_func(DownloadQuery::FilterType func) {
|
| + filter_func_ = func;
|
| + return this;
|
| +}
|
| +
|
| +DownloadQuery* DownloadQuery::state_enum(
|
| + DownloadItem::DownloadState stateenum) {
|
| + has_state_enum_ = true;
|
| + state_enum_ = stateenum;
|
| + return this;
|
| +}
|
| +
|
| +DownloadQuery* DownloadQuery::danger_enum(DownloadItem::DangerType dangerenum) {
|
| + has_danger_enum_ = true;
|
| + danger_enum_ = dangerenum;
|
| + return this;
|
| +}
|
| +
|
| +bool DownloadQuery::Search(
|
| + std::vector<DownloadItem*>* items,
|
| + std::string* error_msg,
|
| + ListValue* results) const {
|
| + DownloadSearch search(*this, items);
|
| + items->clear();
|
| + if (!search.IsWellFormed(error_msg)) return false;
|
| + for (SimpleItems::const_iterator iter = search.begin();
|
| + iter != search.end(); ++iter) {
|
| + if (!search.Matches(**iter)) continue;
|
| + items->push_back((*iter)->item);
|
| + if (results != NULL) results->Append((*iter)->ToJSON());
|
| + if (search.ReachedLimit(items->size())) break;
|
| + }
|
| + return true;
|
| +}
|
| +} // namespace download_util
|
| +
|
|
|