diff options
author | Maximilian Goldstein <max.goldstein@qt.io> | 2020-04-09 13:34:01 +0200 |
---|---|---|
committer | Maximilian Goldstein <max.goldstein@qt.io> | 2020-05-06 10:45:48 +0200 |
commit | a714a3a446a47b3ac18de6cea1e6c4ca01535170 (patch) | |
tree | 2569eb6ec42f4b537bc18477b88d9a718f444012 /src/qml | |
parent | 22f9e5fb1ed643f284f50b9417bdbafdfb20566b (diff) |
Implement URLSearchParams
Implements URLSearchParams (https://url.spec.whatwg.org/#urlsearchparams),
completing our implementation of the URL object.
Still needs the for..of iterator to get implemented.
Change-Id: Iad33ed2f3fe0b2598ca2b0b21a4743f5f7dc19fd
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 8 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4global_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4managed.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4managed_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4urlobject.cpp | 760 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4urlobject_p.h | 103 |
7 files changed, 885 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index fec1524667..6a583bf395 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -657,6 +657,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(global); jsObjects[UrlProto] = memoryManager->allocate<UrlPrototype>(); + jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(global); + jsObjects[UrlSearchParamsProto] = memoryManager->allocate<UrlSearchParamsPrototype>(); str = newString(QStringLiteral("get [Symbol.species]")); jsObjects[GetSymbolSpecies] = FunctionObject::createBuiltinFunction(this, str, ArrayPrototype::method_get_species, 0); @@ -680,6 +682,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor()); static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor()); static_cast<UrlPrototype *>(urlPrototype())->init(this, urlCtor()); + static_cast<UrlSearchParamsPrototype *>(urlSearchParamsPrototype())->init(this, urlSearchParamsCtor()); static_cast<IteratorPrototype *>(iteratorPrototype())->init(this); static_cast<ForInIteratorPrototype *>(forInIteratorPrototype())->init(this); @@ -770,6 +773,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor()); globalObject->defineDefaultProperty(QStringLiteral("Promise"), *promiseCtor()); globalObject->defineDefaultProperty(QStringLiteral("URL"), *urlCtor()); + globalObject->defineDefaultProperty(QStringLiteral("URLSearchParams"), *urlSearchParamsCtor()); globalObject->defineDefaultProperty(QStringLiteral("SharedArrayBuffer"), *sharedArrayBufferCtor()); globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor()); @@ -1064,6 +1068,11 @@ Heap::UrlObject *ExecutionEngine::newUrlObject() return memoryManager->allocate<UrlObject>(); } +Heap::UrlSearchParamsObject *ExecutionEngine::newUrlSearchParamsObject() +{ + return memoryManager->allocate<UrlSearchParamsObject>(); +} + Heap::Object *ExecutionEngine::newErrorObject(const Value &value) { return ErrorObject::create<ErrorObject>(this, value, errorCtor()); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index ebf2fcd55a..c555730838 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -241,6 +241,7 @@ public: ArrayIteratorProto, StringIteratorProto, UrlProto, + UrlSearchParamsProto, Object_Ctor, String_Ctor, @@ -269,6 +270,7 @@ public: Map_Ctor, IntrinsicTypedArray_Ctor, Url_Ctor, + UrlSearchParams_Ctor, GetSymbolSpecies, @@ -313,6 +315,10 @@ public: { return reinterpret_cast<FunctionObject *>(jsObjects + Url_Ctor); } + FunctionObject *urlSearchParamsCtor() const + { + return reinterpret_cast<FunctionObject *>(jsObjects + UrlSearchParams_Ctor); + } FunctionObject *typedArrayCtors; FunctionObject *getSymbolSpecies() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetSymbolSpecies); } @@ -361,6 +367,7 @@ public: Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); } Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); } Object *urlPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlProto); } + Object *urlSearchParamsPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlSearchParamsProto); } EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); } FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); } @@ -591,6 +598,7 @@ public: #endif Heap::UrlObject *newUrlObject(); + Heap::UrlSearchParamsObject *newUrlSearchParamsObject(); Heap::Object *newErrorObject(const Value &value); Heap::Object *newErrorObject(const QString &message); diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 7234a3456f..ace070c683 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -142,6 +142,7 @@ namespace Heap { struct QObjectWrapper; struct RegExpObject; struct UrlObject; + struct UrlSearchParamsObject; struct RegExp; struct EvalFunction; diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 8a0e5509c4..f090afe649 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -108,6 +108,9 @@ QString Managed::className() const case Type_UrlObject: s = "URL"; break; + case Type_UrlSearchParamsObject: + s = "URLSearchParams"; + break; case Type_ExecutionContext: s = "__ExecutionContext"; diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 910eb3a5a1..96c47a9c41 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -145,6 +145,7 @@ public: Type_MathObject, Type_ProxyObject, Type_UrlObject, + Type_UrlSearchParamsObject, Type_ExecutionContext, Type_InternalClass, diff --git a/src/qml/jsruntime/qv4urlobject.cpp b/src/qml/jsruntime/qv4urlobject.cpp index 15e827680e..73b1510d2e 100644 --- a/src/qml/jsruntime/qv4urlobject.cpp +++ b/src/qml/jsruntime/qv4urlobject.cpp @@ -37,15 +37,24 @@ ** ****************************************************************************/ +#include "qv4arrayiterator_p.h" #include "qv4urlobject_p.h" +#include "qv4stringobject_p.h" #include <QtCore/QUrl> +#include <qv4jscall_p.h> +#include <qv4objectiterator_p.h> + using namespace QV4; DEFINE_OBJECT_VTABLE(UrlObject); DEFINE_OBJECT_VTABLE(UrlCtor); +DEFINE_OBJECT_VTABLE(UrlSearchParamsObject); +DEFINE_OBJECT_VTABLE(UrlSearchParamsCtor); + + void Heap::UrlCtor::init(QV4::ExecutionContext *scope) { Heap::FunctionObject::init(scope, QLatin1String("URL")); @@ -71,6 +80,7 @@ void UrlPrototype::init(ExecutionEngine *engine, Object *ctor) defineAccessorProperty(QLatin1String("port"), method_getPort, method_setPort); defineAccessorProperty(QLatin1String("protocol"), method_getProtocol, method_setProtocol); defineAccessorProperty(QLatin1String("search"), method_getSearch, method_setSearch); + defineAccessorProperty(QLatin1String("searchParams"), method_getSearchParams, nullptr); defineAccessorProperty(QLatin1String("username"), method_getUsername, method_setUsername); } @@ -623,6 +633,21 @@ ReturnedValue UrlPrototype::method_setUsername(const FunctionObject *b, const Va return Encode::undefined(); } +ReturnedValue UrlPrototype::method_getSearchParams(const FunctionObject *b, const Value *thisObject, + const Value *, int) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + Scoped<UrlObject> r(scope, thisObject->as<UrlObject>()); + + Scoped<UrlSearchParamsObject> usp(scope, v4->newUrlSearchParamsObject()); + + usp->initializeParams(r->search()); + + return usp->asReturnedValue(); +} + ReturnedValue UrlCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget) { @@ -687,3 +712,738 @@ ReturnedValue UrlCtor::virtualCallAsConstructor(const FunctionObject *that, cons return obj->asReturnedValue(); } + + +void Heap::UrlSearchParamsCtor::init(QV4::ExecutionContext *scope) +{ + Heap::FunctionObject::init(scope, QLatin1String("URLSearchParams")); +} + +void UrlSearchParamsPrototype::init(ExecutionEngine *engine, Object *ctor) +{ + Q_UNUSED(ctor) + + Scope scope(engine); + ScopedObject o(scope); + + defineDefaultProperty(QLatin1String("toString"), method_toString); + defineDefaultProperty(QLatin1String("sort"), method_sort); + defineDefaultProperty(QLatin1String("append"), method_append); + defineDefaultProperty(QLatin1String("delete"), method_delete); + defineDefaultProperty(QLatin1String("has"), method_has); + defineDefaultProperty(QLatin1String("set"), method_set); + defineDefaultProperty(QLatin1String("get"), method_get); + defineDefaultProperty(QLatin1String("getAll"), method_getAll); + defineDefaultProperty(QLatin1String("forEach"), method_forEach); + defineDefaultProperty(QLatin1String("entries"), method_entries); + defineDefaultProperty(QLatin1String("keys"), method_keys); + defineDefaultProperty(QLatin1String("values"), method_values); +} + +ReturnedValue UrlSearchParamsCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, + int argc, const Value *newTarget) +{ + ExecutionEngine *v4 = that->engine(); + + if (argc > 1) + return v4->throwError(QLatin1String("Invalid amount of arguments")); + + Scope scope(v4); + + ScopedValue arg(scope, argv[0]); + ArrayObject *argArrayObject = arg->as<ArrayObject>(); + Object *argObject = arg->as<Object>(); + + ReturnedValue o = Encode(v4->newUrlSearchParamsObject()); + + if (!newTarget) + return o; + + ScopedObject obj(scope, o); + obj->setProtoFromNewTarget(newTarget); + + UrlSearchParamsObject *urlSearchParamsObject = obj->as<UrlSearchParamsObject>(); + + if (argArrayObject != nullptr) { + ScopedArrayObject argArray(scope, argArrayObject); + + uint len = argArray->getLength(); + + for (uint i = 0; i < len; i++) { + QV4::Value pair = argArray->get(i); + auto *pairArrayObject = pair.as<ArrayObject>(); + + if (pairArrayObject == nullptr) { + return v4->throwTypeError( + QLatin1String("element %1 is not a pair").arg(QString::number(i))); + } + + + ScopedArrayObject pairArray(scope, pairArrayObject); + + + uint pairLen = pairArray->getLength(); + + + if (pairLen != 2) { + return v4->throwTypeError(QLatin1String("pair %1 has %2 elements instead of 2") + .arg(QString::number(i)) + .arg(QString::number(pairLen))); + } + } + + urlSearchParamsObject->initializeParams(argArray); + } else if (argObject != nullptr) { + ScopedObject scopedObject(scope, argObject); + urlSearchParamsObject->initializeParams(scopedObject); + } else { + QString value = argc > 0 ? arg->toQString() : QLatin1String(""); + urlSearchParamsObject->initializeParams(value); + } + + return obj->asReturnedValue(); +} + +void UrlSearchParamsObject::initializeParams() +{ + auto *arrayObject = engine()->newArrayObject(0); + auto *keys = engine()->newArrayObject(0); + auto *values = engine()->newArrayObject(0); + + d()->params.set(engine(), arrayObject); + d()->keys.set(engine(), keys); + d()->values.set(engine(), values); +} + +void UrlSearchParamsObject::initializeParams(QString value) +{ + Q_ASSERT(d()->params == nullptr); + + initializeParams(); + + if (value.startsWith(QLatin1Char('?'))) + value = value.mid(1); + + const QStringList params = value.split(QLatin1Char('&')); + + for (const QString& param : params) { + if (param.isEmpty()) + continue; + + QString key, value; + + int equalsIndex = param.indexOf(QLatin1Char('=')); + if (equalsIndex != -1) { + key = param.left(equalsIndex); + value = param.mid(equalsIndex+1); + } else { + key = param; + } + + append(engine()->newString(key), engine()->newString(value)); + } +} + +void UrlSearchParamsObject::initializeParams(ScopedArrayObject& params) +{ + Q_ASSERT(d()->params == nullptr); + + Scope scope(engine()); + + uint len = params->getLength(); + auto *keys = engine()->newArrayObject(len); + auto *values = engine()->newArrayObject(len); + + ScopedArrayObject scopedKeys(scope, keys); + ScopedArrayObject scopedValues(scope, values); + + for (uint i = 0; i < len; i++) + { + QV4::Value pair = params->get(i); + auto *pairArrayObject = pair.as<ArrayObject>(); + + QV4::Value key = pairArrayObject->get(uint(0)); + QV4::Value value = pairArrayObject->get(uint(1)); + + scopedKeys->put(i, key); + scopedValues->put(i, value); + } + + + d()->params.set(engine(), params->d()); + d()->keys.set(engine(), keys); + d()->values.set(engine(), values); +} + +void UrlSearchParamsObject::initializeParams(ScopedObject& params) +{ + Q_ASSERT(d()->params == nullptr); + + initializeParams(); + + Scope scope(engine()); + ObjectIterator it(scope, params, ObjectIterator::EnumerableOnly); + + ScopedValue name(scope); + ScopedValue val(scope); + + while (true) { + name = it.nextPropertyNameAsString(val); + if (name->isNull()) + break; + + Heap::String *nameStr = name->as<String>()->d(); + Heap::String *valStr = val->toString(engine()); + + append(nameStr, valStr); + } +} + +void UrlSearchParamsObject::setParams(QList<QStringList> params) +{ + auto *arrayObject = engine()->newArrayObject(0); + auto *keys = engine()->newArrayObject(0); + auto *values = engine()->newArrayObject(0); + + Scope scope(engine()); + + ScopedArrayObject scopedArray(scope, arrayObject); + + ScopedArrayObject scopedKeys(scope, keys); + ScopedArrayObject scopedValues(scope, values); + + uint len = 0; + + for (const QStringList& param : params) { + + auto *valuePair = engine()->newArrayObject(2); + + ScopedArrayObject valuePairObject(scope, valuePair); + + ScopedValue key(scope, Value::fromHeapObject(engine()->newString(param[0]))); + ScopedValue value(scope, Value::fromHeapObject(engine()->newString(param[1]))); + valuePairObject->put(uint(0), key); + valuePairObject->put(uint(1), value); + + scopedKeys->put(len, key); + scopedValues->put(len, value); + + scopedArray->put(len, valuePairObject); + len++; + } + + d()->params.set(engine(), arrayObject); + d()->keys.set(engine(), keys); + d()->values.set(engine(), values); +} + +void UrlSearchParamsObject::append(Heap::String *name, Heap::String *value) +{ + Scope scope(engine()); + + ScopedArrayObject scopedArray(scope, d()->params); + ScopedArrayObject scopedKeys(scope, d()->keys); + ScopedArrayObject scopedValues(scope, d()->values); + + auto *valuePair = engine()->newArrayObject(2); + + ScopedArrayObject valuePairObject(scope, valuePair); + + ScopedValue keyScoped(scope, Value::fromHeapObject(name)); + ScopedValue valueScoped(scope, Value::fromHeapObject(value)); + valuePairObject->put(uint(0), keyScoped); + valuePairObject->put(uint(1), valueScoped); + + uint len = scopedArray->getLength(); + + scopedKeys->put(len, keyScoped); + scopedValues->put(len, valueScoped); + + scopedArray->put(len, valuePairObject); +} + +QList<QStringList> UrlSearchParamsObject::params() const +{ + auto *arrayObject = d()->params.get(); + Scope scope(engine()); + ScopedArrayObject scopedArray(scope, arrayObject); + + QList<QStringList> result; + + uint len = scopedArray->getLength(); + + for (uint i = 0; i < len; i++) { + QV4::Value pair = scopedArray->get(i); + auto *pairArrayObject = pair.as<ArrayObject>(); + + QV4::Value key = pairArrayObject->get(uint(0)); + QV4::Value value = pairArrayObject->get(uint(1)); + + result << QStringList { key.toQString(), value.toQString() }; + } + + return result; +} + +int UrlSearchParamsObject::length() const +{ + auto *arrayObject = d()->params.get(); + Scope scope(engine()); + ScopedArrayObject scopedArray(scope, arrayObject); + + return scopedArray->getLength(); +} + +int UrlSearchParamsObject::indexOf(QString name, int last) const +{ + auto *arrayObject = d()->params.get(); + Scope scope(engine()); + ScopedArrayObject scopedArray(scope, arrayObject); + + int len = scopedArray->getLength(); + + for (int i = last + 1; i < len; i++) { + QV4::Value pair = scopedArray->get(i); + auto *pairArrayObject = pair.as<ArrayObject>(); + + QV4::Value key = pairArrayObject->get(uint(0)); + + if (key.toQString() == name) + return i; + } + + return -1; +} + +QString UrlSearchParamsObject::stringAt(int index, int pairIndex) const +{ + auto *arrayObject = d()->params.get(); + Scope scope(engine()); + ScopedArrayObject scopedArray(scope, arrayObject); + + if (index >= scopedArray->getLength()) + return {}; + + QV4::Value pair = scopedArray->get(index); + auto *pairArrayObject = pair.as<ArrayObject>(); + + QV4::Value value = pairArrayObject->get(pairIndex); + + return value.toQString(); +} + +QV4::Heap::String * UrlSearchParamsObject::stringAtRaw(int index, int pairIndex) const +{ + auto *arrayObject = d()->params.get(); + Scope scope(engine()); + ScopedArrayObject scopedArray(scope, arrayObject); + + if (index >= scopedArray->getLength()) + return nullptr; + + QV4::Value pair = scopedArray->get(index); + auto *pairArrayObject = pair.as<ArrayObject>(); + + QV4::Value value = pairArrayObject->get(pairIndex); + + return value.as<String>()->d(); +} + +QString UrlSearchParamsObject::nameAt(int index) const +{ + return stringAt(index, 0); +} + +QV4::Heap::String * UrlSearchParamsObject::nameAtRaw(int index) const +{ + return stringAtRaw(index, 0); +} + + +QString UrlSearchParamsObject::valueAt(int index) const +{ + return stringAt(index, 1); +} + +QV4::Heap::String * UrlSearchParamsObject::valueAtRaw(int index) const +{ + return stringAtRaw(index, 1); +} + + +struct UrlSearchParamsObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator +{ + ~UrlSearchParamsObjectOwnPropertyKeyIterator() override = default; + PropertyKey next(const QV4::Object *o, Property *pd = nullptr, + PropertyAttributes *attrs = nullptr) override; +}; + +PropertyKey UrlSearchParamsObjectOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd, + PropertyAttributes *attrs) +{ + const UrlSearchParamsObject *usp = static_cast<const UrlSearchParamsObject *>(o); + + Scope scope(usp); + + uint len = usp->length(); + if (arrayIndex < len) { + uint index = arrayIndex; + ++arrayIndex; + if (attrs) + *attrs = Attr_NotConfigurable | Attr_NotWritable; + if (pd) + pd->value = usp->engine()->newString(usp->nameAt(index)); + return PropertyKey::fromArrayIndex(index); + } + + return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); +} + +OwnPropertyKeyIterator *UrlSearchParamsObject::virtualOwnPropertyKeys(const Object *m, + Value *target) +{ + *target = *m; + return new UrlSearchParamsObjectOwnPropertyKeyIterator; +} + +PropertyAttributes UrlSearchParamsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id, + Property *p) +{ + PropertyAttributes attributes = Object::virtualGetOwnProperty(m, id, p); + if (attributes != Attr_Invalid) + return attributes; + + if (id.isArrayIndex()) { + const int index = id.asArrayIndex(); + const auto usp = static_cast<const UrlSearchParamsObject *>(m); + if (index < usp->length()) { + if (p) + p->value = usp->engine()->newString(usp->nameAt(index)); + return Attr_NotConfigurable | Attr_NotWritable; + } + } + + return Object::virtualGetOwnProperty(m, id, p); +} + +ReturnedValue UrlSearchParamsPrototype::method_toString(const FunctionObject *b, const Value *thisObject, + const Value *, int) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + auto params = o->params(); + + QString value; + + for (const QStringList &pair : params) + value += QLatin1String("%1=%2&").arg(QString::fromUtf8(QUrl::toPercentEncoding(pair[0])), + QString::fromUtf8(QUrl::toPercentEncoding(pair[1]))); + + value.chop(1); + + return Encode(v4->newString(value)); +} + +ReturnedValue UrlSearchParamsPrototype::method_sort(const FunctionObject *b, const Value *thisObject, + const Value *, int) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + QList<QStringList> params = o->params(); + std::stable_sort(params.begin(), params.end(), [](QStringList a, QStringList b) { return a[0] < b[0]; }); + + o->setParams(params); + + return Encode::undefined(); +} + +ReturnedValue UrlSearchParamsPrototype::method_append(const FunctionObject *b, const Value *thisObject, + const Value *argv, int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 2) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + ScopedValue argName(scope, argv[0]); + ScopedValue argValue(scope, argv[1]); + + String *argNameString = argName->stringValue(); + + if (argNameString == nullptr) + return v4->throwTypeError(QLatin1String("Invalid argument provided")); + + ScopedString name(scope, argName->as<String>()); + ScopedString value(scope, argValue->toString(v4)); + + + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + o->append(name->d(), value->d()); + + return Encode::undefined(); +} + +ReturnedValue UrlSearchParamsPrototype::method_delete(const FunctionObject *b, const Value *thisObject, + const Value *argv, int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 1) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + ScopedValue argName(scope, argv[0]); + + String *argNameString = argName->stringValue(); + + if (argNameString == nullptr) + return v4->throwTypeError(QLatin1String("Invalid argument provided")); + + QString name = argNameString->toQString(); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + QList<QStringList> params = o->params(); + + auto to_remove = std::remove_if(params.begin(), params.end(), [&name](QStringList pair) { + return pair[0] == name; + }); + + params.erase(to_remove, params.end()); + + o->setParams(params); + + return Encode::undefined(); +} + +ReturnedValue UrlSearchParamsPrototype::method_has(const FunctionObject *b, const Value *thisObject, + const Value *argv, int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 1) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + ScopedValue argName(scope, argv[0]); + + String *argNameString = argName->stringValue(); + + if (argNameString == nullptr) + return v4->throwTypeError(QLatin1String("Invalid argument provided")); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + QString name = argNameString->toQString(); + + return Encode(o->indexOf(name) != -1); +} + +ReturnedValue UrlSearchParamsPrototype::method_set(const FunctionObject *b, const Value *thisObject, + const Value *argv, int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 2) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + ScopedValue argName(scope, argv[0]); + ScopedValue argValue(scope, argv[1]); + + String *argNameString = argName->stringValue(); + + if (argNameString == nullptr) + return v4->throwTypeError(QLatin1String("Invalid argument provided")); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + QString name = argNameString->toQString(); + QString value = argValue->toQString(); + + auto params = o->params(); + + bool matched = false; + + for (auto *it = params.begin(); it != params.end();) { + QStringList ¶m = *it; + if (param[0] == name) { + if (!matched) { + param[1] = value; + matched = true; + } else { + it = params.erase(it); + continue; + } + } + it++; + } + + if (!matched) + params << QStringList { name, value }; + + o->setParams(params); + + return Encode::undefined(); +} + +ReturnedValue UrlSearchParamsPrototype::method_get(const FunctionObject *b, const Value *thisObject, + const Value *argv, int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 1) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + ScopedValue argName(scope, argv[0]); + + String *argNameString = argName->stringValue(); + + if (argNameString == nullptr) + return v4->throwTypeError(QLatin1String("Invalid argument provided")); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + QString name = argNameString->toQString(); + + int index = o->indexOf(name); + + if (index == -1) + return Encode::null(); + + return Encode(o->valueAtRaw(index)); +} + +ReturnedValue UrlSearchParamsPrototype::method_getAll(const FunctionObject *b, + const Value *thisObject, const Value *argv, + int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 1) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + ScopedValue argName(scope, argv[0]); + + String *argNameString = argName->stringValue(); + + if (argNameString == nullptr) + return v4->throwTypeError(QLatin1String("Invalid argument provided")); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + QString name = argNameString->toQString(); + + auto *arrayObject = v4->newArrayObject(0); + ScopedArrayObject result(scope, arrayObject); + + int i = 0; + for (int index = o->indexOf(name); index != -1; index = o->indexOf(name, index)) { + ScopedValue value(scope, Value::fromHeapObject(o->valueAtRaw(index))); + result->put(i++, value); + } + + return Encode(arrayObject); +} + +ReturnedValue UrlSearchParamsPrototype::method_forEach(const FunctionObject *b, + const Value *thisObject, const Value *argv, + int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 1) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + ScopedValue argFunc(scope, argv[0]); + + FunctionObject *func = argFunc->as<FunctionObject>(); + + if (func == nullptr) + return v4->throwTypeError(QLatin1String("Invalid argument: must be a function")); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + for (int i = 0; i < o->length(); i++) { + Scoped<String> name(scope, o->nameAtRaw(i)); + Scoped<String> value(scope, o->valueAtRaw(i)); + + QV4::JSCallData calldata(scope, 2); + + calldata->args[0] = value; + calldata->args[1] = name; + + func->call(calldata); + } + + return Encode::undefined(); +} + +ReturnedValue UrlSearchParamsPrototype::method_entries(const FunctionObject *b, + const Value *thisObject, const Value *, + int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 0) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + ScopedObject params(scope, o->d()->params.get()); + + Scoped<ArrayIteratorObject> paramsIterator(scope, v4->newArrayIteratorObject(params)); + paramsIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind; + return paramsIterator->asReturnedValue(); +} + +ReturnedValue UrlSearchParamsPrototype::method_keys(const FunctionObject *b, + const Value *thisObject, const Value *, + int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 0) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + ScopedObject keys(scope, o->d()->keys.get()); + + Scoped<ArrayIteratorObject> keysIterator(scope, v4->newArrayIteratorObject(keys)); + keysIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind; + return keysIterator->asReturnedValue(); +} + +ReturnedValue UrlSearchParamsPrototype::method_values(const FunctionObject *b, + const Value *thisObject, const Value *, + int argc) +{ + ExecutionEngine *v4 = b->engine(); + Scope scope(v4); + + if (argc != 0) + return v4->throwError(QLatin1String("Bad amount of arguments")); + + Scoped<UrlSearchParamsObject> o(scope, thisObject->as<UrlSearchParamsObject>()); + + ScopedObject values(scope, o->d()->values.get()); + + Scoped<ArrayIteratorObject> valuesIterator(scope, v4->newArrayIteratorObject(values)); + valuesIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind; + return valuesIterator->asReturnedValue(); +} diff --git a/src/qml/jsruntime/qv4urlobject_p.h b/src/qml/jsruntime/qv4urlobject_p.h index bc066818b6..aa0e7a062f 100644 --- a/src/qml/jsruntime/qv4urlobject_p.h +++ b/src/qml/jsruntime/qv4urlobject_p.h @@ -85,6 +85,24 @@ struct UrlCtor : FunctionObject { void init(QV4::ExecutionContext *scope); }; + +// clang-format on +#define UrlSearchParamsObjectMembers(class, Member) \ + Member(class, Pointer, ArrayObject *, params) \ + Member(class, Pointer, ArrayObject *, keys) \ + Member(class, Pointer, ArrayObject *, values) +// clang-format off + +DECLARE_HEAP_OBJECT(UrlSearchParamsObject, Object) +{ + DECLARE_MARKOBJECTS(UrlSearchParamsObject); + void init() { Object::init(); } +}; + +struct UrlSearchParamsCtor : FunctionObject +{ + void init(QV4::ExecutionContext *scope); +}; } struct UrlObject : Object @@ -205,6 +223,91 @@ struct UrlPrototype : Object const Value *argv, int argc); static ReturnedValue method_setUsername(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + + static ReturnedValue method_getSearchParams(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); +}; + +struct UrlSearchParamsObject : Object +{ + V4_OBJECT2(UrlSearchParamsObject, Object) + Q_MANAGED_TYPE(UrlSearchParamsObject) + V4_PROTOTYPE(urlSearchParamsPrototype) + + void initializeParams(); + void initializeParams(QString params); + void initializeParams(ScopedArrayObject& params); + void initializeParams(ScopedObject& params); + + QList<QStringList> params() const; + void setParams(QList<QStringList> params); + + QString nameAt(int index) const; + Heap::String * nameAtRaw(int index) const; + QString valueAt(int index) const; + Heap::String * valueAtRaw(int index) const; + + void append(Heap::String *name, Heap::String *value); + + int indexOf(QString name, int last = -1) const; + int length() const; + + using Object::getOwnProperty; +protected: + static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target); + static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p); +private: + QString stringAt(int index, int pairIndex) const; + Heap::String * stringAtRaw(int index, int pairIndex) const; +}; + +template<> +inline const UrlSearchParamsObject *Value::as() const +{ + return isManaged() && m()->internalClass->vtable->type == Managed::Type_UrlSearchParamsObject + ? static_cast<const UrlSearchParamsObject *>(this) + : nullptr; +} + +struct UrlSearchParamsCtor : FunctionObject +{ + V4_OBJECT2(UrlSearchParamsCtor, FunctionObject) + + static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, + int argc, const Value *); +}; + +struct UrlSearchParamsPrototype : Object +{ + V4_PROTOTYPE(objectPrototype) + + void init(ExecutionEngine *engine, Object *ctor); + + static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_append(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_get(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_getAll(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_forEach(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + static ReturnedValue method_values(const FunctionObject *, const Value *thisObject, + const Value *argv, int argc); + }; } |