Commit 99d363dc authored by EXT Arnaud Clère's avatar EXT Arnaud Clère

WIP move error handling to user's hands

parent d523f5ea
...@@ -198,7 +198,7 @@ protected: ...@@ -198,7 +198,7 @@ protected:
bool tryBind ( bool&& b) { set(QCborValue( b )); return true; } bool tryBind ( bool&& b) { set(QCborValue( b )); return true; }
bool tryBind ( float&& d) { set(QCborValue(double(d))); return true; } bool tryBind ( float&& d) { set(QCborValue(double(d))); return true; }
bool tryBind ( double&& d) { set(QCborValue( d )); return true; } bool tryBind ( double&& d) { set(QCborValue( d )); return true; }
bool tryBind ( quint64&& n) { if (quint64(std::numeric_limits<qint64>::max())<n) { _reportError(qBindExpectedSmallerNumber); return false; } bool tryBind ( quint64&& n) { if (quint64(std::numeric_limits<qint64>::max())<n) { reportError(qBindExpectedSmallerNumber); return false; }
set(QCborValue(qint64(n))); return true; } set(QCborValue(qint64(n))); return true; }
bool tryBind ( qint64&& n) { set(QCborValue( n )); return true; } bool tryBind ( qint64&& n) { set(QCborValue( n )); return true; }
bool tryBind ( QByteArray&& s) { set(QCborValue( s )); return true; } bool tryBind ( QByteArray&& s) { set(QCborValue( s )); return true; }
...@@ -231,10 +231,7 @@ class QCborVisitor : public QAbstractValueReader ...@@ -231,10 +231,7 @@ class QCborVisitor : public QAbstractValueReader
Q_DISABLE_COPY(QCborVisitor) Q_DISABLE_COPY(QCborVisitor)
public: public:
QCborVisitor(QCborValue* v) : cbor(v) { Q_ASSERT(v); } QCborVisitor(QCborValue* v) : cbor(v) { Q_ASSERT(v); }
void reset(QCborValue* v) { cbor=v; Q_ASSERT(v); steps.resize(0); errors.resize(0); } void reset(QCborValue* v) { cbor=v; Q_ASSERT(v); steps.resize(0); }
struct Error { QIdentifierLiteral error; QAsciiData path; QValueStatus zap(QValue&& value) { return value.bind(QUtf8Data(error.utf8()+' '+path.utf8())); } };
QVector<Error> errors;
QAsciiData currentPath() { QAsciiData currentPath() {
QByteArray path; QByteArray path;
...@@ -250,17 +247,17 @@ public: ...@@ -250,17 +247,17 @@ public:
/**/ QSequence sequence(quint32* s=nullptr) { return QValueStatus(this).value().sequence(s); } /**/ QSequence sequence(quint32* s=nullptr) { return QValueStatus(this).value().sequence(s); }
template<typename T> QValueStatus bind ( T&& t) { return QValueStatus(this).value().bind(std::forward<T>(t)); } template<typename T> QValueStatus bind ( T&& t) { return QValueStatus(this).value().bind(std::forward<T>(t)); }
protected: protected:
bool trySequence(quint32* =nullptr) { if (current().isArray ()) { steps.push(Step()); return true; } _reportError(qBindExpectedSequence); return false; } bool trySequence(quint32* =nullptr) { if (current().isArray ()) { steps.push(Step()); return true; } reportError(qBindExpectedSequence); return false; }
bool tryRecord (quint32* =nullptr) { if (current().isMap ()) { steps.push(Step()); return true; } _reportError(qBindExpectedRecord ); return false; } bool tryRecord (quint32* =nullptr) { if (current().isMap ()) { steps.push(Step()); return true; } reportError(qBindExpectedRecord ); return false; }
bool tryNull ( ) { if (current().isNull ()) { return true; } _reportError(qBindExpectedNull ); return false; } bool tryNull ( ) { if (current().isNull ()) { return true; } reportError(qBindExpectedNull ); return false; }
bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s) ) { u = s .toUtf8 (); return true; } return false; } bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s) ) { u = s .toUtf8 (); return true; } return false; }
bool tryBind ( QString& v) { if (current().isString ()) { v = current().toString (); return true; } _reportError(qBindExpectedText ); return false; } bool tryBind ( QString& v) { if (current().isString ()) { v = current().toString (); return true; } reportError(qBindExpectedText ); return false; }
bool tryBind ( bool& v) { if (current().isBool ()) { v = current().toBool (); return true; } _reportError(qBindExpectedBoolean ); return false; } bool tryBind ( bool& v) { if (current().isBool ()) { v = current().toBool (); return true; } reportError(qBindExpectedBoolean ); return false; }
bool tryBind ( qint64& t) { if (current().isInteger ()) { t = current().toInteger (); return true; } _reportError(qBindExpectedInteger ); return false; } bool tryBind ( qint64& t) { if (current().isInteger ()) { t = current().toInteger (); return true; } reportError(qBindExpectedInteger ); return false; }
bool tryBind ( quint64& t) { qint64 i; if (tryBind(i) ) { t = quint64(i) ; return true; } return false; } bool tryBind ( quint64& t) { qint64 i; if (tryBind(i) ) { t = quint64(i) ; return true; } return false; }
bool tryBind ( float& v) { double d; if (tryBind(d) ) { v = float(d) ; return true; } return false; } bool tryBind ( float& v) { double d; if (tryBind(d) ) { v = float(d) ; return true; } return false; }
bool tryBind ( double& v) { if (current().isDouble ()) { v = current().toDouble (); return true; } _reportError(qBindExpectedDecimal ); return false; } bool tryBind ( double& v) { if (current().isDouble ()) { v = current().toDouble (); return true; } reportError(qBindExpectedDecimal ); return false; }
bool tryBind ( QByteArray& v) { QString s; if (current().isByteArray()) { v = current().toByteArray(); return true; } _reportError(qBindExpectedBytes ); return false; } bool tryBind ( QByteArray& v) { QString s; if (current().isByteArray()) { v = current().toByteArray(); return true; } reportError(qBindExpectedBytes ); return false; }
bool tryItem(QIdentifierLiteral u) { steps.last().key=u; return !(steps.last().item = current(1).toMap().value(steps.last().key.latin1())).isUndefined(); } bool tryItem(QIdentifierLiteral u) { steps.last().key=u; return !(steps.last().item = current(1).toMap().value(steps.last().key.latin1())).isUndefined(); }
bool tryItem(QIdentifier& k) { steps.last().key=k; return !(steps.last().item = current(1).toMap().value(steps.last().key.latin1())).isUndefined(); } bool tryItem(QIdentifier& k) { steps.last().key=k; return !(steps.last().item = current(1).toMap().value(steps.last().key.latin1())).isUndefined(); }
...@@ -268,15 +265,13 @@ protected: ...@@ -268,15 +265,13 @@ protected:
bool tryOut ( ) { steps.pop() ; return true; } bool tryOut ( ) { steps.pop() ; return true; }
bool _isOk() const noexcept { return cbor; } bool _isOk() const noexcept { return cbor; }
void _setChoice(bool v) { isChoice=v; } void reportError(QIdentifierLiteral e, QString context = QString()) { if (errorHandler) errorHandler(e, QString(currentPath().latin1()).append(context)); }
void _reportError(QIdentifierLiteral e) { if (!isChoice) errors.append(Error{ e, currentPath() }); }
private: private:
const QCborValue& current(int outer=0) const { Q_ASSERT(0<=outer); return steps.size()-outer <= 0 ? *cbor : steps[steps.size()-outer-1].item; } const QCborValue& current(int outer=0) const { Q_ASSERT(0<=outer); return steps.size()-outer <= 0 ? *cbor : steps[steps.size()-outer-1].item; }
QCborValue* cbor; QCborValue* cbor;
struct Step { QIdentifier key; int idx=-1; QCborValue item; Step() = default; }; struct Step { QIdentifier key; int idx=-1; QCborValue item; Step() = default; };
QStack<Step> steps = QStack<Step>(); QStack<Step> steps = QStack<Step>();
bool isChoice = false;
}; };
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
...@@ -290,20 +285,17 @@ class QCborReader : public QAbstractValueReader, public QCborStreamReader ...@@ -290,20 +285,17 @@ class QCborReader : public QAbstractValueReader, public QCborStreamReader
public: public:
QCborReader(QIODevice* io) : QCborStreamReader(io), cacheVisitor(&cachedValue) { Q_ASSERT(io); } QCborReader(QIODevice* io) : QCborStreamReader(io), cacheVisitor(&cachedValue) { Q_ASSERT(io); }
struct Error { QIdentifierLiteral error; qint64 index; QCborError cborError; QValueStatus zap(QValue&& value) { QByteArray utf8(error.utf8()); utf8.append(' ').append(QByteArray::number(index)); return value.bind(utf8.constData()); } };
QVector<Error> errors;
// Shortcuts // Shortcuts
/**/ QValue value ( ) { return QValueStatus(this).value(); } /**/ QValue value ( ) { return QValueStatus(this).value(); }
/**/ QSequence sequence(quint32* s=nullptr) { return QValueStatus(this).value().sequence(s); } /**/ QSequence sequence(quint32* s=nullptr) { return QValueStatus(this).value().sequence(s); }
template<typename T> QValueStatus bind ( T&& t) { return QValueStatus(this).value().bind(std::forward<T>(t)); } template<typename T> QValueStatus bind ( T&& t) { return QValueStatus(this).value().bind(std::forward<T>(t)); }
protected: protected:
bool trySequence(quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->trySequence(s); } bool trySequence(quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->trySequence(s); }
skipTag(); if (isArray () && enterContainer()) { levels.push(Level()); return true; } _reportError(qBindExpectedSequence); return false; } skipTag(); if (isArray () && enterContainer()) { levels.push(Level()); return true; } reportError(qBindExpectedSequence); return false; }
bool tryRecord (quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->tryRecord(s); } bool tryRecord (quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->tryRecord(s); }
skipTag(); if (isMap () && enterContainer()) { levels.push(Level()); return true; } _reportError(qBindExpectedRecord ); return false; } skipTag(); if (isMap () && enterContainer()) { levels.push(Level()); return true; } reportError(qBindExpectedRecord ); return false; }
bool tryNull ( ) { if (caching) { cacheLevel++; return caching->tryNull() && cacheOut(); } bool tryNull ( ) { if (caching) { cacheLevel++; return caching->tryNull() && cacheOut(); }
skipTag(); if (isNull () && next ()) { return true; } _reportError(qBindExpectedNull ); return false; } skipTag(); if (isNull () && next ()) { return true; } reportError(qBindExpectedNull ); return false; }
bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s)) { u = s.toUtf8(); return true; } return false; } bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s)) { u = s.toUtf8(); return true; } return false; }
bool tryBind ( QString& s) { if (caching) { cacheLevel++; return caching->tryBind(s) && cacheOut(); } bool tryBind ( QString& s) { if (caching) { cacheLevel++; return caching->tryBind(s) && cacheOut(); }
skipTag(); if (isString()) { skipTag(); if (isString()) {
...@@ -315,13 +307,13 @@ protected: ...@@ -315,13 +307,13 @@ protected:
} }
if (r.status == QCborStreamReader::Error) { if (r.status == QCborStreamReader::Error) {
if (!s.isEmpty()) { if (!s.isEmpty()) {
_reportError(qBindIgnoredBytes); reportError(qBindIgnoredBytes);
s.resize(0); s.resize(0);
} }
return false; return false;
} }
return true; return true;
} else { _reportError(qBindExpectedBytes); return false; } } } else { reportError(qBindExpectedBytes); return false; } }
bool tryBind ( QByteArray& s) { if (caching) { cacheLevel++; return caching->tryBind(s) && cacheOut(); } bool tryBind ( QByteArray& s) { if (caching) { cacheLevel++; return caching->tryBind(s) && cacheOut(); }
skipTag(); if (isByteArray()) { skipTag(); if (isByteArray()) {
s.resize(0); s.resize(0);
...@@ -332,36 +324,36 @@ protected: ...@@ -332,36 +324,36 @@ protected:
} }
if (r.status == QCborStreamReader::Error) { if (r.status == QCborStreamReader::Error) {
if (!s.isEmpty()) { if (!s.isEmpty()) {
_reportError(qBindIgnoredBytes); reportError(qBindIgnoredBytes);
s.resize(0); s.resize(0);
} }
return false; return false;
} }
return true; return true;
} else { _reportError(qBindExpectedBytes); return false; } } } else { reportError(qBindExpectedBytes); return false; } }
bool tryBind ( bool& b) { if (caching) { cacheLevel++; return caching->tryBind(b) && cacheOut(); } bool tryBind ( bool& b) { if (caching) { cacheLevel++; return caching->tryBind(b) && cacheOut(); }
skipTag(); if (isBool()) { skipTag(); if (isBool()) {
b=toBool(); b=toBool();
return next(); return next();
} else { _reportError(qBindExpectedBoolean); return false; } } } else { reportError(qBindExpectedBoolean); return false; } }
bool tryBind ( double& n) { if (caching) { cacheLevel++; return caching->tryBind(n) && cacheOut(); } bool tryBind ( double& n) { if (caching) { cacheLevel++; return caching->tryBind(n) && cacheOut(); }
return getNumber(n); } return getNumber(n); }
bool tryBind ( float& n) { double d; bool tryBind ( float& n) { double d;
if (!tryBind(d)) { return false; } if (!tryBind(d)) { return false; }
if (d<double(std::numeric_limits<float>::min()) || if (d<double(std::numeric_limits<float>::min()) ||
double(std::numeric_limits<float>::max()) <d) { _reportError(qBindExpectedSmallerNumber); return false; } double(std::numeric_limits<float>::max()) <d) { reportError(qBindExpectedSmallerNumber); return false; }
n=float(d); return true; } n=float(d); return true; }
bool tryBind ( quint64& t) { if (caching) { cacheLevel++; return caching->tryBind(t) && cacheOut(); } bool tryBind ( quint64& t) { if (caching) { cacheLevel++; return caching->tryBind(t) && cacheOut(); }
quint64 i; bool neg; quint64 i; bool neg;
if (!getInteger(i,neg)) { _reportError(qBindExpectedInteger ); return false; } if (!getInteger(i,neg)) { reportError(qBindExpectedInteger ); return false; }
if ( neg ) { _reportError(qBindExpectedPositiveInteger); return false; } if ( neg ) { reportError(qBindExpectedPositiveInteger); return false; }
t=i; return true; } t=i; return true; }
bool tryBind ( qint64& t) { if (caching) { cacheLevel++; return caching->tryBind(t) && cacheOut(); } bool tryBind ( qint64& t) { if (caching) { cacheLevel++; return caching->tryBind(t) && cacheOut(); }
quint64 i; bool neg; quint64 i; bool neg;
if (!getInteger(i,neg)) { _reportError(qBindExpectedInteger ); return false; } if (!getInteger(i,neg)) { reportError(qBindExpectedInteger ); return false; }
if ( neg ) { if (quint64(-std::numeric_limits<qint64>::min())<i) { _reportError(qBindExpectedSmallerNumber); return false; } t=-qint64(i); return true; } if ( neg ) { if (quint64(-std::numeric_limits<qint64>::min())<i) { reportError(qBindExpectedSmallerNumber); return false; } t=-qint64(i); return true; }
else { if (quint64( std::numeric_limits<qint64>::max())<i) { _reportError(qBindExpectedSmallerNumber); return false; } t= qint64(i); return true; } else { if (quint64( std::numeric_limits<qint64>::max())<i) { reportError(qBindExpectedSmallerNumber); return false; } t= qint64(i); return true; }
} }
bool tryItem( QIdentifierLiteral u) { if (caching) { return caching->tryItem(u); } bool tryItem( QIdentifierLiteral u) { if (caching) { return caching->tryItem(u); }
...@@ -428,20 +420,19 @@ protected: ...@@ -428,20 +420,19 @@ protected:
bool tryAny() { return next(); } bool tryAny() { return next(); }
bool _isOk() const noexcept { return const_cast<QCborReader*>(this)->lastError()==QCborError::NoError; } bool _isOk() const noexcept { return const_cast<QCborReader*>(this)->lastError()==QCborError::NoError; }
void _setChoice(bool b) { isChoice = b; } void reportError(QIdentifierLiteral e, QString context = QString()) { if (errorHandler) errorHandler(e, QString("at index:%1 ").arg(currentOffset()).append(context)); }
void _reportError(QIdentifierLiteral e) { if (!isChoice) errors.append(Error{ e, currentOffset(), lastError() }); }
private: private:
void skipTag() { if (isTag()) next(); } void skipTag() { if (isTag()) next(); }
bool getNumber(double& d) { skipTag(); bool getNumber(double& d) { skipTag();
if (isFloat16()) { d = double(toFloat16()); return next(); } if (isFloat16()) { d = double(toFloat16()); return next(); }
if (isFloat ()) { d = double(toFloat ()); return next(); } if (isFloat ()) { d = double(toFloat ()); return next(); }
if (isDouble ()) { d = toDouble () ; return next(); } if (isDouble ()) { d = toDouble () ; return next(); }
_reportError(qBindExpectedDecimal); return false; reportError(qBindExpectedDecimal); return false;
} }
bool getInteger(quint64&i, bool& isNegative) { skipTag(); bool getInteger(quint64&i, bool& isNegative) { skipTag();
if (isNegativeInteger()) { i = quint64(toNegativeInteger()); isNegative = true ; return next(); } if (isNegativeInteger()) { i = quint64(toNegativeInteger()); isNegative = true ; return next(); }
if (isUnsignedInteger()) { i = toUnsignedInteger() ; isNegative = false; return next(); } if (isUnsignedInteger()) { i = toUnsignedInteger() ; isNegative = false; return next(); }
_reportError(qBindExpectedInteger); return false; reportError(qBindExpectedInteger); return false;
} }
bool isChoice = false; bool isChoice = false;
...@@ -494,18 +485,17 @@ struct QTransmogrifier<QCborValue> { ...@@ -494,18 +485,17 @@ struct QTransmogrifier<QCborValue> {
} }
else if (v->mode()==Read) { else if (v->mode()==Read) {
QValueStatus r; QValueStatus r;
{ auto suspended = v->setErrorHandler();
QScopedChoice choice(v); QCborArray a; if ((r = v.bind(a))) { j = a ; return r; }
QCborArray a; if ((r = v.bind(a))) { j = a ; return r; } QCborMap o; if ((r = v.bind(o))) { j = o ; return r; }
QCborMap o; if ((r = v.bind(o))) { j = o ; return r; } QString t; if ((r = v.bind(t))) { j = QCborValue( t ); return r; }
QString t; if ((r = v.bind(t))) { j = QCborValue( t ); return r; } bool b; if ((r = v.bind(b))) { j = QCborValue( b ); return r; }
bool b; if ((r = v.bind(b))) { j = QCborValue( b ); return r; } qint64 i; if ((r = v.bind(i))) { j = QCborValue( i ); return r; }
qint64 i; if ((r = v.bind(i))) { j = QCborValue( i ); return r; } quint64 u; if ((r = v.bind(u))) { Q_ASSERT(quint64(std::numeric_limits<qint64>::max())<u); // or tryBind<qint64>() would have succeeded
quint64 u; if ((r = v.bind(u))) { Q_ASSERT(quint64(std::numeric_limits<qint64>::max())<u); // or tryBind<qint64>() would have succeeded j = QCborValue(double(u)); return r; }
j = QCborValue(double(u)); return r; } double d; if ((r = v.bind(d))) { j = QCborValue( d ); return r; }
double d; if ((r = v.bind(d))) { j = QCborValue( d ); return r; } QByteArray y; if ((r = v.bind(y))) { j = QCborValue( y ); return r; }
QByteArray y; if ((r = v.bind(y))) { j = QCborValue( y ); return r; } v->setErrorHandler(suspended);
}
if (!(r = v.null())) r.reportError(qBindIgnoredItem); if (!(r = v.null())) r.reportError(qBindIgnoredItem);
/**/ j = QCborValue( ); return r; /**/ j = QCborValue( ); return r;
} }
......
...@@ -102,10 +102,7 @@ class QJsonVisitor : public QAbstractValueReader ...@@ -102,10 +102,7 @@ class QJsonVisitor : public QAbstractValueReader
Q_DISABLE_COPY(QJsonVisitor) Q_DISABLE_COPY(QJsonVisitor)
public: public:
QJsonVisitor(const QJsonValue* v) : json(v) { Q_ASSERT(v); } QJsonVisitor(const QJsonValue* v) : json(v) { Q_ASSERT(v); }
void reset(QJsonValue* v) { json=v; Q_ASSERT(v); steps.resize(0); errors.resize(0); } void reset(QJsonValue* v) { json=v; Q_ASSERT(v); steps.resize(0); }
struct Error { QIdentifierLiteral error; QAsciiData path; QValueStatus zap(QValue&& value) { return value.bind(QUtf8Data(error.utf8()+' '+path.utf8())); } };
QVector<Error> errors;
QAsciiData currentPath() { QAsciiData currentPath() {
QByteArray path; QByteArray path;
...@@ -122,17 +119,17 @@ public: ...@@ -122,17 +119,17 @@ public:
template<typename T> QValueStatus bind ( T&& t) { return QValueStatus(this).value().bind(std::forward<T>(t)); } template<typename T> QValueStatus bind ( T&& t) { return QValueStatus(this).value().bind(std::forward<T>(t)); }
protected: protected:
bool trySequence(quint32* =nullptr) { if (current().isArray ()) { steps.push(Step()); bool trySequence(quint32* =nullptr) { if (current().isArray ()) { steps.push(Step());
return true; } _reportError(qBindExpectedSequence); return false; } return true; } reportError(qBindExpectedSequence); return false; }
bool tryRecord (quint32* =nullptr) { if (current().isObject()) { steps.push(Step()); bool tryRecord (quint32* =nullptr) { if (current().isObject()) { steps.push(Step());
return true; } _reportError(qBindExpectedRecord ); return false; } return true; } reportError(qBindExpectedRecord ); return false; }
bool tryNull ( ) { if (current().isNull ()) { return true; } _reportError(qBindExpectedNull ); return false; } bool tryNull ( ) { if (current().isNull ()) { return true; } reportError(qBindExpectedNull ); return false; }
bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s) ) { u = s .toUtf8 (); return true; } return false; } bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s) ) { u = s .toUtf8 (); return true; } return false; }
bool tryBind ( QString& v) { if (current().isString()) { v = current().toString(); return true; } _reportError(qBindExpectedText ); return false; } bool tryBind ( QString& v) { if (current().isString()) { v = current().toString(); return true; } reportError(qBindExpectedText ); return false; }
bool tryBind ( bool& v) { if (current().isBool ()) { v = current().toBool (); return true; } _reportError(qBindExpectedBoolean ); return false; } bool tryBind ( bool& v) { if (current().isBool ()) { v = current().toBool (); return true; } reportError(qBindExpectedBoolean ); return false; }
bool tryBind ( qint64& t) { double d; if (tryBind(d) ) { t = qint64(d) ; return true; } return false; } bool tryBind ( qint64& t) { double d; if (tryBind(d) ) { t = qint64(d) ; return true; } return false; }
bool tryBind ( quint64& t) { double d; if (tryBind(d) ) { t = quint64(d) ; return true; } return false; } bool tryBind ( quint64& t) { double d; if (tryBind(d) ) { t = quint64(d) ; return true; } return false; }
bool tryBind ( float& v) { double d; if (tryBind(d) ) { v = float(d) ; return true; } return false; } bool tryBind ( float& v) { double d; if (tryBind(d) ) { v = float(d) ; return true; } return false; }
bool tryBind ( double& v) { if (current().isDouble()) { v = current().toDouble(); return true; } _reportError(qBindExpectedDecimal ); return false; } bool tryBind ( double& v) { if (current().isDouble()) { v = current().toDouble(); return true; } reportError(qBindExpectedDecimal ); return false; }
bool tryItem(QIdentifierLiteral u) { steps.last().key=u; return !(steps.last().item = current(1).toObject().value(steps.last().key.latin1())).isUndefined(); } bool tryItem(QIdentifierLiteral u) { steps.last().key=u; return !(steps.last().item = current(1).toObject().value(steps.last().key.latin1())).isUndefined(); }
bool tryItem(QIdentifier& k) { steps.last().key=k; return !(steps.last().item = current(1).toObject().value(steps.last().key.latin1())).isUndefined(); } bool tryItem(QIdentifier& k) { steps.last().key=k; return !(steps.last().item = current(1).toObject().value(steps.last().key.latin1())).isUndefined(); }
...@@ -140,15 +137,13 @@ protected: ...@@ -140,15 +137,13 @@ protected:
bool tryOut ( ) { steps.removeLast(); return true; } bool tryOut ( ) { steps.removeLast(); return true; }
bool _isOk() const noexcept { return true; } bool _isOk() const noexcept { return true; }
void _setChoice(bool v) { isChoice=v; } void reportError(QIdentifierLiteral e, QString context = QString()) { if (errorHandler) errorHandler(e, QString(currentPath().latin1()).append(context)); }
void _reportError(QIdentifierLiteral e) { if (!isChoice) errors.append(Error{ e, currentPath() }); }
private: private:
const QJsonValue& current(int outer=0) const { Q_ASSERT(0<=outer && json); return steps.size()-outer <= 0 ? *json : steps[steps.size()-outer-1].item; } const QJsonValue& current(int outer=0) const { Q_ASSERT(0<=outer && json); return steps.size()-outer <= 0 ? *json : steps[steps.size()-outer-1].item; }
const QJsonValue* json; const QJsonValue* json;
struct Step { QIdentifier key; int idx=-1; QJsonValue item; Step() = default; }; struct Step { QIdentifier key; int idx=-1; QJsonValue item; Step() = default; };
QStack<Step> steps = QStack<Step>(); QStack<Step> steps = QStack<Step>();
bool isChoice = false;
}; };
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
...@@ -256,23 +251,23 @@ protected: ...@@ -256,23 +251,23 @@ protected:
enum CachedNumber : quint8 { None=0, Integer, FloatingPoint }; enum CachedNumber : quint8 { None=0, Integer, FloatingPoint };
bool trySequence(quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->trySequence(s); } bool trySequence(quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->trySequence(s); }
if (get('[', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"]")); return true; } _reportError(qBindExpectedSequence); return false; } if (get('[', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"]")); return true; } reportError(qBindExpectedSequence); return false; }
bool tryRecord (quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->tryRecord(s); } bool tryRecord (quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->tryRecord(s); }
if (get('{', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"}")); return true; } _reportError(qBindExpectedRecord ); return false; } if (get('{', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"}")); return true; } reportError(qBindExpectedRecord ); return false; }
bool tryNull ( ) { if (caching) { cacheLevel++; return caching->tryNull() && cacheOut(); } bool tryNull ( ) { if (caching) { cacheLevel++; return caching->tryNull() && cacheOut(); }
if (get('n', "[{\"ntf-0123456789.") && if (get('n', "[{\"ntf-0123456789.") &&
get('u', "[{\"" ) && get('u', "[{\"" ) &&
get('l', "[{\"" ) && get('l', "[{\"" ) &&
get('l', "[{\"" )) { get('l', "[{\"" )) {
return true; return true;
} else { _reportError(qBindExpectedNull); return false; } } } else { reportError(qBindExpectedNull); return false; } }
bool tryBind ( QUtf8Data& s) { if (caching) { cacheLevel++; return caching->tryBind(s) && cacheOut(); } bool tryBind ( QUtf8Data& s) { if (caching) { cacheLevel++; return caching->tryBind(s) && cacheOut(); }
QByteArray u; QByteArray u;
if ( get('"', "[{\"ntf-0123456789.")) { u.resize(0); char c; if ( get('"', "[{\"ntf-0123456789.")) { u.resize(0); char c;
while ((c=getCharInString()) != '\0' ) { u.append(c); } while ((c=getCharInString()) != '\0' ) { u.append(c); }
s=QUtf8Data(u); s=QUtf8Data(u);
return get('"'); return get('"');
} else { _reportError(qBindExpectedText); return false; } } } else { reportError(qBindExpectedText); return false; } }
bool tryBind ( QString& s) { QUtf8Data u; if (tryBind(u)) { s = QString(u.utf8()); return true; } return false; } bool tryBind ( QString& s) { QUtf8Data u; if (tryBind(u)) { s = QString(u.utf8()); return true; } return false; }
bool tryBind ( bool& b) { if (caching) { cacheLevel++; return caching->tryBind(bool(b)) && cacheOut(); } bool tryBind ( bool& b) { if (caching) { cacheLevel++; return caching->tryBind(bool(b)) && cacheOut(); }
if (get('t', "[{\"ntf-0123456789.") && if (get('t', "[{\"ntf-0123456789.") &&
...@@ -287,11 +282,11 @@ protected: ...@@ -287,11 +282,11 @@ protected:
get('s', "[{\"" ) && get('s', "[{\"" ) &&
get('e', "[{\"" )) { b=false; get('e', "[{\"" )) { b=false;
return true; return true;
} else { _reportError(qBindExpectedBoolean); return false; } } } else { reportError(qBindExpectedBoolean); return false; } }
bool tryBind ( float& n) { if (caching) { cacheLevel++; return caching->tryBind(double(n)) && cacheOut(); } bool tryBind ( float& n) { if (caching) { cacheLevel++; return caching->tryBind(double(n)) && cacheOut(); }
if (getNumber()==None) return false; // already reported qBindExpectedDecimal if (getNumber()==None) return false; // already reported qBindExpectedDecimal
if (d<double( std::numeric_limits<float >::min())|| if (d<double( std::numeric_limits<float >::min())||
double( std::numeric_limits<float >::max())<d) { _reportError(qBindExpectedSmallerNumber ); return false; } double( std::numeric_limits<float >::max())<d) { reportError(qBindExpectedSmallerNumber ); return false; }
n = float(d); cachedNumber=None; return true; } n = float(d); cachedNumber=None; return true; }
bool tryBind ( double& n) { if (caching) { cacheLevel++; return caching->tryBind(double(n)) && cacheOut(); } bool tryBind ( double& n) { if (caching) { cacheLevel++; return caching->tryBind(double(n)) && cacheOut(); }
if (getNumber()==None) return false; // already reported qBindExpectedDecimal if (getNumber()==None) return false; // already reported qBindExpectedDecimal
...@@ -299,33 +294,33 @@ protected: ...@@ -299,33 +294,33 @@ protected:
bool tryBind ( quint64& t) { if (caching) { cacheLevel++; return caching->tryBind(double(t)) && cacheOut(); } bool tryBind ( quint64& t) { if (caching) { cacheLevel++; return caching->tryBind(double(t)) && cacheOut(); }
auto r=getNumber(); auto r=getNumber();
if (r==None) return false; // already reported qBindExpectedDecimal if (r==None) return false; // already reported qBindExpectedDecimal
if (r==FloatingPoint) { _reportError(qBindExpectedInteger); return false; } if (r==FloatingPoint) { reportError(qBindExpectedInteger); return false; }
if (neg) { _reportError(qBindExpectedPositiveInteger); return false; } if (neg) { reportError(qBindExpectedPositiveInteger); return false; }
t = i ; cachedNumber=None; return true; } t = i ; cachedNumber=None; return true; }
bool tryBind ( qint64& t) { if (caching) { cacheLevel++; return caching->tryBind(double(t)) && cacheOut(); } bool tryBind ( qint64& t) { if (caching) { cacheLevel++; return caching->tryBind(double(t)) && cacheOut(); }
auto r=getNumber(); auto r=getNumber();
if (r==None) return false; // already reported qBindExpectedDecimal if (r==None) return false; // already reported qBindExpectedDecimal
if (r==FloatingPoint) { _reportError(qBindExpectedInteger); return false; } if (r==FloatingPoint) { reportError(qBindExpectedInteger); return false; }
if (!neg && i<quint64( std::numeric_limits<qint64>::max())) { t = qint64(i); cachedNumber=None; return true; } if (!neg && i<quint64( std::numeric_limits<qint64>::max())) { t = qint64(i); cachedNumber=None; return true; }
if ( neg && i<quint64(-std::numeric_limits<qint64>::min())) { t = -qint64(i); cachedNumber=None; return true; } if ( neg && i<quint64(-std::numeric_limits<qint64>::min())) { t = -qint64(i); cachedNumber=None; return true; }
_reportError(qBindExpectedSmallerNumber ); return false; } reportError(qBindExpectedSmallerNumber ); return false; }
bool tryBind ( QVariant& dst) { bool tryBind ( QVariant& dst) {
_setChoice(true); auto suspended = setErrorHandler();
quint32 size=0; QIdentifier key; QVariant item; quint32 size=0; QIdentifier key; QVariant item;
if ( trySequence(&size)) { _setChoice(false); QVariantList l; while (tryItem( )) { l.append( tryBind(item) ? item : QVariant()); } dst = l; return tryOut(); } if ( trySequence(&size)) { setErrorHandler(suspended); QVariantList l; while (tryItem( )) { l.append( tryBind(item) ? item : QVariant()); } dst = l; return tryOut(); }
if ( tryRecord (&size)) { _setChoice(false); QVariantMap l; while (tryItem(key)) { l.insert(key.latin1(), tryBind(item) ? item : QVariant()); } dst = l; return tryOut(); } if ( tryRecord (&size)) { setErrorHandler(suspended); QVariantMap l; while (tryItem(key)) { l.insert(key.latin1(), tryBind(item) ? item : QVariant()); } dst = l; return tryOut(); }
bool b; if (tryBind(b)) { _setChoice(false); dst = QVariant(b ); return true; } bool b; if (tryBind(b)) { setErrorHandler(suspended); dst = QVariant(b ); return true; }
quint64 u; if (tryBind(u)) { _setChoice(false); dst = QVariant(u ); return true; } // may fail after consuming integer part quint64 u; if (tryBind(u)) { setErrorHandler(suspended); dst = QVariant(u ); return true; } // may fail after consuming integer part
qint64 l; if (tryBind(l)) { _setChoice(false); dst = QVariant(l ); return true; } // may fail after consuming integer part qint64 l; if (tryBind(l)) { setErrorHandler(suspended); dst = QVariant(l ); return true; } // may fail after consuming integer part
double d; if (tryBind(d)) { _setChoice(false); dst = QVariant(d+/*integer part consumed by one of*/u+l); return true; } double d; if (tryBind(d)) { setErrorHandler(suspended); dst = QVariant(d+/*integer part consumed by one of*/u+l); return true; }
QUtf8Data s; if (tryBind(s)) { _setChoice(false); QUtf8Data s; if (tryBind(s)) { setErrorHandler(suspended);
QByteArray b; QByteArray b;
if ( toByteArray(b, s)) { toVariant(dst, b); return true; } if ( toByteArray(b, s)) { toVariant(dst, b); return true; }
dst = QVariant(QString::fromUtf8(s.utf8())) ; return true; dst = QVariant(QString::fromUtf8(s.utf8())) ; return true;
} }
_setChoice(false); setErrorHandler(suspended);
if (!tryNull()) _reportError(QIdentifierLiteral("ExpectedOneOfBooleanDecimalBytesTextSequenceRecordNull")); if (!tryNull()) reportError(QIdentifierLiteral("ExpectedOneOfBooleanDecimalBytesTextSequenceRecordNull"));
dst = QVariant(); return true; dst = QVariant(); return true;
} }
...@@ -380,8 +375,7 @@ protected: ...@@ -380,8 +375,7 @@ protected:
return true; } return true; }
bool _isOk() const noexcept { return io; } bool _isOk() const noexcept { return io; }
void _setChoice(bool v) { isChoice=v; } void reportError(QIdentifierLiteral e, QString context = QString()) { if (errorHandler) errorHandler(e, QString("at (%1,%2) ").arg(line).arg(column).append(context)); }
void _reportError(QIdentifierLiteral e) { if (!isChoice) errors.append(Error{ e, line, column, index }); }
private: private:
CachedNumber getNumber() { CachedNumber getNumber() {
if (cachedNumber!=None) return cachedNumber; if (cachedNumber!=None) return cachedNumber;
...@@ -389,7 +383,7 @@ private: ...@@ -389,7 +383,7 @@ private:
neg = get('-', "[{\"ntf-0123456789."); neg = get('-', "[{\"ntf-0123456789.");
qint8 digit; qint8 digit;
if ((digit = getDigit()) < 0) { if ((digit = getDigit()) < 0) {
_reportError(qBindExpectedDecimal); reportError(qBindExpectedDecimal);
return None; // do not accept no digit otherwise we may accept an empty mantissa or string! return None; // do not accept no digit otherwise we may accept an empty mantissa or string!
} }
cachedNumber=Integer; cachedNumber=Integer;
...@@ -484,7 +478,7 @@ private: ...@@ -484,7 +478,7 @@ private:
while (!(nextChar() == expected || strchr(validChars, nextChar()) || nextChar() == '\0')) { while (!(nextChar() == expected || strchr(validChars, nextChar()) || nextChar() == '\0')) {
char ignored = getChar(); char ignored = getChar();
if (!isspace(ignored)) { if (!isspace(ignored)) {
errors.append(Error{ qBindIgnoredCharacter, line, column, index }); reportError(qBindIgnoredCharacter);
} }
} }
} }
...@@ -538,16 +532,15 @@ struct QTransmogrifier<QJsonValue> { ...@@ -538,16 +532,15 @@ struct QTransmogrifier<QJsonValue> {
} }
else if (v->mode()==Read) { else if (v->mode()==Read) {
QValueStatus r; QValueStatus r;
{ auto suspended = v->setErrorHandler();
QScopedChoice choice(v); QJsonArray a; if ((r = v.bind(a))) { j = a ; return r; }
QJsonArray a; if ((r = v.bind(a))) { j = a ; return r; } QJsonObject o; if ((r = v.bind(o))) { j = o ; return r; }
QJsonObject o; if ((r = v.bind(o))) { j = o ; return r; } QString t; if ((r = v.bind(t))) { j = QJsonValue( t) ; return r; }
QString t; if ((r = v.bind(t))) { j = QJsonValue( t) ; return r; } bool b; if ((r = v.bind(b))) { j = QJsonValue( b) ; return r; }
bool b; if ((r = v.bind(b))) { j = QJsonValue( b) ; return r; } qint64 i; if ((r = v.bind(i))) { j = QJsonValue(double(i)); return r; }
qint64 i; if ((r