mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-19 04:50:16 +01:00
More comments
This commit is contained in:
parent
eb9660edad
commit
f5750bc348
@ -21,13 +21,32 @@
|
|||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
FMPSParser::FMPSParser()
|
FMPSParser::FMPSParser() :
|
||||||
: float_re_("\\s*([+-]?\\d+(?:\\.\\d+)?)\\s*(?:$|(?=::|;;))"),
|
// The float regex ends with (?:$|(?=::|;;)) to ensure it matches all the way
|
||||||
|
// up to the end of the value. Without it, it would match a string that
|
||||||
|
// starts with a number, like "123abc".
|
||||||
|
float_re_("\\s*([+-]?\\d+(?:\\.\\d+)?)\\s*(?:$|(?=::|;;))"),
|
||||||
|
|
||||||
|
// Matches any character except unescaped slashes, colons and semicolons.
|
||||||
string_re_("((?:[^\\\\;:]|(?:\\\\[\\\\:;]))+)(?:$|(?=::|;;))"),
|
string_re_("((?:[^\\\\;:]|(?:\\\\[\\\\:;]))+)(?:$|(?=::|;;))"),
|
||||||
|
|
||||||
|
// Used for replacing escaped characters.
|
||||||
escape_re_("\\\\([\\\\:;])")
|
escape_re_("\\\\([\\\\:;])")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parses a list of things (of type T) that are separated by two consecutive
|
||||||
|
// Separator characters. Each individual thing is parsed by the F function.
|
||||||
|
// For example, to parse this data:
|
||||||
|
// foo::bar::baz
|
||||||
|
// Use:
|
||||||
|
// QVariantList ret;
|
||||||
|
// ParseContainer<':'>(data, ParseValue, &ret);
|
||||||
|
// ret will then contain "foo", "bar", and "baz".
|
||||||
|
// Returns the number of characters that were consumed from data.
|
||||||
|
//
|
||||||
|
// You can parse lists of lists by using different separator characters:
|
||||||
|
// ParseContainer<';'>(data, ParseContainer<':'>, &ret);
|
||||||
template <char Separator, typename F, typename T>
|
template <char Separator, typename F, typename T>
|
||||||
static int ParseContainer(const QStringRef& data, F f, QList<T>* ret) {
|
static int ParseContainer(const QStringRef& data, F f, QList<T>* ret) {
|
||||||
ret->clear();
|
ret->clear();
|
||||||
@ -43,6 +62,7 @@ static int ParseContainer(const QStringRef& data, F f, QList<T>* ret) {
|
|||||||
ret->append(value);
|
ret->append(value);
|
||||||
pos += matched_len;
|
pos += matched_len;
|
||||||
|
|
||||||
|
// Expect two separators in a row
|
||||||
if (pos + 2 <= data.length() && data.at(pos) == Separator
|
if (pos + 2 <= data.length() && data.at(pos) == Separator
|
||||||
&& data.at(pos+1) == Separator) {
|
&& data.at(pos+1) == Separator) {
|
||||||
pos += 2;
|
pos += 2;
|
||||||
@ -56,22 +76,23 @@ static int ParseContainer(const QStringRef& data, F f, QList<T>* ret) {
|
|||||||
|
|
||||||
bool FMPSParser::Parse(const QString& data) {
|
bool FMPSParser::Parse(const QString& data) {
|
||||||
result_ = Result();
|
result_ = Result();
|
||||||
|
|
||||||
|
// Only return success if we matched the whole string
|
||||||
return ParseListList(data, &result_) == data.length();
|
return ParseListList(data, &result_) == data.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
int FMPSParser::ParseValue(const QString& data, QVariant* ret) const {
|
|
||||||
return ParseValueRef(QStringRef(&data), ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FMPSParser::ParseValueRef(const QStringRef& data, QVariant* ret) const {
|
int FMPSParser::ParseValueRef(const QStringRef& data, QVariant* ret) const {
|
||||||
|
// Try to match a float
|
||||||
int pos = float_re_.indexIn(*data.string(), data.position());
|
int pos = float_re_.indexIn(*data.string(), data.position());
|
||||||
if (pos == data.position()) {
|
if (pos == data.position()) {
|
||||||
*ret = float_re_.cap(1).toDouble();
|
*ret = float_re_.cap(1).toDouble();
|
||||||
return float_re_.matchedLength();
|
return float_re_.matchedLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise try to match a string
|
||||||
pos = string_re_.indexIn(*data.string(), data.position());
|
pos = string_re_.indexIn(*data.string(), data.position());
|
||||||
if (pos == data.position()) {
|
if (pos == data.position()) {
|
||||||
|
// Replace escape sequences with their actual characters
|
||||||
QString value = string_re_.cap(1);
|
QString value = string_re_.cap(1);
|
||||||
value.replace(escape_re_, "\\1");
|
value.replace(escape_re_, "\\1");
|
||||||
*ret = value;
|
*ret = value;
|
||||||
@ -81,18 +102,24 @@ int FMPSParser::ParseValueRef(const QStringRef& data, QVariant* ret) const {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FMPSParser::ParseList(const QString& data, QVariantList* ret) const {
|
// Parses an inner list - a list of values
|
||||||
return ParseListRef(QStringRef(&data), ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FMPSParser::ParseListRef(const QStringRef& data, QVariantList* ret) const {
|
int FMPSParser::ParseListRef(const QStringRef& data, QVariantList* ret) const {
|
||||||
return ParseContainer<':'>(data, boost::bind(&FMPSParser::ParseValueRef, this, _1, _2), ret);
|
return ParseContainer<':'>(data, boost::bind(&FMPSParser::ParseValueRef, this, _1, _2), ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FMPSParser::ParseListList(const QString& data, Result* ret) const {
|
// Parses an outer list - a list of lists
|
||||||
return ParseListListRef(QStringRef(&data), ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FMPSParser::ParseListListRef(const QStringRef& data, Result* ret) const {
|
int FMPSParser::ParseListListRef(const QStringRef& data, Result* ret) const {
|
||||||
return ParseContainer<';'>(data, boost::bind(&FMPSParser::ParseListRef, this, _1, _2), ret);
|
return ParseContainer<';'>(data, boost::bind(&FMPSParser::ParseListRef, this, _1, _2), ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convenience functions that take QStrings instead of QStringRefs. Use the
|
||||||
|
// QStringRef versions if possible, they're faster.
|
||||||
|
int FMPSParser::ParseValue(const QString& data, QVariant* ret) const {
|
||||||
|
return ParseValueRef(QStringRef(&data), ret);
|
||||||
|
}
|
||||||
|
int FMPSParser::ParseList(const QString& data, QVariantList* ret) const {
|
||||||
|
return ParseListRef(QStringRef(&data), ret);
|
||||||
|
}
|
||||||
|
int FMPSParser::ParseListList(const QString& data, Result* ret) const {
|
||||||
|
return ParseListListRef(QStringRef(&data), ret);
|
||||||
|
}
|
||||||
|
@ -24,13 +24,20 @@ class FMPSParser {
|
|||||||
public:
|
public:
|
||||||
FMPSParser();
|
FMPSParser();
|
||||||
|
|
||||||
|
// A FMPS result is a list of lists of values (where a value is a string or
|
||||||
|
// a float).
|
||||||
typedef QList<QVariantList> Result;
|
typedef QList<QVariantList> Result;
|
||||||
|
|
||||||
|
// Parses a FMPS value and returns true on success.
|
||||||
bool Parse(const QString& data);
|
bool Parse(const QString& data);
|
||||||
|
|
||||||
|
// Gets the result of the last successful Parse.
|
||||||
Result result() const { return result_; }
|
Result result() const { return result_; }
|
||||||
|
|
||||||
|
// Returns true if result() is empty.
|
||||||
bool is_empty() const { return result().isEmpty() || result()[0].isEmpty(); }
|
bool is_empty() const { return result().isEmpty() || result()[0].isEmpty(); }
|
||||||
|
|
||||||
|
// Internal functions, public for unit tests
|
||||||
int ParseValue(const QString& data, QVariant* ret) const;
|
int ParseValue(const QString& data, QVariant* ret) const;
|
||||||
int ParseValueRef(const QStringRef& data, QVariant* ret) const;
|
int ParseValueRef(const QStringRef& data, QVariant* ret) const;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user