From b9fe5b2ef1dbf03456ea582d034826224b956573 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 11 Jul 2014 16:23:19 -0700 Subject: [PATCH] Added JS exceptions + fixed up floating precision mess up --- .../script-engine/src/ArrayBufferClass.cpp | 12 +++- .../script-engine/src/ArrayBufferClass.h | 2 +- libraries/script-engine/src/DataViewClass.cpp | 2 +- .../script-engine/src/DataViewPrototype.cpp | 42 ++++++++----- .../script-engine/src/DataViewPrototype.h | 34 +++++----- libraries/script-engine/src/TypedArrays.cpp | 63 ++++++++++++++----- libraries/script-engine/src/TypedArrays.h | 2 +- 7 files changed, 105 insertions(+), 52 deletions(-) diff --git a/libraries/script-engine/src/ArrayBufferClass.cpp b/libraries/script-engine/src/ArrayBufferClass.cpp index d86e229a1a..4f85eeeae2 100644 --- a/libraries/script-engine/src/ArrayBufferClass.cpp +++ b/libraries/script-engine/src/ArrayBufferClass.cpp @@ -48,7 +48,17 @@ _scriptEngine(scriptEngine) { engine()->globalObject().setProperty(name(), _ctor); } -QScriptValue ArrayBufferClass::newInstance(quint32 size) { +QScriptValue ArrayBufferClass::newInstance(qint32 size) { + const qint32 MAX_LENGTH = 100000000; + if (size < 0) { + engine()->evaluate("throw \"ArgumentError: negative length\""); + return QScriptValue(); + } + if (size > MAX_LENGTH) { + engine()->evaluate("throw \"ArgumentError: absurd length\""); + return QScriptValue(); + } + engine()->reportAdditionalMemoryCost(size); QScriptEngine* eng = engine(); QVariant variant = QVariant::fromValue(QByteArray(size, 0)); diff --git a/libraries/script-engine/src/ArrayBufferClass.h b/libraries/script-engine/src/ArrayBufferClass.h index c56b659eff..c7b4d447dd 100644 --- a/libraries/script-engine/src/ArrayBufferClass.h +++ b/libraries/script-engine/src/ArrayBufferClass.h @@ -26,7 +26,7 @@ class ArrayBufferClass : public QObject, public QScriptClass { Q_OBJECT public: ArrayBufferClass(ScriptEngine* scriptEngine); - QScriptValue newInstance(quint32 size); + QScriptValue newInstance(qint32 size); QScriptValue newInstance(const QByteArray& ba); ScriptEngine* getScriptEngine() { return _scriptEngine; } diff --git a/libraries/script-engine/src/DataViewClass.cpp b/libraries/script-engine/src/DataViewClass.cpp index 938770ecf5..efb45daf3f 100644 --- a/libraries/script-engine/src/DataViewClass.cpp +++ b/libraries/script-engine/src/DataViewClass.cpp @@ -64,7 +64,7 @@ QScriptValue DataViewClass::construct(QScriptContext *context, QScriptEngine *en } if (byteOffsetArg.isNumber() && (byteOffsetArg.toInt32() < 0 || - byteOffsetArg.toInt32() >= arrayBuffer->size())) { + byteOffsetArg.toInt32() > arrayBuffer->size())) { engine->evaluate("throw \"RangeError: byteOffset out of range\""); return QScriptValue(); } diff --git a/libraries/script-engine/src/DataViewPrototype.cpp b/libraries/script-engine/src/DataViewPrototype.cpp index 17734e109c..95f3fdf3f6 100644 --- a/libraries/script-engine/src/DataViewPrototype.cpp +++ b/libraries/script-engine/src/DataViewPrototype.cpp @@ -26,7 +26,10 @@ QByteArray* DataViewPrototype::thisArrayBuffer() const { return qscriptvalue_cast(bufferObject.data()); } -bool DataViewPrototype::realOffset(quint32& offset, size_t size) const { +bool DataViewPrototype::realOffset(qint32& offset, size_t size) const { + if (offset < 0) { + return false; + } quint32 viewOffset = thisObject().data().property(BYTE_OFFSET_PROPERTY_NAME).toInt32(); quint32 viewLength = thisObject().data().property(BYTE_LENGTH_PROPERTY_NAME).toInt32(); //qDebug() << "View Offset: " << viewOffset << ", View Lenght: " << viewLength; @@ -38,7 +41,7 @@ bool DataViewPrototype::realOffset(quint32& offset, size_t size) const { ///////////////// GETTERS //////////////////////////// -qint32 DataViewPrototype::getInt8(quint32 byteOffset) { +qint32 DataViewPrototype::getInt8(qint32 byteOffset) { if (realOffset(byteOffset, sizeof(qint8))) { QDataStream stream(*thisArrayBuffer()); stream.skipRawData(byteOffset); @@ -51,7 +54,7 @@ qint32 DataViewPrototype::getInt8(quint32 byteOffset) { return 0; } -quint32 DataViewPrototype::getUint8(quint32 byteOffset) { +quint32 DataViewPrototype::getUint8(qint32 byteOffset) { if (realOffset(byteOffset, sizeof(quint8))) { QDataStream stream(*thisArrayBuffer()); stream.skipRawData(byteOffset); @@ -64,7 +67,7 @@ quint32 DataViewPrototype::getUint8(quint32 byteOffset) { return 0; } -qint32 DataViewPrototype::getInt16(quint32 byteOffset, bool littleEndian) { +qint32 DataViewPrototype::getInt16(qint32 byteOffset, bool littleEndian) { if (realOffset(byteOffset, sizeof(qint16))) { QDataStream stream(*thisArrayBuffer()); stream.skipRawData(byteOffset); @@ -78,7 +81,7 @@ qint32 DataViewPrototype::getInt16(quint32 byteOffset, bool littleEndian) { return 0; } -quint32 DataViewPrototype::getUint16(quint32 byteOffset, bool littleEndian) { +quint32 DataViewPrototype::getUint16(qint32 byteOffset, bool littleEndian) { if (realOffset(byteOffset, sizeof(quint16))) { QDataStream stream(*thisArrayBuffer()); stream.skipRawData(byteOffset); @@ -92,7 +95,7 @@ quint32 DataViewPrototype::getUint16(quint32 byteOffset, bool littleEndian) { return 0; } -qint32 DataViewPrototype::getInt32(quint32 byteOffset, bool littleEndian) { +qint32 DataViewPrototype::getInt32(qint32 byteOffset, bool littleEndian) { if (realOffset(byteOffset, sizeof(qint32))) { QDataStream stream(*thisArrayBuffer()); stream.skipRawData(byteOffset); @@ -106,7 +109,7 @@ qint32 DataViewPrototype::getInt32(quint32 byteOffset, bool littleEndian) { return 0; } -quint32 DataViewPrototype::getUint32(quint32 byteOffset, bool littleEndian) { +quint32 DataViewPrototype::getUint32(qint32 byteOffset, bool littleEndian) { if (realOffset(byteOffset, sizeof(quint32))) { QDataStream stream(*thisArrayBuffer()); stream.skipRawData(byteOffset); @@ -120,25 +123,28 @@ quint32 DataViewPrototype::getUint32(quint32 byteOffset, bool littleEndian) { return 0; } -float DataViewPrototype::getFloat32(quint32 byteOffset, bool littleEndian) { +float DataViewPrototype::getFloat32(qint32 byteOffset, bool littleEndian) { if (realOffset(byteOffset, sizeof(float))) { QDataStream stream(*thisArrayBuffer()); stream.skipRawData(byteOffset); stream.setByteOrder((littleEndian) ? QDataStream::LittleEndian : QDataStream::BigEndian); + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); float result; stream >> result; + qDebug() << "Get: " << result; return result; } thisObject().engine()->evaluate("throw \"RangeError: byteOffset out of range\""); return 0; } -double DataViewPrototype::getFloat64(quint32 byteOffset, bool littleEndian) { +double DataViewPrototype::getFloat64(qint32 byteOffset, bool littleEndian) { if (realOffset(byteOffset, sizeof(double))) { QDataStream stream(*thisArrayBuffer()); stream.skipRawData(byteOffset); stream.setByteOrder((littleEndian) ? QDataStream::LittleEndian : QDataStream::BigEndian); + stream.setFloatingPointPrecision(QDataStream::DoublePrecision); double result; stream >> result; @@ -150,7 +156,7 @@ double DataViewPrototype::getFloat64(quint32 byteOffset, bool littleEndian) { ///////////////// SETTERS //////////////////////////// -void DataViewPrototype::setInt8(quint32 byteOffset, qint32 value) { +void DataViewPrototype::setInt8(qint32 byteOffset, qint32 value) { if (realOffset(byteOffset, sizeof(qint8))) { QDataStream stream(thisArrayBuffer(), QIODevice::ReadWrite); stream.skipRawData(byteOffset); @@ -161,7 +167,7 @@ void DataViewPrototype::setInt8(quint32 byteOffset, qint32 value) { } } -void DataViewPrototype::setUint8(quint32 byteOffset, quint32 value) { +void DataViewPrototype::setUint8(qint32 byteOffset, quint32 value) { if (realOffset(byteOffset, sizeof(quint8))) { QDataStream stream(thisArrayBuffer(), QIODevice::ReadWrite); stream.skipRawData(byteOffset); @@ -172,7 +178,7 @@ void DataViewPrototype::setUint8(quint32 byteOffset, quint32 value) { } } -void DataViewPrototype::setInt16(quint32 byteOffset, qint32 value, bool littleEndian) { +void DataViewPrototype::setInt16(qint32 byteOffset, qint32 value, bool littleEndian) { if (realOffset(byteOffset, sizeof(qint16))) { QDataStream stream(thisArrayBuffer(), QIODevice::ReadWrite); stream.skipRawData(byteOffset); @@ -184,7 +190,7 @@ void DataViewPrototype::setInt16(quint32 byteOffset, qint32 value, bool littleEn } } -void DataViewPrototype::setUint16(quint32 byteOffset, quint32 value, bool littleEndian) { +void DataViewPrototype::setUint16(qint32 byteOffset, quint32 value, bool littleEndian) { if (realOffset(byteOffset, sizeof(quint16))) { QDataStream stream(thisArrayBuffer(), QIODevice::ReadWrite); stream.skipRawData(byteOffset); @@ -196,7 +202,7 @@ void DataViewPrototype::setUint16(quint32 byteOffset, quint32 value, bool little } } -void DataViewPrototype::setInt32(quint32 byteOffset, qint32 value, bool littleEndian) { +void DataViewPrototype::setInt32(qint32 byteOffset, qint32 value, bool littleEndian) { if (realOffset(byteOffset, sizeof(qint32))) { QDataStream stream(thisArrayBuffer(), QIODevice::ReadWrite); stream.skipRawData(byteOffset); @@ -208,7 +214,7 @@ void DataViewPrototype::setInt32(quint32 byteOffset, qint32 value, bool littleEn } } -void DataViewPrototype::setUint32(quint32 byteOffset, quint32 value, bool littleEndian) { +void DataViewPrototype::setUint32(qint32 byteOffset, quint32 value, bool littleEndian) { if (realOffset(byteOffset, sizeof(quint32))) { QDataStream stream(thisArrayBuffer(), QIODevice::ReadWrite); stream.skipRawData(byteOffset); @@ -220,11 +226,12 @@ void DataViewPrototype::setUint32(quint32 byteOffset, quint32 value, bool little } } -void DataViewPrototype::setFloat32(quint32 byteOffset, float value, bool littleEndian) { +void DataViewPrototype::setFloat32(qint32 byteOffset, float value, bool littleEndian) { if (realOffset(byteOffset, sizeof(float))) { QDataStream stream(thisArrayBuffer(), QIODevice::ReadWrite); stream.skipRawData(byteOffset); stream.setByteOrder((littleEndian) ? QDataStream::LittleEndian : QDataStream::BigEndian); + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); stream << value; } else { @@ -232,11 +239,12 @@ void DataViewPrototype::setFloat32(quint32 byteOffset, float value, bool littleE } } -void DataViewPrototype::setFloat64(quint32 byteOffset, double value, bool littleEndian) { +void DataViewPrototype::setFloat64(qint32 byteOffset, double value, bool littleEndian) { if (realOffset(byteOffset, sizeof(double))) { QDataStream stream(thisArrayBuffer(), QIODevice::ReadWrite); stream.skipRawData(byteOffset); stream.setByteOrder((littleEndian) ? QDataStream::LittleEndian : QDataStream::BigEndian); + stream.setFloatingPointPrecision(QDataStream::DoublePrecision); stream << value; } else { diff --git a/libraries/script-engine/src/DataViewPrototype.h b/libraries/script-engine/src/DataViewPrototype.h index 97c94c58ce..b7061a388e 100644 --- a/libraries/script-engine/src/DataViewPrototype.h +++ b/libraries/script-engine/src/DataViewPrototype.h @@ -31,14 +31,14 @@ public slots: // // These methods raise an exception if they would read // beyond the end of the view. - qint32 getInt8(quint32 byteOffset); - quint32 getUint8(quint32 byteOffset); - qint32 getInt16(quint32 byteOffset, bool littleEndian = false); - quint32 getUint16(quint32 byteOffset, bool littleEndian = false); - qint32 getInt32(quint32 byteOffset, bool littleEndian = false); - quint32 getUint32(quint32 byteOffset, bool littleEndian = false); - float getFloat32(quint32 byteOffset, bool littleEndian = false); - double getFloat64(quint32 byteOffset, bool littleEndian = false); + qint32 getInt8(qint32 byteOffset); + quint32 getUint8(qint32 byteOffset); + qint32 getInt16(qint32 byteOffset, bool littleEndian = false); + quint32 getUint16(qint32 byteOffset, bool littleEndian = false); + qint32 getInt32(qint32 byteOffset, bool littleEndian = false); + quint32 getUint32(qint32 byteOffset, bool littleEndian = false); + float getFloat32(qint32 byteOffset, bool littleEndian = false); + double getFloat64(qint32 byteOffset, bool littleEndian = false); // Stores a value of the given type at the specified byte offset // from the start of the view. There is no alignment constraint; @@ -51,18 +51,18 @@ public slots: // // These methods raise an exception if they would write // beyond the end of the view. - void setInt8(quint32 byteOffset, qint32 value); - void setUint8(quint32 byteOffset, quint32 value); - void setInt16(quint32 byteOffset, qint32 value, bool littleEndian = false); - void setUint16(quint32 byteOffset, quint32 value, bool littleEndian = false); - void setInt32(quint32 byteOffset, qint32 value, bool littleEndian = false); - void setUint32(quint32 byteOffset, quint32 value, bool littleEndian = false); - void setFloat32(quint32 byteOffset, float value, bool littleEndian = false); - void setFloat64(quint32 byteOffset, double value, bool littleEndian = false); + void setInt8(qint32 byteOffset, qint32 value); + void setUint8(qint32 byteOffset, quint32 value); + void setInt16(qint32 byteOffset, qint32 value, bool littleEndian = false); + void setUint16(qint32 byteOffset, quint32 value, bool littleEndian = false); + void setInt32(qint32 byteOffset, qint32 value, bool littleEndian = false); + void setUint32(qint32 byteOffset, quint32 value, bool littleEndian = false); + void setFloat32(qint32 byteOffset, float value, bool littleEndian = false); + void setFloat64(qint32 byteOffset, double value, bool littleEndian = false); private: QByteArray* thisArrayBuffer() const; - bool realOffset(quint32& offset, size_t size) const; + bool realOffset(qint32& offset, size_t size) const; }; #endif // hifi_DataViewPrototype_h \ No newline at end of file diff --git a/libraries/script-engine/src/TypedArrays.cpp b/libraries/script-engine/src/TypedArrays.cpp index d6ffc8f5a6..102c477c04 100644 --- a/libraries/script-engine/src/TypedArrays.cpp +++ b/libraries/script-engine/src/TypedArrays.cpp @@ -56,6 +56,7 @@ QScriptValue TypedArray::newInstance(QScriptValue array) { } return newArray; } + engine()->evaluate("throw \"ArgumentError: not an array\""); return QScriptValue(); } @@ -200,19 +201,23 @@ QByteArray* TypedArrayPrototype::thisArrayBuffer() const { return qscriptvalue_cast(bufferObject.data()); } -void TypedArrayPrototype::set(QScriptValue array, quint32 offset) { +void TypedArrayPrototype::set(QScriptValue array, qint32 offset) { TypedArray* typedArray = static_cast(parent()); - if (array.isArray()) { + if (array.isArray() || typedArray) { + if (offset < 0) { + engine()->evaluate("throw \"ArgumentError: negative offset\""); + } quint32 length = array.property("length").toInt32(); if (offset + length > thisObject().data().property(typedArray->_lengthName).toInt32()) { - // TODO throw an error maybe? + engine()->evaluate("throw \"ArgumentError: array does not fit\""); return; } for (int i = 0; i < length; ++i) { thisObject().setProperty(QString::number(offset + i), array.property(QString::number(i))); } + } else { + engine()->evaluate("throw \"ArgumentError: not an array\""); } - // TODO handle typed arrays } QScriptValue TypedArrayPrototype::subarray(qint32 begin) { @@ -411,15 +416,31 @@ Float32ArrayClass::Float32ArrayClass(ScriptEngine* scriptEngine) : TypedArray(sc QScriptValue Float32ArrayClass::property(const QScriptValue &object, const QScriptString &name, uint id) { - QByteArray* arrayBuffer = qscriptvalue_cast(object.data().property(_bufferName).data()); - QScriptValue result = propertyHelper(arrayBuffer, name, id); - return (result.isValid()) ? result : TypedArray::property(object, name, id); + QByteArray* arrayBuffer = qscriptvalue_cast(object.data().property(_bufferName).data());bool ok = false; + name.toArrayIndex(&ok); + + if (ok && arrayBuffer) { + QDataStream stream(*arrayBuffer); + stream.skipRawData(id); + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); + + float result; + stream >> result; + return result; + } + return TypedArray::property(object, name, id); } void Float32ArrayClass::setProperty(QScriptValue &object, const QScriptString &name, uint id, const QScriptValue &value) { QByteArray *ba = qscriptvalue_cast(object.data().property(_bufferName).data()); - setPropertyHelper(ba, name, id, value); + if (ba && value.isNumber()) { + QDataStream stream(ba, QIODevice::ReadWrite); + stream.skipRawData(id); + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); + + stream << (float)value.toNumber(); + } } Float64ArrayClass::Float64ArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, FLOAT_64_ARRAY_CLASS_NAME) { @@ -428,16 +449,30 @@ Float64ArrayClass::Float64ArrayClass(ScriptEngine* scriptEngine) : TypedArray(sc QScriptValue Float64ArrayClass::property(const QScriptValue &object, const QScriptString &name, uint id) { - QByteArray* arrayBuffer = qscriptvalue_cast(object.data().property(_bufferName).data()); - QScriptValue result = propertyHelper(arrayBuffer, name, id); - return (result.isValid()) ? result : TypedArray::property(object, name, id); + QByteArray* arrayBuffer = qscriptvalue_cast(object.data().property(_bufferName).data());bool ok = false; + name.toArrayIndex(&ok); + + if (ok && arrayBuffer) { + QDataStream stream(*arrayBuffer); + stream.skipRawData(id); + stream.setFloatingPointPrecision(QDataStream::DoublePrecision); + + double result; + stream >> result; + return result; + } + return TypedArray::property(object, name, id); } void Float64ArrayClass::setProperty(QScriptValue &object, const QScriptString &name, uint id, const QScriptValue &value) { QByteArray *ba = qscriptvalue_cast(object.data().property(_bufferName).data()); - setPropertyHelper(ba, name, id, value); + if (ba && value.isNumber()) { + QDataStream stream(ba, QIODevice::ReadWrite); + stream.skipRawData(id); + stream.setFloatingPointPrecision(QDataStream::DoublePrecision); + + stream << (double)value.toNumber(); + } } - - diff --git a/libraries/script-engine/src/TypedArrays.h b/libraries/script-engine/src/TypedArrays.h index 37d341b2ad..2eff3e84b9 100644 --- a/libraries/script-engine/src/TypedArrays.h +++ b/libraries/script-engine/src/TypedArrays.h @@ -69,7 +69,7 @@ public: TypedArrayPrototype(QObject* parent = NULL); public slots: - void set(QScriptValue array, quint32 offset = 0); + void set(QScriptValue array, qint32 offset = 0); QScriptValue subarray(qint32 begin); QScriptValue subarray(qint32 begin, qint32 end);