From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 75 ++++++++++++++++++++++++++++++- dlls/jscript/error.c | 1 + dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/mshtml/tests/es5.js | 97 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 172 insertions(+), 4 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 9e8cb17a7c4..b11691c7053 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -831,13 +831,84 @@ static HRESULT fill_typedarr_data_from_object(script_ctx_t *ctx, BYTE *data, jsd static HRESULT TypedArray_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r, jsclass_t jsclass) { + const unsigned elem_size = TypedArray_elem_size[TYPEDARRAY_INDEX(jsclass)]; TypedArrayInstance *typedarr; + DWORD begin = 0, size; + BYTE *dest, *data; + IDispatch *disp; + jsdisp_t *obj; + HRESULT hres; + jsval_t val; + UINT32 len; + double n;
- FIXME("not implemented\n"); + TRACE("\n");
if(!(typedarr = typedarr_this(vthis, jsclass))) return JS_E_NOT_TYPEDARRAY; - return E_NOTIMPL; + if(!argc) + return JS_E_TYPEDARRAY_INVALID_SOURCE; + + hres = to_object(ctx, argv[0], &disp); + if(FAILED(hres)) + return JS_E_TYPEDARRAY_INVALID_SOURCE; + + if(!(obj = to_jsdisp(disp))) { + FIXME("Non-JS array object\n"); + hres = JS_E_TYPEDARRAY_INVALID_SOURCE; + goto done; + } + + hres = jsdisp_propget_name(obj, L"length", &val); + if(FAILED(hres)) + goto done; + + hres = to_uint32(ctx, val, &len); + jsval_release(val); + if(FAILED(hres)) + goto done; + + if(argc > 1) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + goto done; + if(n < 0.0 || n > typedarr->length) { + hres = JS_E_TYPEDARRAY_INVALID_OFFSLEN; + goto done; + } + begin = n; + } + + if(len > typedarr->length - begin) { + hres = JS_E_TYPEDARRAY_INVALID_OFFSLEN; + goto done; + } + size = len * elem_size; + dest = data = &typedarr->buffer->buf[typedarr->offset + begin * elem_size]; + + /* If they overlap, make a temporary copy */ + if(obj->builtin_info->class >= FIRST_TYPEDARRAY_JSCLASS && obj->builtin_info->class <= LAST_TYPEDARRAY_JSCLASS) { + TypedArrayInstance *src_arr = typedarr_from_jsdisp(obj); + const BYTE *src = src_arr->buffer->buf + src_arr->offset; + + if(dest < src + len * TypedArray_elem_size[TYPEDARRAY_INDEX(obj->builtin_info->class)] && + dest + size > src) { + if(!(data = malloc(size))) { + hres = E_OUTOFMEMORY; + goto done; + } + } + } + + hres = fill_typedarr_data_from_object(ctx, data, obj, len, jsclass); + if(SUCCEEDED(hres) && dest != data) { + memcpy(dest, data, size); + free(data); + } + +done: + IDispatch_Release(disp); + return hres; }
static HRESULT TypedArray_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index ca45697e74a..4902940517c 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -485,6 +485,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_NONWRITABLE_MODIFIED: case JS_E_TYPEDARRAY_BAD_CTOR_ARG: case JS_E_NOT_TYPEDARRAY: + case JS_E_TYPEDARRAY_INVALID_SOURCE: case JS_E_NOT_DATAVIEW: case JS_E_DATAVIEW_NO_ARGUMENT: case JS_E_WRONG_THIS: diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 594531ff031..8c2b4103825 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -601,6 +601,7 @@ static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_ #define JS_E_NOT_TYPEDARRAY MAKE_JSERROR(IDS_NOT_TYPEDARRAY) #define JS_E_TYPEDARRAY_INVALID_OFFSLEN MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_OFFSLEN) #define JS_E_TYPEDARRAY_INVALID_SUBARRAY MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SUBARRAY) +#define JS_E_TYPEDARRAY_INVALID_SOURCE MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SOURCE) #define JS_E_NOT_DATAVIEW MAKE_JSERROR(IDS_NOT_DATAVIEW) #define JS_E_DATAVIEW_NO_ARGUMENT MAKE_JSERROR(IDS_DATAVIEW_NO_ARGUMENT) #define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index b3036ffe435..6feec39d084 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -80,6 +80,7 @@ STRINGTABLE IDS_TYPEDARRAY_BAD_CTOR_ARG "Typed array constructor argument is invalid" IDS_TYPEDARRAY_INVALID_OFFSLEN "Invalid offset/length when creating typed array" IDS_TYPEDARRAY_INVALID_SUBARRAY "Invalid begin/end value in typed array subarray method" + IDS_TYPEDARRAY_INVALID_SOURCE "Invalid source in typed array set" IDS_NOT_DATAVIEW "'this' is not a DataView object" IDS_DATAVIEW_NO_ARGUMENT "Required argument offset or value in DataView method is not specified" IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 91d99048858..48572bd4992 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -78,6 +78,7 @@ #define IDS_NOT_TYPEDARRAY 0x13DB #define IDS_TYPEDARRAY_INVALID_OFFSLEN 0x13DC #define IDS_TYPEDARRAY_INVALID_SUBARRAY 0x13DD +#define IDS_TYPEDARRAY_INVALID_SOURCE 0x13DE #define IDS_NOT_DATAVIEW 0x13DF #define IDS_DATAVIEW_NO_ARGUMENT 0x13E0 #define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index f416f26da15..b344061ef5c 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -36,6 +36,7 @@ var JS_E_TYPEDARRAY_BAD_CTOR_ARG = 0x800a13da; var JS_E_NOT_TYPEDARRAY = 0x800a13db; var JS_E_TYPEDARRAY_INVALID_OFFSLEN = 0x800a13dc; var JS_E_TYPEDARRAY_INVALID_SUBARRAY = 0x800a13dd; +var JS_E_TYPEDARRAY_INVALID_SOURCE = 0x800a13de; var JS_E_NOT_DATAVIEW = 0x800a13df; var JS_E_DATAVIEW_NO_ARGUMENT = 0x800a13e0; var JS_E_DATAVIEW_INVALID_ACCESS = 0x800a13e1; @@ -2349,6 +2350,87 @@ sync_test("ArrayBuffers & Views", function() { ok(arr2.byteOffset === 2 * typeSz, name + ".subarray(2, -3).byteOffset = " + arr2.byteOffset); ok(arr2.length === 5, name + ".subarray(2, -3).length = " + arr2.length); ok(arr2.buffer === arr.buffer, name + ".subarray(2, -3).buffer = " + arr2.buffer); + + try { + arr.set.call(null, [1]); + ok(false, arrType + ": calling set with null context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, arrType + ": calling set with null context threw " + n); + } + try { + arr.set.call({}, [1]); + ok(false, arrType + ": calling set with an object context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, arrType + ": calling set with an object context threw " + n); + } + try { + arr.set(); + ok(false, name + ".set() did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_SOURCE, name + ".set() threw " + n); + } + try { + arr.set(null); + ok(false, name + ".set(null) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_SOURCE, name + ".set(null) threw " + n); + } + try { + arr.set([1,2,3], 8); + ok(false, name + ".set([1,2,3], 8) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, name + ".set([1,2,3], 8) threw " + n); + } + try { + arr.set([99], -3); + ok(false, name + ".set([99], -3) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, name + ".set([99], -3) threw " + n); + } + + r = arr.set(5); + ok(r === undefined, name + ".set(5) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === 0, name + ".set(5): arr[" + j + "] = " + arr[j]); + + r = arr.set({}); + ok(r === undefined, name + ".set({}) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === 0, name + ".set({}): arr[" + j + "] = " + arr[j]); + + r = arr.set("12"); + ok(r === undefined, name + ".set('12') returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 1, 2, 0, 0, 0, 0, 0, 0, 0, 0 ][j], name + ".set('12'): arr[" + j + "] = " + arr[j]); + + arr2 = { length: 2 }; + arr2[0] = 9; + arr2[1] = 7; + r = arr.set(arr2); + ok(r === undefined, name + ".set(array-like obj) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 0, 0, 0, 0, 0, 0, 0, 0 ][j], name + ".set(array-like obj): arr[" + j + "] = " + arr[j]); + + r = arr.set([12, 10, 11], 3); + ok(r === undefined, name + ".set([12, 10, 11], 3) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 0, 12, 10, 11, 0, 0, 0, 0 ][j], name + ".set([12, 10, 11], 3): arr[" + j + "] = " + arr[j]); + + r = arr.set(arr.subarray(4, 6), 5); + ok(r === undefined, name + ".set(arr.subarray(4, 2), 5) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 0, 12, 10, 10, 11, 0, 0, 0 ][j], name + ".set(arr.subarray(4, 2), 5): arr[" + j + "] = " + arr[j]); + + r = arr.set(arr.subarray(3, 7), 2); + ok(r === undefined, name + ".set(arr.subarray(3, 7), 2) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 12, 10, 10, 11, 11, 0, 0, 0 ][j], name + ".set(arr.subarray(3, 7), 2): arr[" + j + "] = " + arr[j]); }
arr = new Float32Array(3); @@ -2378,8 +2460,19 @@ sync_test("ArrayBuffers & Views", function() { ok(arr[0] == 254, "8-bit arr[0] after overflow = " + arr[0]); ok(arr[1] == 2, "8-bit arr[1] after overflow = " + arr[1]);
- arr = new Int8Array(); - arr2 = new Int32Array(); + arr = new Int8Array(12); + arr.set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); + for(var j = 0; j < 12; j++) + ok(arr[j] === j + 1, "sequential arr[" + j + "] = " + arr[j]); + arr2 = new Int32Array(arr.buffer); + ok(arr2.buffer === arr.buffer, "arr2.buffer = " + arr2.buffer); + for(var j = 0; j < 3; j++) + ok(arr2[j] === [ 0x04030201, 0x08070605, 0x0c0b0a09 ][j], "sequential 32-bit arr[" + j + "] = " + arr2[j]); + + /* test overlap */ + arr2.set(arr.subarray(1, 4)); + for(var j = 0; j < 3; j++) + ok(arr2[j] === j + 2, "arr with overlap[" + j + "] = " + arr[j]);
/* methods are incompatible, even though thrown error is not explicit */ ok(Uint16Array.prototype.subarray !== Int32Array.prototype.subarray, "Uint16Array and Int32Array have same subarray methods");