SongFilter: Parse() throws exception on error

This commit is contained in:
Max Kellermann 2018-07-21 07:20:59 +02:00
parent bd8cf7c53d
commit 821f77325c
4 changed files with 52 additions and 42 deletions

View File

@ -177,7 +177,6 @@ SongFilter::~SongFilter()
/* this destructor exists here just so it won't get inlined */ /* this destructor exists here just so it won't get inlined */
} }
gcc_pure
static std::chrono::system_clock::time_point static std::chrono::system_clock::time_point
ParseTimeStamp(const char *s) ParseTimeStamp(const char *s)
{ {
@ -189,53 +188,39 @@ ParseTimeStamp(const char *s)
/* it's an integral UNIX time stamp */ /* it's an integral UNIX time stamp */
return std::chrono::system_clock::from_time_t((time_t)value); return std::chrono::system_clock::from_time_t((time_t)value);
try { /* try ISO 8601 */
/* try ISO 8601 */ return ParseTimePoint(s, "%FT%TZ");
return ParseTimePoint(s, "%FT%TZ");
} catch (...) {
return std::chrono::system_clock::time_point::min();
}
} }
bool void
SongFilter::Parse(const char *tag_string, const char *value, bool fold_case) SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
{ {
unsigned tag = locate_parse_type(tag_string); unsigned tag = locate_parse_type(tag_string);
if (tag == TAG_NUM_OF_ITEM_TYPES) if (tag == TAG_NUM_OF_ITEM_TYPES)
return false; throw std::runtime_error("Unknown filter type");
if (tag == LOCATE_TAG_BASE_TYPE) { if (tag == LOCATE_TAG_BASE_TYPE) {
if (!uri_safe_local(value)) if (!uri_safe_local(value))
return false; throw std::runtime_error("Bad URI");
/* case folding doesn't work with "base" */ /* case folding doesn't work with "base" */
fold_case = false; fold_case = false;
} }
if (tag == LOCATE_TAG_MODIFIED_SINCE) { if (tag == LOCATE_TAG_MODIFIED_SINCE)
const auto t = ParseTimeStamp(value); items.push_back(Item(tag, ParseTimeStamp(value)));
if (IsNegative(t)) else
return false; items.push_back(Item(tag, value, fold_case));
items.push_back(Item(tag, t));
return true;
}
items.push_back(Item(tag, value, fold_case));
return true;
} }
bool void
SongFilter::Parse(ConstBuffer<const char *> args, bool fold_case) SongFilter::Parse(ConstBuffer<const char *> args, bool fold_case)
{ {
if (args.size == 0 || args.size % 2 != 0) if (args.size == 0 || args.size % 2 != 0)
return false; throw std::runtime_error("Incorrect number of filter arguments");
for (unsigned i = 0; i < args.size; i += 2) for (unsigned i = 0; i < args.size; i += 2)
if (!Parse(args[i], args[i + 1], fold_case)) Parse(args[i], args[i + 1], fold_case);
return false;
return true;
} }
bool bool

View File

@ -112,10 +112,13 @@ public:
private: private:
gcc_nonnull(2,3) gcc_nonnull(2,3)
bool Parse(const char *tag, const char *value, bool fold_case=false); void Parse(const char *tag, const char *value, bool fold_case=false);
public: public:
bool Parse(ConstBuffer<const char *> args, bool fold_case=false); /**
* Throws on error.
*/
void Parse(ConstBuffer<const char *> args, bool fold_case=false);
gcc_pure gcc_pure
bool Match(const DetachedSong &song) const noexcept; bool Match(const DetachedSong &song) const noexcept;

View File

@ -31,6 +31,7 @@
#include "tag/ParseName.hxx" #include "tag/ParseName.hxx"
#include "tag/Mask.hxx" #include "tag/Mask.hxx"
#include "util/ConstBuffer.hxx" #include "util/ConstBuffer.hxx"
#include "util/Exception.hxx"
#include "util/StringAPI.hxx" #include "util/StringAPI.hxx"
#include "SongFilter.hxx" #include "SongFilter.hxx"
#include "BulkEdit.hxx" #include "BulkEdit.hxx"
@ -96,8 +97,11 @@ handle_match(Client &client, Request args, Response &r, bool fold_case)
} }
SongFilter filter; SongFilter filter;
if (!filter.Parse(args, fold_case)) { try {
r.Error(ACK_ERROR_ARG, "incorrect arguments"); filter.Parse(args, fold_case);
} catch (...) {
r.Error(ACK_ERROR_ARG,
GetFullMessage(std::current_exception()).c_str());
return CommandResult::ERROR; return CommandResult::ERROR;
} }
@ -126,8 +130,11 @@ static CommandResult
handle_match_add(Client &client, Request args, Response &r, bool fold_case) handle_match_add(Client &client, Request args, Response &r, bool fold_case)
{ {
SongFilter filter; SongFilter filter;
if (!filter.Parse(args, fold_case)) { try {
r.Error(ACK_ERROR_ARG, "incorrect arguments"); filter.Parse(args, fold_case);
} catch (...) {
r.Error(ACK_ERROR_ARG,
GetFullMessage(std::current_exception()).c_str());
return CommandResult::ERROR; return CommandResult::ERROR;
} }
@ -157,8 +164,11 @@ handle_searchaddpl(Client &client, Request args, Response &r)
const char *playlist = args.shift(); const char *playlist = args.shift();
SongFilter filter; SongFilter filter;
if (!filter.Parse(args, true)) { try {
r.Error(ACK_ERROR_ARG, "incorrect arguments"); filter.Parse(args, true);
} catch (...) {
r.Error(ACK_ERROR_ARG,
GetFullMessage(std::current_exception()).c_str());
return CommandResult::ERROR; return CommandResult::ERROR;
} }
@ -187,9 +197,14 @@ handle_count(Client &client, Request args, Response &r)
} }
SongFilter filter; SongFilter filter;
if (!args.empty() && !filter.Parse(args, false)) { if (!args.empty()) {
r.Error(ACK_ERROR_ARG, "incorrect arguments"); try {
return CommandResult::ERROR; filter.Parse(args, false);
} catch (...) {
r.Error(ACK_ERROR_ARG,
GetFullMessage(std::current_exception()).c_str());
return CommandResult::ERROR;
}
} }
PrintSongCount(r, client.GetPartition(), "", &filter, group); PrintSongCount(r, client.GetPartition(), "", &filter, group);
@ -255,8 +270,11 @@ handle_list(Client &client, Request args, Response &r)
if (!args.empty()) { if (!args.empty()) {
filter.reset(new SongFilter()); filter.reset(new SongFilter());
if (!filter->Parse(args, false)) { try {
r.Error(ACK_ERROR_ARG, "not able to parse args"); filter->Parse(args, false);
} catch (...) {
r.Error(ACK_ERROR_ARG,
GetFullMessage(std::current_exception()).c_str());
return CommandResult::ERROR; return CommandResult::ERROR;
} }
} }

View File

@ -35,6 +35,7 @@
#include "Instance.hxx" #include "Instance.hxx"
#include "BulkEdit.hxx" #include "BulkEdit.hxx"
#include "util/ConstBuffer.hxx" #include "util/ConstBuffer.hxx"
#include "util/Exception.hxx"
#include "util/StringAPI.hxx" #include "util/StringAPI.hxx"
#include "util/NumberParser.hxx" #include "util/NumberParser.hxx"
@ -264,8 +265,11 @@ handle_playlist_match(Client &client, Request args, Response &r,
bool fold_case) bool fold_case)
{ {
SongFilter filter; SongFilter filter;
if (!filter.Parse(args, fold_case)) { try {
r.Error(ACK_ERROR_ARG, "incorrect arguments"); filter.Parse(args, fold_case);
} catch (...) {
r.Error(ACK_ERROR_ARG,
GetFullMessage(std::current_exception()).c_str());
return CommandResult::ERROR; return CommandResult::ERROR;
} }