diff options
Diffstat (limited to 'src')
9 files changed, 545 insertions, 138 deletions
diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 0b62a10..5ccab57 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -22,9 +22,9 @@ namespace uscxml { class Data { public: enum Type { - VERBATIM, - INTERPRETED, - BINARY, + VERBATIM, + INTERPRETED, + BINARY, }; Data() : type(INTERPRETED) {} diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp index f8e0479..c5aec92 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp @@ -292,32 +292,32 @@ JSValueRef JSCDataModel::getDataAsValue(const Data& data) { handleException(exception); return value; } - + switch (data.type) { - case Data::VERBATIM: { - JSStringRef stringRef = JSStringCreateWithUTF8CString(data.atom.c_str()); - JSValueRef value = JSValueMakeString(_ctx, stringRef); - JSStringRelease(stringRef); - return value; - break; - } - case Data::INTERPRETED: { - return evalAsValue(data.atom); - break; - } - case Data::BINARY: { - uscxml::ArrayBuffer* localInstance = new uscxml::ArrayBuffer((void*)data.atom.c_str(), data.atom.size()); - - JSClassRef retClass = JSCArrayBuffer::getTmpl(); - struct JSCArrayBuffer::JSCArrayBufferPrivate* retPrivData = new JSCArrayBuffer::JSCArrayBufferPrivate(); - retPrivData->nativeObj = localInstance; - - JSObjectRef retObj = JSObjectMake(_ctx, retClass, retPrivData); - return retObj; - break; - } + case Data::VERBATIM: { + JSStringRef stringRef = JSStringCreateWithUTF8CString(data.atom.c_str()); + JSValueRef value = JSValueMakeString(_ctx, stringRef); + JSStringRelease(stringRef); + return value; + break; } - + case Data::INTERPRETED: { + return evalAsValue(data.atom); + break; + } + case Data::BINARY: { + uscxml::ArrayBuffer* localInstance = new uscxml::ArrayBuffer((void*)data.atom.c_str(), data.atom.size()); + + JSClassRef retClass = JSCArrayBuffer::getTmpl(); + struct JSCArrayBuffer::JSCArrayBufferPrivate* retPrivData = new JSCArrayBuffer::JSCArrayBufferPrivate(); + retPrivData->nativeObj = localInstance; + + JSObjectRef retObj = JSObjectMake(_ctx, retClass, retPrivData); + return retObj; + break; + } + } + } Data JSCDataModel::getValueAsData(const JSValueRef value) { diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCArrayBuffer.h b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCArrayBuffer.h index b3fa8ea..452b652 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCArrayBuffer.h +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCArrayBuffer.h @@ -44,9 +44,6 @@ public: static JSObjectRef jsConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); static JSValueRef byteLengthAttrGetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception); - static bool hasPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName); - static JSValueRef getPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception); - static bool setPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception); static JSStaticValue staticValues[]; @@ -59,9 +56,6 @@ public: classDef.staticValues = staticValues; classDef.staticFunctions = staticFunctions; classDef.finalize = jsDestructor; - classDef.hasProperty = hasPropertyCustomCallback; - classDef.getProperty = getPropertyCustomCallback; - classDef.setProperty = setPropertyCustomCallback; classDef.callAsConstructor = jsConstructor; Tmpl = JSClassCreate(&classDef); diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCTypedArrayCustom.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCTypedArrayCustom.cpp index 4ef0b8e..3c0f3d5 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCTypedArrayCustom.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCTypedArrayCustom.cpp @@ -150,10 +150,6 @@ bool JSCUint8ClampedArray::hasPropertyCustomCallback(JSContextRef ctx, JSObjectR JSC_TYPED_ARRAY_HAS_PROP_RETURN(Uint8ClampedArray); } -bool JSCArrayBuffer::hasPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) { - JSC_TYPED_ARRAY_HAS_PROP_RETURN(ArrayBuffer); -} - // ----------------- JSValueRef JSCInt8Array::getPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { @@ -192,10 +188,6 @@ JSValueRef JSCUint8ClampedArray::getPropertyCustomCallback(JSContextRef ctx, JSO JSC_TYPED_ARRAY_GET_PROP_RETURN(Uint8ClampedArray); } -JSValueRef JSCArrayBuffer::getPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { - JSC_TYPED_ARRAY_GET_PROP_RETURN(ArrayBuffer); -} - // ---------------- bool JSCInt8Array::setPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) { @@ -234,10 +226,6 @@ bool JSCUint8ClampedArray::setPropertyCustomCallback(JSContextRef ctx, JSObjectR JSC_TYPED_ARRAY_SET_PROP_RETURN(Uint8ClampedArray); } -bool JSCArrayBuffer::setPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) { - JSC_TYPED_ARRAY_SET_PROP_RETURN(ArrayBuffer); -} - } }
\ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp index 16ee766..e52dfd3 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp @@ -1,10 +1,10 @@ #include "TypedArray.h" #include <iostream> +#include <boost/detail/endian.hpp> -#define DATAVIEW_TYPED_RETURN(type) \ +#define DATAVIEW_TYPED_GET(type) \ type retVal;\ -memcpy(&retVal, _buffer->_data + (_start + index), sizeof(type));\ -return retVal; +memcpy(&retVal, _buffer->_data + (_start + index), sizeof(type)); #define DATAVIEW_TYPED_SET(type) \ memcpy(_buffer->_data + (_start + index), &value, sizeof(type)); @@ -39,17 +39,28 @@ ArrayBuffer::ArrayBuffer(void* data, unsigned int size) { } unsigned long ArrayBuffer::getByteLength() { + if (!_buffer) + return 0; return _buffer->_size; } -ArrayBuffer ArrayBuffer::slice(long begin, long length) { - ArrayBuffer arrBuffer(length); - memcpy(arrBuffer._buffer->_data, _buffer->_data + begin, length); +ArrayBuffer ArrayBuffer::slice(long begin, long end) { + if (!_buffer) { + return ArrayBuffer(0); + } + unsigned int realBegin = (begin + _buffer->_size) % _buffer->_size; + unsigned int realEnd = (end + _buffer->_size) % _buffer->_size; + if (realEnd < realBegin) { + return ArrayBuffer(0); + } + + ArrayBuffer arrBuffer(realEnd - realBegin); + memcpy(arrBuffer._buffer->_data, _buffer->_data + realBegin, realEnd - realBegin); return arrBuffer; } ArrayBuffer ArrayBuffer::slice(long begin) { - return slice(begin, _buffer->_size - begin); + return slice(begin, _buffer->_size); } bool ArrayBuffer::isView(void*) { @@ -95,35 +106,91 @@ unsigned long DataView::getLength() { } char DataView::getInt8(unsigned long index) { - DATAVIEW_TYPED_RETURN(int8_t); + DATAVIEW_TYPED_GET(int8_t); + return retVal; } unsigned char DataView::getUint8(unsigned long index) { - DATAVIEW_TYPED_RETURN(uint8_t); + DATAVIEW_TYPED_GET(uint8_t); + return retVal; } short DataView::getInt16(unsigned long index, bool littleEndian) { - DATAVIEW_TYPED_RETURN(int16_t); + DATAVIEW_TYPED_GET(int16_t); +#ifdef BOOST_LITTLE_ENDIAN + if (littleEndian) + return retVal; + return byte_swap<little_endian, big_endian>(retVal); +#else + if (littleEndian) + return byte_swap<big_endian, little_endian>(retVal); + return retVal; +#endif } unsigned short DataView::getUint16(unsigned long index, bool littleEndian) { - DATAVIEW_TYPED_RETURN(uint16_t); + DATAVIEW_TYPED_GET(uint16_t); +#ifdef BOOST_LITTLE_ENDIAN + if (littleEndian) + return retVal; + return byte_swap<little_endian, big_endian>(retVal); +#else + if (littleEndian) + return byte_swap<big_endian, little_endian>(retVal); + return retVal; +#endif } long DataView::getInt32(unsigned long index, bool littleEndian) { - DATAVIEW_TYPED_RETURN(int32_t); + DATAVIEW_TYPED_GET(int32_t); +#ifdef BOOST_LITTLE_ENDIAN + if (littleEndian) + return retVal; + return byte_swap<little_endian, big_endian>(retVal); +#else + if (littleEndian) + return byte_swap<big_endian, little_endian>(retVal); + return retVal; +#endif } unsigned long DataView::getUint32(unsigned long index, bool littleEndian) { - DATAVIEW_TYPED_RETURN(uint32_t); + DATAVIEW_TYPED_GET(uint32_t); +#ifdef BOOST_LITTLE_ENDIAN + if (littleEndian) + return retVal; + return byte_swap<little_endian, big_endian>(retVal); +#else + if (littleEndian) + return byte_swap<big_endian, little_endian>(retVal); + return retVal; +#endif } float DataView::getFloat32(unsigned long index, bool littleEndian) { - DATAVIEW_TYPED_RETURN(float); + DATAVIEW_TYPED_GET(float); +#ifdef BOOST_LITTLE_ENDIAN + if (littleEndian) + return retVal; + return byte_swap<little_endian, big_endian>(retVal); +#else + if (littleEndian) + return byte_swap<big_endian, little_endian>(retVal); + return retVal; +#endif } double DataView::getFloat64(unsigned long index, bool littleEndian) { - DATAVIEW_TYPED_RETURN(double); + DATAVIEW_TYPED_GET(double); +#ifdef BOOST_LITTLE_ENDIAN + if (littleEndian) + return retVal; + return byte_swap<little_endian, big_endian>(retVal); +#else + if (littleEndian) + return byte_swap<big_endian, little_endian>(retVal); + return retVal; +#endif } void DataView::setInt8(long index, char value) { @@ -134,26 +201,69 @@ void DataView::setUint8(long index, unsigned char value) { DATAVIEW_TYPED_SET(uint8_t); } -void DataView::setInt16(long index, short value, bool) { +void DataView::setInt16(long index, short value, bool littleEndian) { +#ifdef BOOST_LITTLE_ENDIAN + if (!littleEndian) + value = byte_swap<little_endian, big_endian>(value); +#else + if (littleEndian) + value = byte_swap<big_endian, little_endian>(value); +#endif DATAVIEW_TYPED_SET(int16_t); } + void DataView::setUint16(long index, unsigned short value, bool littleEndian) { +#ifdef BOOST_LITTLE_ENDIAN + if (!littleEndian) + value = byte_swap<little_endian, big_endian>(value); +#else + if (littleEndian) + value = byte_swap<big_endian, little_endian>(value); +#endif DATAVIEW_TYPED_SET(uint16_t); } void DataView::setInt32(long index, long value, bool littleEndian) { +#ifdef BOOST_LITTLE_ENDIAN + if (!littleEndian) + value = byte_swap<little_endian, big_endian>(value); +#else + if (littleEndian) + value = byte_swap<big_endian, little_endian>(value); +#endif DATAVIEW_TYPED_SET(int32_t); } void DataView::setUint32(long index, unsigned long value, bool littleEndian) { +#ifdef BOOST_LITTLE_ENDIAN + if (!littleEndian) + value = byte_swap<little_endian, big_endian>(value); +#else + if (littleEndian) + value = byte_swap<big_endian, little_endian>(value); +#endif DATAVIEW_TYPED_SET(uint32_t); } void DataView::setFloat32(long index, float value, bool littleEndian) { +#ifdef BOOST_LITTLE_ENDIAN + if (!littleEndian) + value = byte_swap<little_endian, big_endian>(value); +#else + if (littleEndian) + value = byte_swap<big_endian, little_endian>(value); +#endif DATAVIEW_TYPED_SET(float); } void DataView::setFloat64(long index, double value, bool littleEndian) { +#ifdef BOOST_LITTLE_ENDIAN + if (!littleEndian) + value = byte_swap<little_endian, big_endian>(value); +#else + if (littleEndian) + value = byte_swap<big_endian, little_endian>(value); +#endif DATAVIEW_TYPED_SET(double); } diff --git a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h index 229ae70..e238d15 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h +++ b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h @@ -7,9 +7,18 @@ #include <string.h> #include <inttypes.h> +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> +#include <boost/detail/endian.hpp> +#include <stdexcept> + namespace uscxml { +/** + * https://www.khronos.org/registry/typedarray/specs/latest/ + */ + class ArrayBuffer { public: class Buffer { @@ -22,10 +31,33 @@ public: }; ArrayBuffer(void* data, unsigned int size); + + /** + * Creates a new ArrayBuffer of the given length in bytes. The contents of the + * ArrayBuffer are initialized to 0. If the requested number of bytes could not + * be allocated an exception is raised. + */ ArrayBuffer(unsigned long length); ArrayBuffer(boost::shared_ptr<ArrayBuffer::Buffer>); + + /** + * The length of the ArrayBuffer in bytes, as fixed at construction time. + * Reading this property returns 0 if this ArrayBuffer has been neutered. + */ unsigned long getByteLength(); - ArrayBuffer slice(long begin, long length); + + /** + * Returns a new ArrayBuffer whose contents are a copy of this ArrayBuffer's + * bytes from begin, inclusive, up to end, exclusive. If either begin or end + * is negative, it refers to an index from the end of the array, as opposed + * to from the beginning. + * If end is unspecified, the new ArrayBuffer contains all bytes from begin + * to the end of this ArrayBuffer. + * The range specified by the begin and end values is clamped to the valid + * index range for the current array. If the computed length of the new + * ArrayBuffer would be negative, it is clamped to zero. + */ + ArrayBuffer slice(long begin, long end); ArrayBuffer slice(long begin); static bool isView(void*); unsigned long getLength() { @@ -35,17 +67,17 @@ public: bool operator== (const ArrayBuffer& other) { return other._buffer == _buffer; } - unsigned char get(unsigned long index) { - if (index >= getLength()) - return 0; - unsigned char retVal; - memcpy(&retVal, _buffer->_data + index * sizeof(unsigned char), sizeof(unsigned char)); - return retVal; - } - - void set(unsigned long index, unsigned char value) { - memcpy(_buffer->_data + index * sizeof(unsigned char), &value, sizeof(unsigned char)); - } +// unsigned char get(unsigned long index) { +// if (index >= getLength()) +// return 0; +// unsigned char retVal; +// memcpy(&retVal, _buffer->_data + index * sizeof(unsigned char), sizeof(unsigned char)); +// return retVal; +// } +// +// void set(unsigned long index, unsigned char value) { +// memcpy(_buffer->_data + index * sizeof(unsigned char), &value, sizeof(unsigned char)); +// } boost::shared_ptr<Buffer> _buffer; }; @@ -53,8 +85,23 @@ public: class ArrayBufferView { public: virtual ~ArrayBufferView() {} + /** + * The ArrayBuffer that this ArrayBufferView references. + */ ArrayBuffer getBuffer(); + + /** + * The offset of this ArrayBufferView from the start of its ArrayBuffer, in + * bytes, as fixed at construction time. Reading this property returns 0 if + * the referenced ArrayBuffer has been neutered. + */ virtual unsigned long getByteOffset() = 0; + + /** + * The length of the ArrayBufferView in bytes, as fixed at construction time. + * Reading this property returns 0 if the referenced ArrayBuffer has been + * neutered. + */ virtual unsigned long getByteLength() = 0; virtual unsigned long getLength() = 0; protected: @@ -63,6 +110,7 @@ protected: unsigned long _end; }; + class DataView : ArrayBufferView { public: DataView(ArrayBuffer*, unsigned long, unsigned long); @@ -73,6 +121,17 @@ public: unsigned long getByteLength(); unsigned long getLength(); + /** + * Gets the value of the given type at the specified byte offset + * from the start of the view. There is no alignment constraint; + * multi-byte values may be fetched from any offset. + * For multi-byte values, the optional littleEndian argument + * indicates whether a big-endian or little-endian value should be + * read. If false or undefined, a big-endian value is read. + * These methods raise an exception if they would read + * beyond the end of the view. + */ + char getInt8(unsigned long); unsigned char getUint8(unsigned long); short getInt16(unsigned long, bool = false); @@ -82,6 +141,18 @@ public: float getFloat32(unsigned long, bool = false); double getFloat64(unsigned long, bool = false); + /** + * Stores a value of the given type at the specified byte offset + * from the start of the view. There is no alignment constraint; + * multi-byte values may be stored at any offset. + * For multi-byte values, the optional littleEndian argument + * indicates whether the value should be stored in big-endian or + * little-endian byte order. If false or undefined, the value is + * stored in big-endian byte order. + * These methods raise an exception if they would write + * beyond the end of the view. + */ + void setInt8(long, char); void setUint8(long, unsigned char); void setInt16(long, short, bool = false); @@ -96,13 +167,41 @@ public: template<class T, class S> class TypedArray : public ArrayBufferView { public: virtual ~TypedArray() {} - TypedArray(uscxml::ArrayBuffer* buffer, unsigned long start, unsigned long length) { - _start = start; - _end = start + length; + + /** + * Create a new TypedArray object using the passed ArrayBuffer for its storage. + * Optional byteOffset and length can be used to limit the section of the buffer + * referenced. The byteOffset indicates the offset in bytes from the start of + * the ArrayBuffer, and the length is the count of elements from the offset + * that this TypedArray will reference. If both byteOffset and length are + * omitted, the TypedArray spans the entire ArrayBuffer range. If the length + * is omitted, the TypedArray extends from the given byteOffset until the end + * of the ArrayBuffer. + * The given byteOffset must be a multiple of the element size of the specific + * type, otherwise an exception is raised. + * If a given byteOffset and length references an area beyond the end of the + * ArrayBuffer an exception is raised. + * If length is not explicitly specified, the length of the ArrayBuffer minus + * the byteOffset must be a multiple of the element size of the specific type, + * or an exception is raised. + */ + TypedArray(uscxml::ArrayBuffer* buffer, unsigned long byteOffset, unsigned long length) { + if (byteOffset % sizeof(S)) + return; + + _start = byteOffset / sizeof(S); + _end = _start + length; + + if (_end > buffer->_buffer->_size / sizeof(S)) + return; + _buffer = buffer->_buffer; } - TypedArray(uscxml::ArrayBuffer* buffer, unsigned long start) { - _start = start / sizeof(S); + TypedArray(uscxml::ArrayBuffer* buffer, unsigned long byteOffset) { + if (byteOffset % sizeof(S)) + return; + + _start = byteOffset / sizeof(S); _end = buffer->_buffer->_size / sizeof(S); _buffer = buffer->_buffer; } @@ -112,38 +211,55 @@ public: _buffer = buffer->_buffer; } - TypedArray(boost::shared_ptr<ArrayBuffer::Buffer> buffer, unsigned long start, unsigned long length) { - _start = start; - _end = start + length; + TypedArray(boost::shared_ptr<ArrayBuffer::Buffer> buffer, unsigned long byteOffset, unsigned long length) { + if (byteOffset % sizeof(S)) + return; + + _start = byteOffset / sizeof(S); + _end = _start + length; + + if (_end > buffer->_size / sizeof(S)) + return; + _buffer = buffer; } + + /** + * Create a new ArrayBuffer with enough bytes to hold length elements of this + * typed array, then creates a typed array view referring to the full buffer. + * As with a directly constructed ArrayBuffer, the contents are initialized + * to 0. If the requested number of bytes could not be allocated an exception + * is raised. + */ TypedArray(unsigned long length) { _start = 0; _end = length; _buffer = boost::shared_ptr<ArrayBuffer::Buffer>(new ArrayBuffer::Buffer(length * sizeof(S))); } + + /** + * Create a new ArrayBuffer with enough bytes to hold array.length elements of + * this typed array, then creates a typed array view referring to the full + * buffer. The contents of the new view are initialized to the contents of the + * given array or typed array, with each element converted to the appropriate + * typed array type. + */ TypedArray(std::vector<T> data) { _start = 0; _end = data.size(); - if (sizeof(T) == sizeof(S)) { - _buffer = boost::shared_ptr<ArrayBuffer::Buffer>(new ArrayBuffer::Buffer(((void*)&data[0]), data.size() * sizeof(T))); - } else { - S* buffer = (S*)malloc(data.size() * sizeof(S)); - typename std::vector<T>::const_iterator dataIter = data.begin(); - unsigned long i = 0; - while(dataIter != data.end()) { - buffer[i] = *dataIter; - dataIter++; - i++; - } - _buffer = boost::shared_ptr<ArrayBuffer::Buffer>(new ArrayBuffer::Buffer(buffer, data.size() * sizeof(S))); - } + _buffer = boost::shared_ptr<ArrayBuffer::Buffer>(new ArrayBuffer::Buffer(data.size() * sizeof(S))); + set(data, 0); } TypedArray(TypedArray* other) { _start = other->_start; _end = other->_end; _buffer = other->_buffer; } + + /** + * This is an index getter. + * Returns the element at the given numeric index. + */ T get(unsigned long index) { if (index >= getLength()) return static_cast<T>(0); @@ -151,44 +267,129 @@ public: memcpy(&retVal, _buffer->_data + (_start + index) * sizeof(S), sizeof(S)); return retVal; } + + /** + * This is an index setter. + * Sets the element at the given numeric index to the given value. + */ void set(unsigned long index, T value) { memcpy(_buffer->_data + (_start + index) * sizeof(S), &value, sizeof(S)); } + /** + * Set multiple values, reading input values from the array. + * The optional offset value indicates the index in the current array where + * values are written. If omitted, it is assumed to be 0. + * If the input array is a TypedArray, the two arrays may use the same + * underlying ArrayBuffer. In this situation, setting the values takes place + * as if all the data is first copied into a temporary buffer that does not + * overlap either of the arrays, and then the data from the temporary buffer + * is copied into the current array. + * If the offset plus the length of the given array is out of range for the + * current TypedArray, an exception is raised. + */ void set(TypedArray<T, S>* value, unsigned long offset) { - memcpy(_buffer->_data + (_start) * sizeof(S), &value->_buffer->_data[offset], value->_buffer->_size); + if (!_buffer) + return; + if (offset * sizeof(S) + value->_buffer->_size > _buffer->_size) + return; + + // will this work if we use the same buffer? + memcpy(_buffer->_data + (_start + offset) * sizeof(S), &value->_buffer->_data, value->_buffer->_size); } void set(TypedArray<T, S>* value) { set(value, 0); } + /** + * Set multiple values, reading input values from the array. + * The optional offset value indicates the index in the current array where + * values are written. If omitted, it is assumed to be 0. + * If the input array is a TypedArray, the two arrays may use the same + * underlying ArrayBuffer. In this situation, setting the values takes place + * as if all the data is first copied into a temporary buffer that does not + * overlap either of the arrays, and then the data from the temporary buffer + * is copied into the current array. + * If the offset plus the length of the given array is out of range for the + * current TypedArray, an exception is raised. + */ void set(std::vector<T> data, unsigned long offset) { + if (!_buffer) + return; + if (data.size() + offset > _end) + return; + + if (sizeof(T) == sizeof(S)) { + memcpy(_buffer->_data + offset, (void*)&data[0], data.size()); + } else { + S* buffer = (S*)malloc(data.size() * sizeof(S)); + typename std::vector<T>::const_iterator dataIter = data.begin(); + unsigned long i = 0; + while(dataIter != data.end()) { + buffer[i] = *dataIter; + dataIter++; + i++; + } + memcpy(_buffer->_data + offset, buffer, data.size()); + free (buffer); + } } void set(std::vector<T> data) { set(data, 0); } - TypedArray* subarray(long start, long end) { - return new TypedArray<T, S>(_buffer, start, end); + /** + * Returns a new TypedArray view of the ArrayBuffer store for this TypedArray, + * referencing the elements at begin, inclusive, up to end, exclusive. If + * either begin or end is negative, it refers to an index from the end of the + * array, as opposed to from the beginning. + * If end is unspecified, the subarray contains all elements from begin to the + * end of the TypedArray. + * The range specified by the begin and end values is clamped to the valid + * index range for the current array. If the computed length of the new + * TypedArray would be negative, it is clamped to zero. + * The returned TypedArray will be of the same type as the array on which this + * method is invoked. + */ + TypedArray* subarray(long begin, long end) { + if (!_buffer) + return NULL; + unsigned int realBegin = (begin + _buffer->_size) % _buffer->_size; + unsigned int realEnd = (end + _buffer->_size) % _buffer->_size; + + if (realEnd < realBegin) + return NULL; + + return new TypedArray<T, S>(_buffer, realBegin, realEnd); } unsigned long getLength() { + if (!_buffer) + return 0; return _end - _start; } unsigned long getByteLength() { + if (!_buffer) + return 0; return (_end - _start) * sizeof(S); } unsigned long getByteOffset() { + if (!_buffer) + return 0; return _start * sizeof(S); } - }; +/** + * Define actual types as template instances. + * First argument is representation from JavaScript, second type maybe smaller to + * exactly specify the byte width ot the TypedArray. + */ typedef TypedArray<unsigned char, uint8_t> Uint8Array; typedef TypedArray<unsigned char, uint8_t> Uint8ClampedArray; typedef TypedArray<char, int8_t> Int8Array; @@ -199,6 +400,141 @@ typedef TypedArray<unsigned long, uint32_t> Uint32Array; typedef TypedArray<float, float> Float32Array; typedef TypedArray<double, double> Float64Array; + +// see http://www.cplusplus.com/forum/general/27544/ + +// Little-endian operating systems: +//--------------------------------- +// Linux on x86, x64, Alpha and Itanium +// Mac OS on x86, x64 +// Solaris on x86, x64, PowerPC +// Tru64 on Alpha +// Windows on x86, x64 and Itanium + +// Big-endian operating systems: +//------------------------------ +// AIX on POWER +// AmigaOS on PowerPC and 680x0 +// HP-UX on Itanium and PA-RISC +// Linux on MIPS, SPARC, PA-RISC, POWER, PowerPC, and 680x0 +// Mac OS on PowerPC and 680x0 +// Solaris on SPARC + +enum endianness { + little_endian, + big_endian, + network_endian = big_endian, + +#if defined(BOOST_LITTLE_ENDIAN) + host_endian = little_endian +#elif defined(BOOST_BIG_ENDIAN) + host_endian = big_endian +#else +#error "unable to determine system endianness" +#endif +}; + +namespace detail { + +template<typename T, size_t sz> +struct swap_bytes { + inline T operator()(T val) { + throw std::out_of_range("data size"); + } +}; + +template<typename T> +struct swap_bytes<T, 1> { + inline T operator()(T val) { + return val; + } +}; + +template<typename T> +struct swap_bytes<T, 2> { // for 16 bit + inline T operator()(T val) { + return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8)); + } +}; + +template<typename T> +struct swap_bytes<T, 4> { // for 32 bit + inline T operator()(T val) { +#if defined(_USE_BUILTIN_BSWAPS) && defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4) + return __builtin_bswap32(val); +#else + return ((((val) & 0xff000000) >> 24) | + (((val) & 0x00ff0000) >> 8) | + (((val) & 0x0000ff00) << 8) | + (((val) & 0x000000ff) << 24)); +#endif + } +}; + +template<> +struct swap_bytes<float, 4> { + inline float operator()(float val) { + uint32_t mem = swap_bytes<uint32_t, sizeof(uint32_t)>()(*(uint32_t*)&val); + return *(float*)&mem; + } +}; + +template<typename T> +struct swap_bytes<T, 8> { // for 64 bit + inline T operator()(T val) { +#if defined(_USE_BUILTIN_BSWAPS) && defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4) + return __builtin_bswap64(val); +#else + return ((((val) & 0xff00000000000000ull) >> 56) | + (((val) & 0x00ff000000000000ull) >> 40) | + (((val) & 0x0000ff0000000000ull) >> 24) | + (((val) & 0x000000ff00000000ull) >> 8 ) | + (((val) & 0x00000000ff000000ull) << 8 ) | + (((val) & 0x0000000000ff0000ull) << 24) | + (((val) & 0x000000000000ff00ull) << 40) | + (((val) & 0x00000000000000ffull) << 56)); +#endif + } +}; + +template<> +struct swap_bytes<double, 8> { + inline double operator()(double val) { + uint64_t mem = swap_bytes<uint64_t, sizeof(uint64_t)>()(*(uint64_t*)&val); + return *(double*)&mem; + } +}; + +template<endianness from, endianness to, class T> +struct do_byte_swap { + inline T operator()(T value) { + return swap_bytes<T, sizeof(T)>()(value); + } +}; +// specialisations when attempting to swap to the same endianess +template<class T> struct do_byte_swap<little_endian, little_endian, T> { + inline T operator()(T value) { + return value; + } +}; +template<class T> struct do_byte_swap<big_endian, big_endian, T> { + inline T operator()(T value) { + return value; + } +}; + +} // namespace detail + +template<endianness from, endianness to, class T> +inline T byte_swap(T value) { + // ensure the data is only 1, 2, 4 or 8 bytes + BOOST_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8); + // ensure we're only swapping arithmetic types + BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value); + + return detail::do_byte_swap<from, to, T>()(value); +} + } #endif /* end of include guard: TYPEDARRAY_H_99815BLY */ diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 919f4a1..caf482b 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -351,25 +351,25 @@ v8::Handle<v8::Value> V8DataModel::getDataAsValue(const Data& data) { return value; } switch (data.type) { - case Data::VERBATIM: - return v8::String::New(data.atom.c_str()); - break; - case Data::INTERPRETED: - return evalAsValue(data.atom); - break; - case Data::BINARY: { - uscxml::ArrayBuffer* arrBuffer = new uscxml::ArrayBuffer((void*)data.atom.c_str(), data.atom.size()); - v8::Handle<v8::Function> retCtor = V8ArrayBuffer::getTmpl()->GetFunction(); - v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance()); - - struct V8ArrayBuffer::V8ArrayBufferPrivate* retPrivData = new V8ArrayBuffer::V8ArrayBufferPrivate(); - retPrivData->nativeObj = arrBuffer; - retObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); - - retObj.MakeWeak(0, V8ArrayBuffer::jsDestructor); - return retObj; - break; - } + case Data::VERBATIM: + return v8::String::New(data.atom.c_str()); + break; + case Data::INTERPRETED: + return evalAsValue(data.atom); + break; + case Data::BINARY: { + uscxml::ArrayBuffer* arrBuffer = new uscxml::ArrayBuffer((void*)data.atom.c_str(), data.atom.size()); + v8::Handle<v8::Function> retCtor = V8ArrayBuffer::getTmpl()->GetFunction(); + v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance()); + + struct V8ArrayBuffer::V8ArrayBufferPrivate* retPrivData = new V8ArrayBuffer::V8ArrayBufferPrivate(); + retPrivData->nativeObj = arrBuffer; + retObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); + + retObj.MakeWeak(0, V8ArrayBuffer::jsDestructor); + return retObj; + break; + } } // this will never be reached return v8::Undefined(); diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8ArrayBuffer.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8ArrayBuffer.h index d4229eb..767d520 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8ArrayBuffer.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8ArrayBuffer.h @@ -45,8 +45,6 @@ public: static v8::Handle<v8::Value> isViewCallback(const v8::Arguments&); static v8::Handle<v8::Value> byteLengthAttrGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info); - static v8::Handle<v8::Value> indexedPropertyCustomGetter(uint32_t, const v8::AccessorInfo&); - static v8::Handle<v8::Value> indexedPropertyCustomSetter(uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo&); static v8::Handle<v8::Value> constructor(const v8::Arguments&); static v8::Persistent<v8::FunctionTemplate> Constr; @@ -74,7 +72,6 @@ public: instance->SetAccessor(v8::String::NewSymbol("byteLength"), V8ArrayBuffer::byteLengthAttrGetter, 0, v8::External::New(0), static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None)); - instance->SetIndexedPropertyHandler(V8ArrayBuffer::indexedPropertyCustomGetter, V8ArrayBuffer::indexedPropertyCustomSetter); prototype->Set(v8::String::NewSymbol("slice"), v8::FunctionTemplate::New(V8ArrayBuffer::sliceCallback, v8::Undefined()), static_cast<v8::PropertyAttribute>(v8::DontDelete)); prototype->Set(v8::String::NewSymbol("isView"), diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8TypedArrayCustom.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8TypedArrayCustom.cpp index 118eb46..95e86de 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8TypedArrayCustom.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8TypedArrayCustom.cpp @@ -75,16 +75,6 @@ v8::Handle<v8::Value> V8Uint8ClampedArray::indexedPropertyCustomSetter(unsigned return value; } -v8::Handle<v8::Value> V8ArrayBuffer::indexedPropertyCustomSetter(unsigned int index, v8::Local<v8::Value> value, const v8::AccessorInfo &info) { - v8::Local<v8::Object> self = info.Holder(); - uscxml::ArrayBuffer* array = V8DOM::toClassPtr<V8ArrayBufferPrivate >(self->GetInternalField(0))->nativeObj; - if (index > array->getByteLength()) - return v8::Undefined(); - array->_buffer->_data[index] = value->ToInt32()->Value() & 0xff; - return value; - -} - // ---------------- v8::Handle<v8::Value> V8Int8Array::indexedPropertyCustomGetter(unsigned int index, const v8::AccessorInfo &info) { @@ -132,13 +122,5 @@ v8::Handle<v8::Value> V8Uint8ClampedArray::indexedPropertyCustomGetter(unsigned return v8::Uint32::New(array->get(index)); } -v8::Handle<v8::Value> V8ArrayBuffer::indexedPropertyCustomGetter(unsigned int index, const v8::AccessorInfo &info) { - v8::Local<v8::Object> self = info.Holder(); - uscxml::ArrayBuffer* array = V8DOM::toClassPtr<V8ArrayBufferPrivate >(self->GetInternalField(0))->nativeObj; - if (index > array->getByteLength()) - return v8::Undefined(); - return v8::Int32::New(array->_buffer->_data[index]); -} - } }
\ No newline at end of file |