1
0
mirror of https://github.com/wine-mirror/wine synced 2024-07-01 07:14:31 +00:00

jscript: Add initial implementation of ArrayBuffer.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
Gabriel Ivăncescu 2024-02-12 17:47:11 +02:00 committed by Alexandre Julliard
parent 52b9f8a9fa
commit 88c0f72bbf
6 changed files with 247 additions and 1 deletions

View File

@ -4,6 +4,7 @@ IMPORTS = oleaut32 ole32 user32 advapi32
SOURCES = \
activex.c \
array.c \
arraybuf.c \
bool.c \
cc_parser.y \
compile.c \

189
dlls/jscript/arraybuf.c Normal file
View File

@ -0,0 +1,189 @@
/*
* Copyright 2024 Gabriel Ivăncescu for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <limits.h>
#include "jscript.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(jscript);
typedef struct {
jsdisp_t dispex;
DWORD size;
DECLSPEC_ALIGN(sizeof(double)) BYTE buf[];
} ArrayBufferInstance;
static inline ArrayBufferInstance *arraybuf_from_jsdisp(jsdisp_t *jsdisp)
{
return CONTAINING_RECORD(jsdisp, ArrayBufferInstance, dispex);
}
static HRESULT ArrayBuffer_get_byteLength(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
{
TRACE("%p\n", jsthis);
*r = jsval_number(arraybuf_from_jsdisp(jsthis)->size);
return S_OK;
}
static HRESULT ArrayBuffer_slice(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
FIXME("not implemented\n");
return E_NOTIMPL;
}
static const builtin_prop_t ArrayBuffer_props[] = {
{L"byteLength", NULL, 0, ArrayBuffer_get_byteLength},
{L"slice", ArrayBuffer_slice, PROPF_METHOD|2},
};
static const builtin_info_t ArrayBuffer_info = {
JSCLASS_ARRAYBUFFER,
NULL,
ARRAY_SIZE(ArrayBuffer_props),
ArrayBuffer_props,
NULL,
NULL
};
static const builtin_prop_t ArrayBufferInst_props[] = {
{L"byteLength", NULL, 0, ArrayBuffer_get_byteLength},
};
static const builtin_info_t ArrayBufferInst_info = {
JSCLASS_ARRAYBUFFER,
NULL,
ARRAY_SIZE(ArrayBufferInst_props),
ArrayBufferInst_props,
NULL,
NULL
};
static HRESULT create_arraybuf(script_ctx_t *ctx, DWORD size, ArrayBufferInstance **ret)
{
ArrayBufferInstance *arraybuf;
HRESULT hres;
if(!(arraybuf = calloc(1, FIELD_OFFSET(ArrayBufferInstance, buf[size]))))
return E_OUTOFMEMORY;
hres = init_dispex_from_constr(&arraybuf->dispex, ctx, &ArrayBufferInst_info, ctx->arraybuf_constr);
if(FAILED(hres)) {
free(arraybuf);
return hres;
}
arraybuf->size = size;
*ret = arraybuf;
return S_OK;
}
static HRESULT ArrayBufferConstr_isView(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
FIXME("not implemented\n");
return E_NOTIMPL;
}
static HRESULT ArrayBufferConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
ArrayBufferInstance *arraybuf;
DWORD size = 0;
HRESULT hres;
TRACE("\n");
switch(flags) {
case DISPATCH_METHOD:
case DISPATCH_CONSTRUCT: {
if(argc) {
double n;
hres = to_integer(ctx, argv[0], &n);
if(FAILED(hres))
return hres;
if(n < 0.0)
return JS_E_INVALID_LENGTH;
if(n > (UINT_MAX - FIELD_OFFSET(ArrayBufferInstance, buf[0])))
return E_OUTOFMEMORY;
size = n;
}
if(r) {
hres = create_arraybuf(ctx, size, &arraybuf);
if(FAILED(hres))
return hres;
*r = jsval_obj(&arraybuf->dispex);
}
break;
}
default:
FIXME("unimplemented flags: %x\n", flags);
return E_NOTIMPL;
}
return S_OK;
}
static const builtin_prop_t ArrayBufferConstr_props[] = {
{L"isView", ArrayBufferConstr_isView, PROPF_METHOD|1},
};
static const builtin_info_t ArrayBufferConstr_info = {
JSCLASS_FUNCTION,
Function_value,
ARRAY_SIZE(ArrayBufferConstr_props),
ArrayBufferConstr_props,
NULL,
NULL
};
HRESULT init_arraybuf_constructors(script_ctx_t *ctx)
{
ArrayBufferInstance *arraybuf;
HRESULT hres;
if(ctx->version < SCRIPTLANGUAGEVERSION_ES5)
return S_OK;
if(!(arraybuf = calloc(1, FIELD_OFFSET(ArrayBufferInstance, buf[0]))))
return E_OUTOFMEMORY;
hres = init_dispex(&arraybuf->dispex, ctx, &ArrayBuffer_info, ctx->object_prototype);
if(FAILED(hres)) {
free(arraybuf);
return hres;
}
hres = create_builtin_constructor(ctx, ArrayBufferConstr_value, L"ArrayBuffer", &ArrayBufferConstr_info,
PROPF_CONSTR|1, &arraybuf->dispex, &ctx->arraybuf_constr);
jsdisp_release(&arraybuf->dispex);
if(FAILED(hres))
return hres;
hres = jsdisp_define_data_property(ctx->global, L"ArrayBuffer", PROPF_CONFIGURABLE | PROPF_WRITABLE,
jsval_obj(ctx->arraybuf_constr));
return hres;
}

View File

@ -1148,5 +1148,9 @@ HRESULT init_global(script_ctx_t *ctx)
if(FAILED(hres))
return hres;
hres = init_arraybuf_constructors(ctx);
if(FAILED(hres))
return hres;
return init_set_constructor(ctx);
}

View File

@ -116,6 +116,7 @@ typedef enum {
JSCLASS_ARGUMENTS,
JSCLASS_VBARRAY,
JSCLASS_JSON,
JSCLASS_ARRAYBUFFER,
JSCLASS_MAP,
JSCLASS_SET,
JSCLASS_WEAKMAP,
@ -435,11 +436,12 @@ struct _script_ctx_t {
jsdisp_t *regexp_constr;
jsdisp_t *string_constr;
jsdisp_t *vbarray_constr;
jsdisp_t *arraybuf_constr;
jsdisp_t *map_prototype;
jsdisp_t *set_prototype;
jsdisp_t *weakmap_prototype;
};
jsdisp_t *global_objects[23];
jsdisp_t *global_objects[24];
};
};
C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, weakmap_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects));
@ -464,6 +466,7 @@ HRESULT init_global(script_ctx_t*);
HRESULT init_function_constr(script_ctx_t*,jsdisp_t*);
HRESULT create_object_prototype(script_ctx_t*,jsdisp_t**);
HRESULT init_set_constructor(script_ctx_t*);
HRESULT init_arraybuf_constructors(script_ctx_t*);
HRESULT create_activex_constr(script_ctx_t*,jsdisp_t**);
HRESULT create_array_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**);

View File

@ -50,6 +50,7 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns
L"[object Object]",
L"[object Object]",
L"[object Object]",
L"[object ArrayBuffer]",
L"[object Object]",
L"[object Object]",
L"[object Object]"

View File

@ -28,6 +28,7 @@ var JS_E_VBARRAY_EXPECTED = 0x800a1395;
var JS_E_ENUMERATOR_EXPECTED = 0x800a1397;
var JS_E_REGEXP_EXPECTED = 0x800a1398;
var JS_E_UNEXPECTED_QUANTIFIER = 0x800a139a;
var JS_E_INVALID_LENGTH = 0x800a13a5;
var JS_E_INVALID_WRITABLE_PROP_DESC = 0x800a13ac;
var JS_E_NONCONFIGURABLE_REDEFINED = 0x800a13d6;
var JS_E_NONWRITABLE_MODIFIED = 0x800a13d7;
@ -1681,6 +1682,53 @@ sync_test("RegExp", function() {
}
});
sync_test("ArrayBuffers & Views", function() {
var r, buf;
function test_own_props(obj_name, props) {
var obj = eval(obj_name);
for(var i = 0; i < props.length; i++)
ok(Object.prototype.hasOwnProperty.call(obj, props[i]), props[i] + " not a property of " + obj_name);
}
function test_readonly(obj, prop, val) {
var name = Object.getPrototypeOf(obj).constructor.toString();
name = name.substring(9, name.indexOf("(", 9)) + ".prototype." + prop;
obj[prop] = val + 42;
ok(obj[prop] === val, name + " not read-only");
}
test_own_props("ArrayBuffer", [ "isView" ]);
test_own_props("ArrayBuffer.prototype", [ "byteLength", "slice" ]);
test_own_data_prop_desc(ArrayBuffer.prototype, "byteLength", false, false, false);
r = Object.prototype.toString.call(new ArrayBuffer());
ok(r === "[object ArrayBuffer]", "Object toString(new ArrayBuffer()) = " + r);
r = ArrayBuffer.length;
ok(r === 1, "ArrayBuffer.length = " + r);
r = ArrayBuffer.isView.length;
ok(r === 1, "ArrayBuffer.isView.length = " + r);
r = ArrayBuffer.prototype.slice.length;
ok(r === 2, "ArrayBuffer.prototype.slice.length = " + r);
try {
new ArrayBuffer(-1);
ok(false, "new ArrayBuffer(-1) did not throw exception");
}catch(ex) {
var n = ex.number >>> 0;
ok(n === JS_E_INVALID_LENGTH, "new ArrayBuffer(-1) threw " + n);
}
buf = new ArrayBuffer();
ok(buf.byteLength === 0, "ArrayBuffer().byteLength = " + buf.byteLength);
buf = new ArrayBuffer(13.1);
ok(buf.byteLength === 13, "ArrayBuffer(13).byteLength = " + buf.byteLength);
buf = ArrayBuffer("10");
ok(buf.byteLength === 10, "ArrayBuffer(10).byteLength = " + buf.byteLength);
test_readonly(buf, "byteLength", 10);
test_own_data_prop_desc(buf, "byteLength", false, false, false);
});
sync_test("builtin_context", function() {
var nullDisp = external.nullDisp;
var tests = [