Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4438500
buffer.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
118 KB
Referenced Files
None
Subscribers
None
buffer.c
View Options
#include
<stdlib.h>
#include
<stdio.h>
#include
<string.h>
#include
<ctype.h>
#include
"ant.h"
#include
"ptr.h"
#include
"utf8.h"
#include
"utils.h"
#include
"errors.h"
#include
"base64.h"
#include
"internal.h"
#include
"runtime.h"
#include
"gc/roots.h"
#include
"descriptors.h"
#include
"silver/engine.h"
#include
"modules/bigint.h"
#include
"modules/buffer.h"
#include
"modules/symbol.h"
#define BUFFER_REGISTRY_INITIAL_CAP 64
// Node compatibility exports only
// Ant does not enforce these as allocation limits
#define BUFFER_COMPAT_MAX_LENGTH 4294967296.0
#define BUFFER_COMPAT_MAX_STRING_LENGTH 536870888.0
#define BUFFER_COMPAT_INSPECT_MAX_BYTES 50.0
static
size_t
ta_metadata_bytes
=
0
;
static
size_t
buffer_registry_count
=
0
;
static
size_t
buffer_registry_cap
=
0
;
static
ArrayBufferData
**
buffer_registry
=
NULL
;
static
ant_value_t
g_typedarray_iter_proto
=
0
;
enum
{
BUFFER_ARRAYBUFFER_NATIVE_TAG
=
0x41425546u
,
// ABUF
BUFFER_TYPEDARRAY_NATIVE_TAG
=
0x54594152u
,
// TYAR
BUFFER_DATAVIEW_NATIVE_TAG
=
0x44564957u
,
// DVIW
};
static
void
*
ta_meta_alloc
(
size_t
size
)
{
void
*
ptr
=
ant_calloc
(
size
);
if
(
!
ptr
)
return
NULL
;
ta_metadata_bytes
+=
size
;
return
ptr
;
}
static
void
ta_meta_free
(
void
*
ptr
,
size_t
size
)
{
if
(
!
ptr
)
return
;
if
(
ta_metadata_bytes
>=
size
)
ta_metadata_bytes
-=
size
;
else
ta_metadata_bytes
=
0
;
free
(
ptr
);
}
ArrayBufferData
*
buffer_get_arraybuffer_data
(
ant_value_t
value
)
{
if
(
!
is_object_type
(
value
)
||
buffer_is_dataview
(
value
))
return
NULL
;
if
(
js_check_native_tag
(
value
,
BUFFER_ARRAYBUFFER_NATIVE_TAG
))
return
(
ArrayBufferData
*
)
js_get_native_ptr
(
value
);
return
NULL
;
}
TypedArrayData
*
buffer_get_typedarray_data
(
ant_value_t
value
)
{
if
(
vtype
(
value
)
==
T_TYPEDARRAY
)
return
(
TypedArrayData
*
)
js_gettypedarray
(
value
);
if
(
!
is_object_type
(
value
))
return
NULL
;
if
(
js_check_native_tag
(
value
,
BUFFER_TYPEDARRAY_NATIVE_TAG
))
return
(
TypedArrayData
*
)
js_get_native_ptr
(
value
);
return
NULL
;
}
DataViewData
*
buffer_get_dataview_data
(
ant_value_t
value
)
{
if
(
!
is_object_type
(
value
))
return
NULL
;
if
(
js_check_native_tag
(
value
,
BUFFER_DATAVIEW_NATIVE_TAG
))
return
(
DataViewData
*
)
js_get_native_ptr
(
value
);
return
NULL
;
}
static
void
arraybuffer_finalize
(
ant_t
*
js
,
ant_object_t
*
obj
)
{
ant_value_t
value
=
js_obj_from_ptr
(
obj
);
if
(
!
js_check_native_tag
(
value
,
BUFFER_ARRAYBUFFER_NATIVE_TAG
))
return
;
ArrayBufferData
*
data
=
(
ArrayBufferData
*
)
js_get_native_ptr
(
value
);
js_set_native_ptr
(
value
,
NULL
);
js_set_native_tag
(
value
,
0
);
if
(
data
)
free_array_buffer_data
(
data
);
}
static
void
typedarray_finalize
(
ant_t
*
js
,
ant_object_t
*
obj
)
{
ant_value_t
value
=
js_obj_from_ptr
(
obj
);
if
(
!
js_check_native_tag
(
value
,
BUFFER_TYPEDARRAY_NATIVE_TAG
))
return
;
TypedArrayData
*
ta_data
=
(
TypedArrayData
*
)
js_get_native_ptr
(
value
);
js_set_native_ptr
(
value
,
NULL
);
js_set_native_tag
(
value
,
0
);
if
(
!
ta_data
)
return
;
if
(
ta_data
->
buffer
)
free_array_buffer_data
(
ta_data
->
buffer
);
ta_meta_free
(
ta_data
,
sizeof
(
*
ta_data
));
}
static
void
dataview_finalize
(
ant_t
*
js
,
ant_object_t
*
obj
)
{
ant_value_t
value
=
js_obj_from_ptr
(
obj
);
if
(
!
js_check_native_tag
(
value
,
BUFFER_DATAVIEW_NATIVE_TAG
))
return
;
DataViewData
*
dv_data
=
(
DataViewData
*
)
js_get_native_ptr
(
value
);
js_set_native_ptr
(
value
,
NULL
);
js_set_native_tag
(
value
,
0
);
if
(
!
dv_data
)
return
;
if
(
dv_data
->
buffer
)
free_array_buffer_data
(
dv_data
->
buffer
);
ta_meta_free
(
dv_data
,
sizeof
(
*
dv_data
));
}
bool
buffer_is_dataview
(
ant_value_t
obj
)
{
return
js_check_brand
(
obj
,
BRAND_DATAVIEW
);
}
bool
buffer_is_binary_source
(
ant_value_t
value
)
{
if
(
vtype
(
value
)
==
T_TYPEDARRAY
)
return
true
;
if
(
!
is_object_type
(
value
))
return
false
;
if
(
buffer_is_dataview
(
value
))
return
true
;
return
buffer_get_typedarray_data
(
value
)
!=
NULL
||
buffer_get_arraybuffer_data
(
value
)
!=
NULL
;
}
bool
buffer_source_get_bytes
(
ant_t
*
js
,
ant_value_t
value
,
const
uint8_t
**
out
,
size_t
*
len
)
{
if
(
out
)
*
out
=
NULL
;
if
(
len
)
*
len
=
0
;
if
(
!
buffer_is_binary_source
(
value
))
return
false
;
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
value
);
if
(
ta
)
{
if
(
!
ta
->
buffer
||
ta
->
buffer
->
is_detached
)
{
*
out
=
NULL
;
*
len
=
0
;
return
true
;
}
*
out
=
ta
->
buffer
->
data
+
ta
->
byte_offset
;
*
len
=
ta
->
byte_length
;
return
true
;
}
ArrayBufferData
*
ab
=
buffer_get_arraybuffer_data
(
value
);
if
(
ab
)
{
if
(
ab
->
is_detached
)
{
*
out
=
NULL
;
*
len
=
0
;
return
true
;
}
*
out
=
ab
->
data
;
*
len
=
ab
->
length
;
return
true
;
}
if
(
buffer_is_dataview
(
value
))
{
DataViewData
*
dv
=
buffer_get_dataview_data
(
value
);
if
(
!
dv
||
!
dv
->
buffer
||
dv
->
buffer
->
is_detached
)
{
*
out
=
NULL
;
*
len
=
0
;
return
true
;
}
*
out
=
dv
->
buffer
->
data
+
dv
->
byte_offset
;
*
len
=
dv
->
byte_length
;
return
true
;
}
return
false
;
}
static
bool
typedarray_read_value
(
ant_t
*
js
,
const
TypedArrayData
*
ta_data
,
size_t
index
,
ant_value_t
*
out
)
{
if
(
!
out
||
!
ta_data
||
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
||
index
>=
ta_data
->
length
)
{
return
false
;
}
uint8_t
*
data
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
switch
(
ta_data
->
type
)
{
case
TYPED_ARRAY_INT8
:
*
out
=
js_mknum
((
double
)((
int8_t
*
)
data
)[
index
]);
return
true
;
case
TYPED_ARRAY_UINT8
:
case
TYPED_ARRAY_UINT8_CLAMPED
:
*
out
=
js_mknum
((
double
)
data
[
index
]);
return
true
;
case
TYPED_ARRAY_INT16
:
*
out
=
js_mknum
((
double
)((
int16_t
*
)
data
)[
index
]);
return
true
;
case
TYPED_ARRAY_UINT16
:
*
out
=
js_mknum
((
double
)((
uint16_t
*
)
data
)[
index
]);
return
true
;
case
TYPED_ARRAY_INT32
:
*
out
=
js_mknum
((
double
)((
int32_t
*
)
data
)[
index
]);
return
true
;
case
TYPED_ARRAY_UINT32
:
*
out
=
js_mknum
((
double
)((
uint32_t
*
)
data
)[
index
]);
return
true
;
case
TYPED_ARRAY_FLOAT16
:
*
out
=
js_mknum
(
half_to_double
(((
uint16_t
*
)
data
)[
index
]));
return
true
;
case
TYPED_ARRAY_FLOAT32
:
*
out
=
js_mknum
((
double
)((
float
*
)
data
)[
index
]);
return
true
;
case
TYPED_ARRAY_FLOAT64
:
*
out
=
js_mknum
(((
double
*
)
data
)[
index
]);
return
true
;
case
TYPED_ARRAY_BIGINT64
:
*
out
=
bigint_from_int64
(
js
,
((
int64_t
*
)
data
)[
index
]);
return
!
is_err
(
*
out
);
case
TYPED_ARRAY_BIGUINT64
:
*
out
=
bigint_from_uint64
(
js
,
((
uint64_t
*
)
data
)[
index
]);
return
!
is_err
(
*
out
);
default
:
return
false
;
}
}
static
bool
advance_typedarray
(
ant_t
*
js
,
js_iter_t
*
it
,
ant_value_t
*
out
)
{
ant_value_t
iter
=
it
->
iterator
;
ant_value_t
ta_obj
=
js_get_slot
(
iter
,
SLOT_DATA
);
ant_value_t
state_v
=
js_get_slot
(
iter
,
SLOT_ITER_STATE
);
uint32_t
state
=
(
vtype
(
state_v
)
==
T_NUM
)
?
(
uint32_t
)
js_getnum
(
state_v
)
:
0
;
uint32_t
kind
=
ITER_STATE_KIND
(
state
);
uint32_t
idx
=
ITER_STATE_INDEX
(
state
);
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
ta_obj
);
if
(
!
ta
||
!
ta
->
buffer
||
ta
->
buffer
->
is_detached
||
idx
>=
(
uint32_t
)
ta
->
length
)
return
false
;
ant_value_t
value
;
if
(
!
typedarray_read_value
(
js
,
ta
,
idx
,
&
value
))
return
false
;
switch
(
kind
)
{
case
ARR_ITER_KEYS
:
*
out
=
js_mknum
((
double
)
idx
);
break
;
case
ARR_ITER_ENTRIES
:
{
ant_value_t
pair
=
js_mkarr
(
js
);
js_arr_push
(
js
,
pair
,
js_mknum
((
double
)
idx
));
js_arr_push
(
js
,
pair
,
value
);
*
out
=
pair
;
break
;
}
default
:
*
out
=
value
;
break
;
}
js_set_slot
(
iter
,
SLOT_ITER_STATE
,
js_mknum
((
double
)
ITER_STATE_PACK
(
kind
,
idx
+
1
)));
return
true
;
}
static
ant_value_t
ta_iter_next
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
js_iter_t
it
=
{
.
iterator
=
js
->
this_val
};
ant_value_t
value
;
return
js_iter_result
(
js
,
advance_typedarray
(
js
,
&
it
,
&
value
),
value
);
}
static
ant_value_t
ta_values
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
iter
=
js_mkobj
(
js
);
js_set_slot_wb
(
js
,
iter
,
SLOT_DATA
,
js
->
this_val
);
js_set_slot
(
iter
,
SLOT_ITER_STATE
,
js_mknum
((
double
)
ITER_STATE_PACK
(
ARR_ITER_VALUES
,
0
)));
js_set_proto_init
(
iter
,
g_typedarray_iter_proto
);
return
iter
;
}
static
ant_value_t
ta_keys
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
iter
=
js_mkobj
(
js
);
js_set_slot_wb
(
js
,
iter
,
SLOT_DATA
,
js
->
this_val
);
js_set_slot
(
iter
,
SLOT_ITER_STATE
,
js_mknum
((
double
)
ITER_STATE_PACK
(
ARR_ITER_KEYS
,
0
)));
js_set_proto_init
(
iter
,
g_typedarray_iter_proto
);
return
iter
;
}
static
ant_value_t
ta_entries
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
iter
=
js_mkobj
(
js
);
js_set_slot_wb
(
js
,
iter
,
SLOT_DATA
,
js
->
this_val
);
js_set_slot
(
iter
,
SLOT_ITER_STATE
,
js_mknum
((
double
)
ITER_STATE_PACK
(
ARR_ITER_ENTRIES
,
0
)));
js_set_proto_init
(
iter
,
g_typedarray_iter_proto
);
return
iter
;
}
static
void
register_buffer
(
ArrayBufferData
*
data
)
{
if
(
!
data
)
return
;
if
(
!
buffer_registry
)
{
buffer_registry
=
calloc
(
BUFFER_REGISTRY_INITIAL_CAP
,
sizeof
(
ArrayBufferData
*
));
if
(
!
buffer_registry
)
return
;
buffer_registry_cap
=
BUFFER_REGISTRY_INITIAL_CAP
;
}
if
(
buffer_registry_count
>=
buffer_registry_cap
)
{
size_t
new_cap
=
buffer_registry_cap
*
2
;
ArrayBufferData
**
new_reg
=
realloc
(
buffer_registry
,
new_cap
*
sizeof
(
ArrayBufferData
*
));
if
(
!
new_reg
)
return
;
buffer_registry
=
new_reg
;
buffer_registry_cap
=
new_cap
;
}
buffer_registry
[
buffer_registry_count
++
]
=
data
;
}
static
void
unregister_buffer
(
ArrayBufferData
*
data
)
{
if
(
!
data
||
!
buffer_registry
)
return
;
for
(
size_t
i
=
0
;
i
<
buffer_registry_count
;
i
++
)
{
if
(
buffer_registry
[
i
]
==
data
)
{
buffer_registry
[
i
]
=
buffer_registry
[
--
buffer_registry_count
];
return
;
}}
}
static
inline
ssize_t
normalize_index
(
ssize_t
idx
,
ssize_t
len
)
{
if
(
idx
<
0
)
idx
+=
len
;
if
(
idx
<
0
)
return
0
;
if
(
idx
>
len
)
return
len
;
return
idx
;
}
ArrayBufferData
*
create_array_buffer_data
(
size_t
length
)
{
ArrayBufferData
*
data
=
ant_calloc
(
sizeof
(
ArrayBufferData
)
+
length
);
if
(
!
data
)
return
NULL
;
data
->
data
=
(
uint8_t
*
)(
data
+
1
);
memset
(
data
->
data
,
0
,
length
);
data
->
length
=
length
;
data
->
capacity
=
length
;
data
->
ref_count
=
1
;
data
->
is_shared
=
0
;
data
->
is_detached
=
0
;
register_buffer
(
data
);
return
data
;
}
static
ArrayBufferData
*
create_shared_array_buffer_data
(
size_t
length
)
{
ArrayBufferData
*
data
=
create_array_buffer_data
(
length
);
if
(
data
)
data
->
is_shared
=
1
;
return
data
;
}
void
free_array_buffer_data
(
ArrayBufferData
*
data
)
{
if
(
!
data
)
return
;
data
->
ref_count
--
;
if
(
data
->
ref_count
<=
0
)
{
unregister_buffer
(
data
);
free
(
data
);
}
}
static
size_t
get_element_size
(
TypedArrayType
type
)
{
static
const
void
*
dispatch
[]
=
{
&&
L_1
,
&&
L_1
,
&&
L_1
,
&&
L_2
,
&&
L_2
,
&&
L_4
,
&&
L_4
,
&&
L_2
,
&&
L_4
,
&&
L_8
,
&&
L_8
,
&&
L_8
};
if
(
type
>
TYPED_ARRAY_BIGUINT64
)
goto
L_1
;
goto
*
dispatch
[
type
];
L_1
:
return
1
;
L_2
:
return
2
;
L_4
:
return
4
;
L_8
:
return
8
;
}
const
char
*
buffer_typedarray_type_name
(
TypedArrayType
type
)
{
static
const
char
*
const
names
[]
=
{
"Int8Array"
,
"Uint8Array"
,
"Uint8ClampedArray"
,
"Int16Array"
,
"Uint16Array"
,
"Int32Array"
,
"Uint32Array"
,
"Float16Array"
,
"Float32Array"
,
"Float64Array"
,
"BigInt64Array"
,
"BigUint64Array"
,
};
int
i
=
(
int
)
type
;
if
(
i
<
0
||
i
>=
(
int
)(
sizeof
(
names
)
/
sizeof
(
names
[
0
])))
return
"Uint8Array"
;
return
names
[
i
];
}
static
ant_value_t
create_typed_array_like
(
ant_t
*
js
,
ant_value_t
this_val
,
TypedArrayType
type
,
ArrayBufferData
*
buffer
,
size_t
byte_offset
,
size_t
length
)
{
ant_value_t
ab_obj
=
create_arraybuffer_obj
(
js
,
buffer
);
ant_value_t
out
=
create_typed_array_with_buffer
(
js
,
type
,
buffer
,
byte_offset
,
length
,
buffer_typedarray_type_name
(
type
),
ab_obj
);
if
(
is_err
(
out
))
return
out
;
ant_value_t
proto
=
js_get_proto
(
js
,
this_val
);
if
(
is_special_object
(
proto
))
js_set_proto_init
(
out
,
proto
);
return
out
;
}
static
ant_value_t
js_arraybuffer_constructor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
vtype
(
js
->
new_target
)
==
T_UNDEF
)
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"ArrayBuffer constructor requires 'new'"
);
}
size_t
length
=
0
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
{
length
=
(
size_t
)
js_getnum
(
args
[
0
]);
}
ArrayBufferData
*
data
=
create_array_buffer_data
(
length
);
if
(
!
data
)
{
return
js_mkerr
(
js
,
"Failed to allocate ArrayBuffer"
);
}
ant_value_t
obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_get_ctor_proto
(
js
,
"ArrayBuffer"
,
11
);
if
(
is_special_object
(
proto
))
js_set_proto_init
(
obj
,
proto
);
js_set_native_ptr
(
obj
,
data
);
js_set_native_tag
(
obj
,
BUFFER_ARRAYBUFFER_NATIVE_TAG
);
js_set
(
js
,
obj
,
"byteLength"
,
js_mknum
((
double
)
length
));
js_set_finalizer
(
obj
,
arraybuffer_finalize
);
return
obj
;
}
// ArrayBuffer.prototype.slice(begin, end)
static
ant_value_t
js_arraybuffer_slice
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
ArrayBufferData
*
data
=
buffer_get_arraybuffer_data
(
this_val
);
if
(
!
data
)
return
js_mkerr
(
js
,
"Invalid ArrayBuffer"
);
if
(
data
->
is_detached
)
return
js_mkerr
(
js
,
"Cannot slice a detached ArrayBuffer"
);
ssize_t
len
=
(
ssize_t
)
data
->
length
;
ssize_t
begin
=
0
,
end
=
len
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
begin
=
(
ssize_t
)
js_getnum
(
args
[
0
]);
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
end
=
(
ssize_t
)
js_getnum
(
args
[
1
]);
begin
=
normalize_index
(
begin
,
len
);
end
=
normalize_index
(
end
,
len
);
if
(
end
<
begin
)
end
=
begin
;
size_t
new_length
=
(
size_t
)(
end
-
begin
);
ArrayBufferData
*
new_data
=
create_array_buffer_data
(
new_length
);
if
(
!
new_data
)
return
js_mkerr
(
js
,
"Failed to allocate new ArrayBuffer"
);
memcpy
(
new_data
->
data
,
data
->
data
+
begin
,
new_length
);
ant_value_t
new_obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_get_ctor_proto
(
js
,
"ArrayBuffer"
,
11
);
if
(
is_special_object
(
proto
))
js_set_proto_init
(
new_obj
,
proto
);
js_set_native_ptr
(
new_obj
,
new_data
);
js_set_native_tag
(
new_obj
,
BUFFER_ARRAYBUFFER_NATIVE_TAG
);
js_set
(
js
,
new_obj
,
"byteLength"
,
js_mknum
((
double
)
new_length
));
js_set_finalizer
(
new_obj
,
arraybuffer_finalize
);
return
new_obj
;
}
// ArrayBuffer.prototype.transfer(newLength)
static
ant_value_t
js_arraybuffer_transfer
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
ArrayBufferData
*
data
=
buffer_get_arraybuffer_data
(
this_val
);
if
(
!
data
)
return
js_mkerr
(
js
,
"Invalid ArrayBuffer"
);
if
(
data
->
is_detached
)
{
return
js_mkerr
(
js
,
"Cannot transfer a detached ArrayBuffer"
);
}
if
(
data
->
is_shared
)
{
return
js_mkerr
(
js
,
"Cannot transfer a SharedArrayBuffer"
);
}
size_t
new_length
=
data
->
length
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
{
new_length
=
(
size_t
)
js_getnum
(
args
[
0
]);
}
ArrayBufferData
*
new_data
=
create_array_buffer_data
(
new_length
);
if
(
!
new_data
)
return
js_mkerr
(
js
,
"Failed to allocate new ArrayBuffer"
);
size_t
copy_length
=
data
->
length
<
new_length
?
data
->
length
:
new_length
;
memcpy
(
new_data
->
data
,
data
->
data
,
copy_length
);
data
->
is_detached
=
1
;
data
->
length
=
0
;
js_set
(
js
,
this_val
,
"byteLength"
,
js_mknum
(
0
));
ant_value_t
new_obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_get_ctor_proto
(
js
,
"ArrayBuffer"
,
11
);
if
(
is_special_object
(
proto
))
js_set_proto_init
(
new_obj
,
proto
);
js_set_native_ptr
(
new_obj
,
new_data
);
js_set_native_tag
(
new_obj
,
BUFFER_ARRAYBUFFER_NATIVE_TAG
);
js_set
(
js
,
new_obj
,
"byteLength"
,
js_mknum
((
double
)
new_length
));
js_set_finalizer
(
new_obj
,
arraybuffer_finalize
);
return
new_obj
;
}
// ArrayBuffer.prototype.transferToFixedLength(newLength)
static
ant_value_t
js_arraybuffer_transferToFixedLength
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_arraybuffer_transfer
(
js
,
args
,
nargs
);
}
// ArrayBuffer.prototype.detached getter
static
ant_value_t
js_arraybuffer_detached_getter
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
ArrayBufferData
*
data
=
buffer_get_arraybuffer_data
(
this_val
);
if
(
!
data
)
return
js_false
;
return
js_bool
(
data
->
is_detached
);
}
static
ant_value_t
js_arraybuffer_byteLength_getter
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
ant_value_t
this_val
=
js_getthis
(
js
);
ArrayBufferData
*
data
=
buffer_get_arraybuffer_data
(
this_val
);
if
(
!
data
||
data
->
is_detached
)
return
js_mknum
(
0
);
return
js_mknum
((
double
)
data
->
length
);
}
// ArrayBuffer.isView(value)
static
ant_value_t
js_arraybuffer_isView
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
return
js_bool
(
buffer_is_dataview
(
args
[
0
])
||
buffer_get_typedarray_data
(
args
[
0
])
!=
NULL
);
}
static
ant_value_t
buffer_require_bigint_value
(
ant_t
*
js
,
ant_value_t
value
)
{
if
(
vtype
(
value
)
==
T_BIGINT
)
return
value
;
if
(
is_object_type
(
value
))
{
ant_value_t
primitive
=
js_get_slot
(
value
,
SLOT_PRIMITIVE
);
if
(
vtype
(
primitive
)
==
T_BIGINT
)
return
primitive
;
}
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Cannot convert to BigInt"
);
}
static
ant_value_t
typedarray_write_value
(
ant_t
*
js
,
TypedArrayData
*
ta_data
,
size_t
index
,
ant_value_t
value
)
{
if
(
!
ta_data
||
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
||
index
>=
ta_data
->
length
)
{
return
js_mkundef
();
}
uint8_t
*
data
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
switch
(
ta_data
->
type
)
{
case
TYPED_ARRAY_INT8
:
((
int8_t
*
)
data
)[
index
]
=
(
int8_t
)
js_to_number
(
js
,
value
);
return
js_mkundef
();
case
TYPED_ARRAY_UINT8
:
data
[
index
]
=
(
uint8_t
)
js_to_number
(
js
,
value
);
return
js_mkundef
();
case
TYPED_ARRAY_UINT8_CLAMPED
:
data
[
index
]
=
(
uint8_t
)
js_to_number
(
js
,
value
);
return
js_mkundef
();
case
TYPED_ARRAY_INT16
:
((
int16_t
*
)
data
)[
index
]
=
(
int16_t
)
js_to_number
(
js
,
value
);
return
js_mkundef
();
case
TYPED_ARRAY_UINT16
:
((
uint16_t
*
)
data
)[
index
]
=
(
uint16_t
)
js_to_number
(
js
,
value
);
return
js_mkundef
();
case
TYPED_ARRAY_INT32
:
((
int32_t
*
)
data
)[
index
]
=
(
int32_t
)
js_to_number
(
js
,
value
);
return
js_mkundef
();
case
TYPED_ARRAY_UINT32
:
((
uint32_t
*
)
data
)[
index
]
=
(
uint32_t
)
js_to_number
(
js
,
value
);
return
js_mkundef
();
case
TYPED_ARRAY_FLOAT16
:
((
uint16_t
*
)
data
)[
index
]
=
double_to_half
(
js_to_number
(
js
,
value
));
return
js_mkundef
();
case
TYPED_ARRAY_FLOAT32
:
((
float
*
)
data
)[
index
]
=
(
float
)
js_to_number
(
js
,
value
);
return
js_mkundef
();
case
TYPED_ARRAY_FLOAT64
:
((
double
*
)
data
)[
index
]
=
js_to_number
(
js
,
value
);
return
js_mkundef
();
case
TYPED_ARRAY_BIGINT64
:
{
ant_value_t
bigint
=
buffer_require_bigint_value
(
js
,
value
);
int64_t
wrapped
=
0
;
if
(
is_err
(
bigint
))
return
bigint
;
if
(
!
bigint_to_int64_wrapping
(
js
,
bigint
,
&
wrapped
))
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Cannot convert to BigInt"
);
}
((
int64_t
*
)
data
)[
index
]
=
wrapped
;
return
js_mkundef
();
}
case
TYPED_ARRAY_BIGUINT64
:
{
ant_value_t
bigint
=
buffer_require_bigint_value
(
js
,
value
);
uint64_t
wrapped
=
0
;
if
(
is_err
(
bigint
))
return
bigint
;
if
(
!
bigint_to_uint64_wrapping
(
js
,
bigint
,
&
wrapped
))
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Cannot convert to BigInt"
);
}
((
uint64_t
*
)
data
)[
index
]
=
wrapped
;
return
js_mkundef
();
}
default
:
return
js_mkundef
();
}
}
static
ant_value_t
typedarray_index_getter
(
ant_t
*
js
,
ant_value_t
obj
,
const
char
*
key
,
size_t
key_len
)
{
if
(
key_len
==
0
||
key_len
>
10
)
return
js_mkundef
();
size_t
index
=
0
;
for
(
size_t
i
=
0
;
i
<
key_len
;
i
++
)
{
char
c
=
key
[
i
];
if
(
c
<
'0'
||
c
>
'9'
)
return
js_mkundef
();
index
=
index
*
10
+
(
c
-
'0'
);
}
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
obj
);
if
(
!
ta_data
||
index
>=
ta_data
->
length
)
return
js_mkundef
();
if
(
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
return
js_mkundef
();
ant_value_t
value
;
if
(
!
typedarray_read_value
(
js
,
ta_data
,
index
,
&
value
))
return
js_mkundef
();
return
value
;
}
static
bool
typedarray_index_setter
(
ant_t
*
js
,
ant_value_t
obj
,
const
char
*
key
,
size_t
key_len
,
ant_value_t
value
)
{
if
(
key_len
==
0
||
key_len
>
10
)
return
false
;
size_t
index
=
0
;
for
(
size_t
i
=
0
;
i
<
key_len
;
i
++
)
{
char
c
=
key
[
i
];
if
(
c
<
'0'
||
c
>
'9'
)
return
false
;
index
=
index
*
10
+
(
c
-
'0'
);
}
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
obj
);
if
(
!
ta_data
||
index
>=
ta_data
->
length
)
return
true
;
if
(
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
return
true
;
return
!
is_err
(
typedarray_write_value
(
js
,
ta_data
,
index
,
value
));
}
static
bool
typedarray_read_number
(
const
TypedArrayData
*
ta_data
,
size_t
index
,
double
*
out
)
{
if
(
!
ta_data
||
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
||
index
>=
ta_data
->
length
)
return
false
;
uint8_t
*
data
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
static
const
void
*
dispatch
[]
=
{
&&
R_INT8
,
&&
R_UINT8
,
&&
R_UINT8
,
&&
R_INT16
,
&&
R_UINT16
,
&&
R_INT32
,
&&
R_UINT32
,
&&
R_FLOAT16
,
&&
R_FLOAT32
,
&&
R_FLOAT64
,
&&
R_FAIL
,
&&
R_FAIL
};
if
(
ta_data
->
type
>
TYPED_ARRAY_BIGUINT64
)
goto
R_FAIL
;
goto
*
dispatch
[
ta_data
->
type
];
R_INT8
:
*
out
=
(
double
)((
int8_t
*
)
data
)[
index
];
return
true
;
R_UINT8
:
*
out
=
(
double
)
data
[
index
];
return
true
;
R_INT16
:
*
out
=
(
double
)((
int16_t
*
)
data
)[
index
];
return
true
;
R_UINT16
:
*
out
=
(
double
)((
uint16_t
*
)
data
)[
index
];
return
true
;
R_INT32
:
*
out
=
(
double
)((
int32_t
*
)
data
)[
index
];
return
true
;
R_UINT32
:
*
out
=
(
double
)((
uint32_t
*
)
data
)[
index
];
return
true
;
R_FLOAT16
:
*
out
=
half_to_double
(((
uint16_t
*
)
data
)[
index
]);
return
true
;
R_FLOAT32
:
*
out
=
(
double
)((
float
*
)
data
)[
index
];
return
true
;
R_FLOAT64
:
*
out
=
((
double
*
)
data
)[
index
];
return
true
;
R_FAIL
:
return
false
;
}
static
bool
typedarray_write_number
(
TypedArrayData
*
ta_data
,
size_t
index
,
double
value
)
{
if
(
!
ta_data
||
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
||
index
>=
ta_data
->
length
)
return
false
;
uint8_t
*
data
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
static
const
void
*
dispatch
[]
=
{
&&
W_INT8
,
&&
W_UINT8
,
&&
W_UINT8
,
&&
W_INT16
,
&&
W_UINT16
,
&&
W_INT32
,
&&
W_UINT32
,
&&
W_FLOAT16
,
&&
W_FLOAT32
,
&&
W_FLOAT64
,
&&
W_FAIL
,
&&
W_FAIL
};
if
(
ta_data
->
type
>
TYPED_ARRAY_BIGUINT64
)
goto
W_FAIL
;
goto
*
dispatch
[
ta_data
->
type
];
W_INT8
:
((
int8_t
*
)
data
)[
index
]
=
(
int8_t
)
value
;
return
true
;
W_UINT8
:
data
[
index
]
=
(
uint8_t
)
value
;
return
true
;
W_INT16
:
((
int16_t
*
)
data
)[
index
]
=
(
int16_t
)
value
;
return
true
;
W_UINT16
:
((
uint16_t
*
)
data
)[
index
]
=
(
uint16_t
)
value
;
return
true
;
W_INT32
:
((
int32_t
*
)
data
)[
index
]
=
(
int32_t
)
value
;
return
true
;
W_UINT32
:
((
uint32_t
*
)
data
)[
index
]
=
(
uint32_t
)
value
;
return
true
;
W_FLOAT16
:
((
uint16_t
*
)
data
)[
index
]
=
double_to_half
(
value
);
return
true
;
W_FLOAT32
:
((
float
*
)
data
)[
index
]
=
(
float
)
value
;
return
true
;
W_FLOAT64
:
((
double
*
)
data
)[
index
]
=
value
;
return
true
;
W_FAIL
:
return
false
;
}
static
ant_value_t
js_typedarray_every
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_callable
(
args
[
0
]))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"TypedArray.prototype.every requires a callable"
);
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
if
(
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
return
js_mkerr
(
js
,
"Cannot operate on a detached TypedArray"
);
ant_value_t
callback
=
args
[
0
];
ant_value_t
this_arg
=
nargs
>
1
?
args
[
1
]
:
js_mkundef
();
for
(
size_t
i
=
0
;
i
<
ta_data
->
length
;
i
++
)
{
ant_value_t
value
=
js_mkundef
();
if
(
!
typedarray_read_value
(
js
,
ta_data
,
i
,
&
value
))
return
js_false
;
ant_value_t
call_args
[
3
]
=
{
value
,
js_mknum
((
double
)
i
),
this_val
};
ant_value_t
result
=
sv_vm_call
(
js
->
vm
,
js
,
callback
,
this_arg
,
call_args
,
3
,
NULL
,
false
);
if
(
is_err
(
result
))
return
result
;
if
(
!
js_truthy
(
js
,
result
))
return
js_false
;
}
return
js_true
;
}
ant_value_t
create_arraybuffer_obj
(
ant_t
*
js
,
ArrayBufferData
*
buffer
)
{
ant_value_t
ab_obj
=
js_mkobj
(
js
);
ant_value_t
ab_proto
=
js_get_ctor_proto
(
js
,
"ArrayBuffer"
,
11
);
if
(
is_special_object
(
ab_proto
))
js_set_proto_init
(
ab_obj
,
ab_proto
);
js_set_native_ptr
(
ab_obj
,
buffer
);
js_set_native_tag
(
ab_obj
,
BUFFER_ARRAYBUFFER_NATIVE_TAG
);
js_set
(
js
,
ab_obj
,
"byteLength"
,
js_mknum
((
double
)
buffer
->
length
));
js_set_finalizer
(
ab_obj
,
arraybuffer_finalize
);
buffer
->
ref_count
++
;
return
ab_obj
;
}
ant_value_t
create_typed_array_with_buffer
(
ant_t
*
js
,
TypedArrayType
type
,
ArrayBufferData
*
buffer
,
size_t
byte_offset
,
size_t
length
,
const
char
*
type_name
,
ant_value_t
arraybuffer_obj
)
{
TypedArrayData
*
ta_data
=
ta_meta_alloc
(
sizeof
(
TypedArrayData
));
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Failed to allocate TypedArray"
);
size_t
element_size
=
get_element_size
(
type
);
ta_data
->
buffer
=
buffer
;
ta_data
->
type
=
type
;
ta_data
->
byte_offset
=
byte_offset
;
ta_data
->
byte_length
=
length
*
element_size
;
ta_data
->
length
=
length
;
buffer
->
ref_count
++
;
ant_value_t
obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_get_ctor_proto
(
js
,
type_name
,
strlen
(
type_name
));
if
(
is_special_object
(
proto
))
js_set_proto_init
(
obj
,
proto
);
js_set_native_ptr
(
obj
,
ta_data
);
js_set_native_tag
(
obj
,
BUFFER_TYPEDARRAY_NATIVE_TAG
);
js_set
(
js
,
obj
,
"length"
,
js_mknum
((
double
)
length
));
js_set
(
js
,
obj
,
"byteLength"
,
js_mknum
((
double
)(
length
*
element_size
)));
js_set
(
js
,
obj
,
"byteOffset"
,
js_mknum
((
double
)
byte_offset
));
js_set
(
js
,
obj
,
"BYTES_PER_ELEMENT"
,
js_mknum
((
double
)
element_size
));
js_set
(
js
,
obj
,
"buffer"
,
arraybuffer_obj
);
js_set_getter
(
obj
,
typedarray_index_getter
);
js_set_setter
(
obj
,
typedarray_index_setter
);
js_set_finalizer
(
obj
,
typedarray_finalize
);
return
obj
;
}
ant_value_t
create_typed_array
(
ant_t
*
js
,
TypedArrayType
type
,
ArrayBufferData
*
buffer
,
size_t
byte_offset
,
size_t
length
,
const
char
*
type_name
)
{
ant_value_t
ab_obj
=
create_arraybuffer_obj
(
js
,
buffer
);
ant_value_t
result
=
create_typed_array_with_buffer
(
js
,
type
,
buffer
,
byte_offset
,
length
,
type_name
,
ab_obj
);
free_array_buffer_data
(
buffer
);
return
result
;
}
ant_value_t
create_dataview_with_buffer
(
ant_t
*
js
,
ArrayBufferData
*
buffer
,
size_t
byte_offset
,
size_t
byte_length
,
ant_value_t
arraybuffer_obj
)
{
DataViewData
*
dv_data
=
ta_meta_alloc
(
sizeof
(
DataViewData
));
if
(
!
dv_data
)
return
js_mkerr
(
js
,
"Failed to allocate DataView"
);
dv_data
->
buffer
=
buffer
;
dv_data
->
byte_offset
=
byte_offset
;
dv_data
->
byte_length
=
byte_length
;
buffer
->
ref_count
++
;
ant_value_t
obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_get_ctor_proto
(
js
,
"DataView"
,
8
);
if
(
is_special_object
(
proto
))
js_set_proto_init
(
obj
,
proto
);
js_set_native_ptr
(
obj
,
dv_data
);
js_set_native_tag
(
obj
,
BUFFER_DATAVIEW_NATIVE_TAG
);
js_set_slot
(
obj
,
SLOT_BRAND
,
js_mknum
(
BRAND_DATAVIEW
));
js_mkprop_fast
(
js
,
obj
,
"buffer"
,
6
,
arraybuffer_obj
);
js_set_descriptor
(
js
,
obj
,
"buffer"
,
6
,
0
);
js_set
(
js
,
obj
,
"byteLength"
,
js_mknum
((
double
)
byte_length
));
js_set
(
js
,
obj
,
"byteOffset"
,
js_mknum
((
double
)
byte_offset
));
js_set_finalizer
(
obj
,
dataview_finalize
);
return
obj
;
}
typedef
struct
{
ant_value_t
*
values
;
size_t
length
;
size_t
capacity
;
}
iter_collect_ctx_t
;
static
bool
iter_collect_callback
(
ant_t
*
js
,
ant_value_t
value
,
void
*
udata
)
{
iter_collect_ctx_t
*
ctx
=
(
iter_collect_ctx_t
*
)
udata
;
if
(
ctx
->
length
>=
ctx
->
capacity
)
{
ctx
->
capacity
*=
2
;
ant_value_t
*
new_values
=
realloc
(
ctx
->
values
,
ctx
->
capacity
*
sizeof
(
ant_value_t
));
if
(
!
new_values
)
return
false
;
ctx
->
values
=
new_values
;
}
ctx
->
values
[
ctx
->
length
++
]
=
value
;
return
true
;
}
static
ant_value_t
js_typedarray_constructor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
TypedArrayType
type
,
const
char
*
type_name
)
{
if
(
nargs
==
0
)
{
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
0
);
return
create_typed_array
(
js
,
type
,
buffer
,
0
,
0
,
type_name
);
}
if
(
vtype
(
args
[
0
])
==
T_NUM
)
{
size_t
length
=
(
size_t
)
js_getnum
(
args
[
0
]);
size_t
element_size
=
get_element_size
(
type
);
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
length
*
element_size
);
if
(
!
buffer
)
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
return
create_typed_array
(
js
,
type
,
buffer
,
0
,
length
,
type_name
);
}
ArrayBufferData
*
arraybuffer
=
buffer_get_arraybuffer_data
(
args
[
0
]);
if
(
arraybuffer
)
{
ArrayBufferData
*
buffer
=
arraybuffer
;
size_t
byte_offset
=
0
;
size_t
length
=
buffer
->
length
;
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
{
byte_offset
=
(
size_t
)
js_getnum
(
args
[
1
]);
}
size_t
element_size
=
get_element_size
(
type
);
if
(
byte_offset
>
buffer
->
length
)
{
return
js_mkerr
(
js
,
"Start offset is outside the bounds of the buffer"
);
}
if
(
nargs
>
2
&&
vtype
(
args
[
2
])
==
T_NUM
)
{
length
=
(
size_t
)
js_getnum
(
args
[
2
]);
size_t
available
=
buffer
->
length
-
byte_offset
;
if
(
length
>
available
/
element_size
)
{
return
js_mkerr
(
js
,
"Invalid TypedArray length"
);
}
}
else
length
=
(
buffer
->
length
-
byte_offset
)
/
element_size
;
return
create_typed_array_with_buffer
(
js
,
type
,
buffer
,
byte_offset
,
length
,
type_name
,
args
[
0
]);
}
if
(
is_special_object
(
args
[
0
]))
{
ant_value_t
len_val
=
js_get
(
js
,
args
[
0
],
"length"
);
size_t
length
=
0
;
ant_value_t
*
values
=
NULL
;
bool
is_iterable
=
false
;
if
(
vtype
(
len_val
)
==
T_NUM
)
length
=
(
size_t
)
js_getnum
(
len_val
);
else
{
iter_collect_ctx_t
ctx
=
{
.
values
=
NULL
,
.
length
=
0
,
.
capacity
=
16
};
ctx
.
values
=
malloc
(
ctx
.
capacity
*
sizeof
(
ant_value_t
));
if
(
!
ctx
.
values
)
return
js_mkerr
(
js
,
"Failed to allocate memory"
);
is_iterable
=
js_iter
(
js
,
args
[
0
],
iter_collect_callback
,
&
ctx
);
if
(
is_iterable
)
{
values
=
ctx
.
values
;
length
=
ctx
.
length
;
}
else
free
(
ctx
.
values
);
}
if
(
length
>
0
||
is_iterable
||
vtype
(
len_val
)
==
T_NUM
)
{
size_t
element_size
=
get_element_size
(
type
);
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
length
*
element_size
);
if
(
!
buffer
)
{
if
(
values
)
free
(
values
);
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
}
ant_value_t
result
=
create_typed_array
(
js
,
type
,
buffer
,
0
,
length
,
type_name
);
if
(
is_err
(
result
))
{
if
(
values
)
free
(
values
);
return
result
;
}
TypedArrayData
*
result_ta
=
buffer_get_typedarray_data
(
result
);
for
(
size_t
i
=
0
;
i
<
length
;
i
++
)
{
ant_value_t
elem
;
if
(
values
)
elem
=
values
[
i
];
else
{
char
idx_str
[
16
];
snprintf
(
idx_str
,
sizeof
(
idx_str
),
"%zu"
,
i
);
elem
=
js_get
(
js
,
args
[
0
],
idx_str
);
}
ant_value_t
write_result
=
typedarray_write_value
(
js
,
result_ta
,
i
,
elem
);
if
(
is_err
(
write_result
))
{
if
(
values
)
free
(
values
);
return
write_result
;
}
}
if
(
values
)
free
(
values
);
return
result
;
}
}
return
js_mkerr
(
js
,
"Invalid TypedArray constructor arguments"
);
}
// TypedArray.prototype.slice(begin, end)
// TypedArray.prototype.at(index)
static
ant_value_t
js_typedarray_at
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
if
(
nargs
==
0
||
vtype
(
args
[
0
])
!=
T_NUM
)
return
js_mkundef
();
ssize_t
len
=
(
ssize_t
)
ta_data
->
length
;
ssize_t
idx
=
(
ssize_t
)
js_getnum
(
args
[
0
]);
if
(
idx
<
0
)
idx
+=
len
;
if
(
idx
<
0
||
idx
>=
len
)
return
js_mkundef
();
if
(
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
return
js_mkundef
();
ant_value_t
value
;
if
(
!
typedarray_read_value
(
js
,
ta_data
,
(
size_t
)
idx
,
&
value
))
return
js_mkundef
();
return
value
;
}
static
ant_value_t
js_typedarray_slice
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
ssize_t
len
=
(
ssize_t
)
ta_data
->
length
;
ssize_t
begin
=
0
,
end
=
len
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
begin
=
(
ssize_t
)
js_getnum
(
args
[
0
]);
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
end
=
(
ssize_t
)
js_getnum
(
args
[
1
]);
begin
=
normalize_index
(
begin
,
len
);
end
=
normalize_index
(
end
,
len
);
if
(
end
<
begin
)
end
=
begin
;
size_t
new_length
=
(
size_t
)(
end
-
begin
);
size_t
element_size
=
get_element_size
(
ta_data
->
type
);
ArrayBufferData
*
new_buffer
=
create_array_buffer_data
(
new_length
*
element_size
);
if
(
!
new_buffer
)
return
js_mkerr
(
js
,
"Failed to allocate new buffer"
);
memcpy
(
new_buffer
->
data
,
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
+
(
size_t
)
begin
*
element_size
,
new_length
*
element_size
);
ant_value_t
out
=
create_typed_array_like
(
js
,
this_val
,
ta_data
->
type
,
new_buffer
,
0
,
new_length
);
free_array_buffer_data
(
new_buffer
);
return
out
;
}
// TypedArray.prototype.subarray(begin, end)
static
ant_value_t
js_typedarray_subarray
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
ssize_t
len
=
(
ssize_t
)
ta_data
->
length
;
ssize_t
begin
=
0
,
end
=
len
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
begin
=
(
ssize_t
)
js_getnum
(
args
[
0
]);
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
end
=
(
ssize_t
)
js_getnum
(
args
[
1
]);
begin
=
normalize_index
(
begin
,
len
);
end
=
normalize_index
(
end
,
len
);
if
(
end
<
begin
)
end
=
begin
;
size_t
new_length
=
(
size_t
)(
end
-
begin
);
size_t
element_size
=
get_element_size
(
ta_data
->
type
);
size_t
new_offset
=
ta_data
->
byte_offset
+
(
size_t
)
begin
*
element_size
;
return
create_typed_array_like
(
js
,
this_val
,
ta_data
->
type
,
ta_data
->
buffer
,
new_offset
,
new_length
);
}
// TypedArray.prototype.fill(value, start, end)
static
ant_value_t
js_typedarray_fill
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
ant_value_t
value
=
nargs
>
0
?
args
[
0
]
:
js_mknum
(
0
);
ssize_t
len
=
(
ssize_t
)
ta_data
->
length
;
ssize_t
start
=
0
,
end
=
len
;
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
start
=
(
ssize_t
)
js_getnum
(
args
[
1
]);
if
(
nargs
>
2
&&
vtype
(
args
[
2
])
==
T_NUM
)
end
=
(
ssize_t
)
js_getnum
(
args
[
2
]);
start
=
normalize_index
(
start
,
len
);
end
=
normalize_index
(
end
,
len
);
if
(
end
<
start
)
end
=
start
;
if
(
ta_data
->
type
==
TYPED_ARRAY_BIGINT64
||
ta_data
->
type
==
TYPED_ARRAY_BIGUINT64
)
{
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
{
ant_value_t
write_result
=
typedarray_write_value
(
js
,
ta_data
,
(
size_t
)
i
,
value
);
if
(
is_err
(
write_result
))
return
write_result
;
}
return
this_val
;
}
uint8_t
*
data
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
static
const
void
*
dispatch
[]
=
{
&&
L_INT8
,
&&
L_UINT8
,
&&
L_UINT8
,
&&
L_INT16
,
&&
L_UINT16
,
&&
L_INT32
,
&&
L_UINT32
,
&&
L_FLOAT16
,
&&
L_FLOAT32
,
&&
L_FLOAT64
,
&&
L_DONE
,
&&
L_DONE
};
if
(
ta_data
->
type
>
TYPED_ARRAY_BIGUINT64
)
goto
L_DONE
;
goto
*
dispatch
[
ta_data
->
type
];
L_INT8
:
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
((
int8_t
*
)
data
)[
i
]
=
(
int8_t
)
js_to_number
(
js
,
value
);
goto
L_DONE
;
L_UINT8
:
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
data
[
i
]
=
(
uint8_t
)
js_to_number
(
js
,
value
);
goto
L_DONE
;
L_INT16
:
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
((
int16_t
*
)
data
)[
i
]
=
(
int16_t
)
js_to_number
(
js
,
value
);
goto
L_DONE
;
L_UINT16
:
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
((
uint16_t
*
)
data
)[
i
]
=
(
uint16_t
)
js_to_number
(
js
,
value
);
goto
L_DONE
;
L_INT32
:
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
((
int32_t
*
)
data
)[
i
]
=
(
int32_t
)
js_to_number
(
js
,
value
);
goto
L_DONE
;
L_UINT32
:
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
((
uint32_t
*
)
data
)[
i
]
=
(
uint32_t
)
js_to_number
(
js
,
value
);
goto
L_DONE
;
L_FLOAT16
:
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
((
uint16_t
*
)
data
)[
i
]
=
double_to_half
(
js_to_number
(
js
,
value
));
goto
L_DONE
;
L_FLOAT32
:
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
((
float
*
)
data
)[
i
]
=
(
float
)
js_to_number
(
js
,
value
);
goto
L_DONE
;
L_FLOAT64
:
for
(
ssize_t
i
=
start
;
i
<
end
;
i
++
)
((
double
*
)
data
)[
i
]
=
js_to_number
(
js
,
value
);
goto
L_DONE
;
L_DONE
:
return
this_val
;
}
// TypedArray.prototype.set(source, offset = 0)
static
ant_value_t
js_typedarray_set
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"set requires source argument"
);
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
dst
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
dst
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
if
(
!
dst
->
buffer
||
dst
->
buffer
->
is_detached
)
return
js_mkerr
(
js
,
"Cannot operate on a detached TypedArray"
);
ssize_t
offset_i
=
0
;
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
offset_i
=
(
ssize_t
)
js_getnum
(
args
[
1
]);
if
(
offset_i
<
0
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
size_t
offset
=
(
size_t
)
offset_i
;
if
(
offset
>
dst
->
length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
ant_value_t
src_val
=
args
[
0
];
TypedArrayData
*
src_ta
=
buffer_get_typedarray_data
(
src_val
);
if
(
src_ta
&&
src_ta
->
buffer
&&
!
src_ta
->
buffer
->
is_detached
)
{
size_t
src_len
=
src_ta
->
length
;
if
(
offset
+
src_len
>
dst
->
length
)
return
js_mkerr
(
js
,
"Source is too large"
);
if
(
src_ta
->
type
==
dst
->
type
)
{
size_t
el
=
get_element_size
(
dst
->
type
);
uint8_t
*
dst_data
=
dst
->
buffer
->
data
+
dst
->
byte_offset
+
offset
*
el
;
uint8_t
*
src_data
=
src_ta
->
buffer
->
data
+
src_ta
->
byte_offset
;
memmove
(
dst_data
,
src_data
,
src_len
*
el
);
return
js_mkundef
();
}
for
(
size_t
i
=
0
;
i
<
src_len
;
i
++
)
{
ant_value_t
value
=
js_mkundef
();
if
(
!
typedarray_read_value
(
js
,
src_ta
,
i
,
&
value
))
value
=
js_mknum
(
0
);
ant_value_t
write_result
=
typedarray_write_value
(
js
,
dst
,
offset
+
i
,
value
);
if
(
is_err
(
write_result
))
return
write_result
;
}
return
js_mkundef
();
}
if
(
!
is_special_object
(
src_val
)
&&
vtype
(
src_val
)
!=
T_STR
)
{
return
js_mkerr
(
js
,
"set source must be array-like or TypedArray"
);
}
size_t
src_len
=
0
;
if
(
vtype
(
src_val
)
==
T_STR
)
{
src_len
=
(
size_t
)
vstrlen
(
js
,
src_val
);
}
else
{
ant_value_t
len_val
=
js_get
(
js
,
src_val
,
"length"
);
src_len
=
vtype
(
len_val
)
==
T_NUM
?
(
size_t
)
js_getnum
(
len_val
)
:
0
;
}
if
(
offset
+
src_len
>
dst
->
length
)
return
js_mkerr
(
js
,
"Source is too large"
);
for
(
size_t
i
=
0
;
i
<
src_len
;
i
++
)
{
if
(
vtype
(
src_val
)
==
T_STR
)
{
ant_offset_t
slen
=
0
;
ant_offset_t
soff
=
vstr
(
js
,
src_val
,
&
slen
);
const
unsigned
char
*
sptr
=
(
const
unsigned
char
*
)(
uintptr_t
)
soff
;
double
value
=
0
;
if
(
i
<
(
size_t
)
slen
)
value
=
sptr
[
i
];
ant_value_t
write_result
=
typedarray_write_value
(
js
,
dst
,
offset
+
i
,
js_mknum
(
value
));
if
(
is_err
(
write_result
))
return
write_result
;
}
else
{
char
idx
[
24
];
size_t
idx_len
=
uint_to_str
(
idx
,
sizeof
(
idx
),
(
uint64_t
)
i
);
idx
[
idx_len
]
=
'\0'
;
ant_value_t
elem
=
js_get
(
js
,
src_val
,
idx
);
ant_value_t
write_result
=
typedarray_write_value
(
js
,
dst
,
offset
+
i
,
elem
);
if
(
is_err
(
write_result
))
return
write_result
;
}
}
return
js_mkundef
();
}
// TypedArray.prototype.copyWithin(target, start, end)
static
ant_value_t
js_typedarray_copyWithin
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
if
(
!
ta
->
buffer
||
ta
->
buffer
->
is_detached
)
return
js_mkerr
(
js
,
"Cannot operate on a detached TypedArray"
);
ssize_t
len
=
(
ssize_t
)
ta
->
length
;
if
(
len
<=
0
)
return
this_val
;
ssize_t
target
=
0
,
start
=
0
,
end
=
len
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
target
=
(
ssize_t
)
js_getnum
(
args
[
0
]);
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
start
=
(
ssize_t
)
js_getnum
(
args
[
1
]);
if
(
nargs
>
2
&&
vtype
(
args
[
2
])
==
T_NUM
)
end
=
(
ssize_t
)
js_getnum
(
args
[
2
]);
target
=
normalize_index
(
target
,
len
);
start
=
normalize_index
(
start
,
len
);
end
=
normalize_index
(
end
,
len
);
if
(
end
<
start
)
end
=
start
;
if
(
target
>=
len
||
start
>=
len
||
end
<=
start
)
return
this_val
;
size_t
count
=
(
size_t
)(
end
-
start
);
size_t
max_to_end
=
(
size_t
)(
len
-
target
);
if
(
count
>
max_to_end
)
count
=
max_to_end
;
if
(
count
==
0
)
return
this_val
;
size_t
el
=
get_element_size
(
ta
->
type
);
uint8_t
*
base
=
ta
->
buffer
->
data
+
ta
->
byte_offset
;
memmove
(
base
+
(
size_t
)
target
*
el
,
base
+
(
size_t
)
start
*
el
,
count
*
el
);
return
this_val
;
}
// TypedArray.prototype.toReversed()
static
ant_value_t
js_typedarray_toReversed
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
size_t
length
=
ta_data
->
length
;
size_t
element_size
=
get_element_size
(
ta_data
->
type
);
ArrayBufferData
*
new_buffer
=
create_array_buffer_data
(
length
*
element_size
);
if
(
!
new_buffer
)
return
js_mkerr
(
js
,
"Failed to allocate new buffer"
);
uint8_t
*
src
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
uint8_t
*
dst
=
new_buffer
->
data
;
for
(
size_t
i
=
0
;
i
<
length
;
i
++
)
{
memcpy
(
dst
+
i
*
element_size
,
src
+
(
length
-
1
-
i
)
*
element_size
,
element_size
);
}
ant_value_t
out
=
create_typed_array_like
(
js
,
this_val
,
ta_data
->
type
,
new_buffer
,
0
,
length
);
free_array_buffer_data
(
new_buffer
);
return
out
;
}
// TypedArray.prototype.toSorted(comparefn)
static
ant_value_t
js_typedarray_toSorted
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
size_t
length
=
ta_data
->
length
;
size_t
element_size
=
get_element_size
(
ta_data
->
type
);
ArrayBufferData
*
new_buffer
=
create_array_buffer_data
(
length
*
element_size
);
if
(
!
new_buffer
)
return
js_mkerr
(
js
,
"Failed to allocate new buffer"
);
memcpy
(
new_buffer
->
data
,
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
,
length
*
element_size
);
ant_value_t
result
=
create_typed_array_like
(
js
,
this_val
,
ta_data
->
type
,
new_buffer
,
0
,
length
);
free_array_buffer_data
(
new_buffer
);
if
(
is_err
(
result
))
return
result
;
TypedArrayData
*
result_ta
=
buffer_get_typedarray_data
(
result
);
uint8_t
*
data
=
result_ta
->
buffer
->
data
;
ant_value_t
comparefn
=
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_FUNC
)
?
args
[
0
]
:
js_mkundef
();
bool
has_comparefn
=
vtype
(
comparefn
)
==
T_FUNC
;
for
(
size_t
i
=
1
;
i
<
length
;
i
++
)
{
for
(
size_t
j
=
i
;
j
>
0
;
j
--
)
{
double
a_val
,
b_val
;
int
cmp
;
static
const
void
*
read_dispatch
[]
=
{
&&
R_INT8
,
&&
R_UINT8
,
&&
R_UINT8
,
&&
R_INT16
,
&&
R_UINT16
,
&&
R_INT32
,
&&
R_UINT32
,
&&
R_FLOAT16
,
&&
R_FLOAT32
,
&&
R_FLOAT64
,
&&
R_DONE
,
&&
R_DONE
};
if
(
ta_data
->
type
>
TYPED_ARRAY_BIGUINT64
)
goto
R_DONE
;
goto
*
read_dispatch
[
ta_data
->
type
];
R_INT8
:
a_val
=
(
double
)((
int8_t
*
)
data
)[
j
-1
];
b_val
=
(
double
)((
int8_t
*
)
data
)[
j
];
goto
R_COMPARE
;
R_UINT8
:
a_val
=
(
double
)
data
[
j
-1
];
b_val
=
(
double
)
data
[
j
];
goto
R_COMPARE
;
R_INT16
:
a_val
=
(
double
)((
int16_t
*
)
data
)[
j
-1
];
b_val
=
(
double
)((
int16_t
*
)
data
)[
j
];
goto
R_COMPARE
;
R_UINT16
:
a_val
=
(
double
)((
uint16_t
*
)
data
)[
j
-1
];
b_val
=
(
double
)((
uint16_t
*
)
data
)[
j
];
goto
R_COMPARE
;
R_INT32
:
a_val
=
(
double
)((
int32_t
*
)
data
)[
j
-1
];
b_val
=
(
double
)((
int32_t
*
)
data
)[
j
];
goto
R_COMPARE
;
R_UINT32
:
a_val
=
(
double
)((
uint32_t
*
)
data
)[
j
-1
];
b_val
=
(
double
)((
uint32_t
*
)
data
)[
j
];
goto
R_COMPARE
;
R_FLOAT16
:
a_val
=
half_to_double
(((
uint16_t
*
)
data
)[
j
-1
]);
b_val
=
half_to_double
(((
uint16_t
*
)
data
)[
j
]);
goto
R_COMPARE
;
R_FLOAT32
:
a_val
=
(
double
)((
float
*
)
data
)[
j
-1
];
b_val
=
(
double
)((
float
*
)
data
)[
j
];
goto
R_COMPARE
;
R_FLOAT64
:
a_val
=
((
double
*
)
data
)[
j
-1
];
b_val
=
((
double
*
)
data
)[
j
];
goto
R_COMPARE
;
R_DONE
:
goto
SORT_DONE
;
R_COMPARE
:
if
(
has_comparefn
)
{
ant_value_t
cmp_args
[
2
]
=
{
js_mknum
(
a_val
),
js_mknum
(
b_val
)
};
ant_value_t
cmp_result
=
sv_vm_call
(
js
->
vm
,
js
,
comparefn
,
js_mkundef
(),
cmp_args
,
2
,
NULL
,
false
);
cmp
=
(
int
)
js_getnum
(
cmp_result
);
}
else
{
cmp
=
(
a_val
>
b_val
)
?
1
:
((
a_val
<
b_val
)
?
-1
:
0
);
}
if
(
cmp
<=
0
)
break
;
static
const
void
*
swap_dispatch
[]
=
{
&&
S_INT8
,
&&
S_UINT8
,
&&
S_UINT8
,
&&
S_INT16
,
&&
S_UINT16
,
&&
S_INT32
,
&&
S_UINT32
,
&&
S_FLOAT16
,
&&
S_FLOAT32
,
&&
S_FLOAT64
,
&&
S_DONE
,
&&
S_DONE
};
if
(
ta_data
->
type
>
TYPED_ARRAY_BIGUINT64
)
goto
S_DONE
;
goto
*
swap_dispatch
[
ta_data
->
type
];
S_INT8
:
{
int8_t
tmp
=
((
int8_t
*
)
data
)[
j
-1
];
((
int8_t
*
)
data
)[
j
-1
]
=
((
int8_t
*
)
data
)[
j
];
((
int8_t
*
)
data
)[
j
]
=
tmp
;
goto
S_DONE
;
}
S_UINT8
:
{
uint8_t
tmp
=
data
[
j
-1
];
data
[
j
-1
]
=
data
[
j
];
data
[
j
]
=
tmp
;
goto
S_DONE
;
}
S_INT16
:
{
int16_t
tmp
=
((
int16_t
*
)
data
)[
j
-1
];
((
int16_t
*
)
data
)[
j
-1
]
=
((
int16_t
*
)
data
)[
j
];
((
int16_t
*
)
data
)[
j
]
=
tmp
;
goto
S_DONE
;
}
S_UINT16
:
{
uint16_t
tmp
=
((
uint16_t
*
)
data
)[
j
-1
];
((
uint16_t
*
)
data
)[
j
-1
]
=
((
uint16_t
*
)
data
)[
j
];
((
uint16_t
*
)
data
)[
j
]
=
tmp
;
goto
S_DONE
;
}
S_INT32
:
{
int32_t
tmp
=
((
int32_t
*
)
data
)[
j
-1
];
((
int32_t
*
)
data
)[
j
-1
]
=
((
int32_t
*
)
data
)[
j
];
((
int32_t
*
)
data
)[
j
]
=
tmp
;
goto
S_DONE
;
}
S_UINT32
:
{
uint32_t
tmp
=
((
uint32_t
*
)
data
)[
j
-1
];
((
uint32_t
*
)
data
)[
j
-1
]
=
((
uint32_t
*
)
data
)[
j
];
((
uint32_t
*
)
data
)[
j
]
=
tmp
;
goto
S_DONE
;
}
S_FLOAT16
:
{
uint16_t
tmp
=
((
uint16_t
*
)
data
)[
j
-1
];
((
uint16_t
*
)
data
)[
j
-1
]
=
((
uint16_t
*
)
data
)[
j
];
((
uint16_t
*
)
data
)[
j
]
=
tmp
;
goto
S_DONE
;
}
S_FLOAT32
:
{
float
tmp
=
((
float
*
)
data
)[
j
-1
];
((
float
*
)
data
)[
j
-1
]
=
((
float
*
)
data
)[
j
];
((
float
*
)
data
)[
j
]
=
tmp
;
goto
S_DONE
;
}
S_FLOAT64
:
{
double
tmp
=
((
double
*
)
data
)[
j
-1
];
((
double
*
)
data
)[
j
-1
]
=
((
double
*
)
data
)[
j
];
((
double
*
)
data
)[
j
]
=
tmp
;
goto
S_DONE
;
}
S_DONE
:;
}
}
SORT_DONE
:
return
result
;
}
// TypedArray.prototype.with(index, value)
static
ant_value_t
js_typedarray_with
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"with requires index and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
ssize_t
index
=
(
ssize_t
)
js_getnum
(
args
[
0
]);
size_t
length
=
ta_data
->
length
;
if
(
index
<
0
)
index
=
(
ssize_t
)
length
+
index
;
if
(
index
<
0
||
(
size_t
)
index
>=
length
)
{
return
js_mkerr
(
js
,
"Index out of bounds"
);
}
size_t
element_size
=
get_element_size
(
ta_data
->
type
);
ArrayBufferData
*
new_buffer
=
create_array_buffer_data
(
length
*
element_size
);
if
(
!
new_buffer
)
return
js_mkerr
(
js
,
"Failed to allocate new buffer"
);
memcpy
(
new_buffer
->
data
,
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
,
length
*
element_size
);
ant_value_t
out
=
create_typed_array_like
(
js
,
this_val
,
ta_data
->
type
,
new_buffer
,
0
,
length
);
free_array_buffer_data
(
new_buffer
);
if
(
is_err
(
out
))
return
out
;
TypedArrayData
*
out_ta
=
buffer_get_typedarray_data
(
out
);
ant_value_t
write_result
=
typedarray_write_value
(
js
,
out_ta
,
(
size_t
)
index
,
args
[
1
]);
if
(
is_err
(
write_result
))
return
write_result
;
return
out
;
}
#define DEFINE_TYPEDARRAY_CONSTRUCTOR(name, type) \
static ant_value_t js_##name##_constructor(ant_t *js, ant_value_t *args, int nargs) { \
if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, #name " constructor requires 'new'"); \
return js_typedarray_constructor(js, args, nargs, type, #name); \
}
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Int8Array
,
TYPED_ARRAY_INT8
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Uint8Array
,
TYPED_ARRAY_UINT8
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Uint8ClampedArray
,
TYPED_ARRAY_UINT8_CLAMPED
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Int16Array
,
TYPED_ARRAY_INT16
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Uint16Array
,
TYPED_ARRAY_UINT16
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Int32Array
,
TYPED_ARRAY_INT32
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Uint32Array
,
TYPED_ARRAY_UINT32
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Float16Array
,
TYPED_ARRAY_FLOAT16
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Float32Array
,
TYPED_ARRAY_FLOAT32
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
Float64Array
,
TYPED_ARRAY_FLOAT64
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
BigInt64Array
,
TYPED_ARRAY_BIGINT64
)
DEFINE_TYPEDARRAY_CONSTRUCTOR
(
BigUint64Array
,
TYPED_ARRAY_BIGUINT64
)
static
ant_value_t
js_typedarray_from
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
TypedArrayType
type
,
const
char
*
type_name
)
{
if
(
nargs
<
1
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"%s.from requires at least 1 argument"
,
type_name
);
ant_value_t
source
=
args
[
0
];
bool
has_map
=
nargs
>=
2
&&
vtype
(
args
[
1
])
!=
T_UNDEF
;
ant_value_t
map_fn
=
js_mkundef
();
ant_value_t
this_arg
=
nargs
>=
3
?
args
[
2
]
:
js_mkundef
();
ant_value_t
result
=
js_mkundef
();
ant_value_t
*
collected
=
NULL
;
gc_temp_root_scope_t
temp_roots
=
{
0
};
bool
temp_roots_active
=
false
;
if
(
has_map
)
{
if
(
!
is_callable
(
args
[
1
]))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"%s.from: mapFn is not a function"
,
type_name
);
map_fn
=
args
[
1
];
}
gc_temp_root_scope_begin
(
js
,
&
temp_roots
);
temp_roots_active
=
true
;
if
(
!
gc_temp_root_handle_valid
(
gc_temp_root_add
(
&
temp_roots
,
source
)))
goto
oom
;
if
(
!
gc_temp_root_handle_valid
(
gc_temp_root_add
(
&
temp_roots
,
map_fn
)))
goto
oom
;
if
(
!
gc_temp_root_handle_valid
(
gc_temp_root_add
(
&
temp_roots
,
this_arg
)))
goto
oom
;
size_t
count
=
0
,
cap
=
16
;
collected
=
malloc
(
cap
*
sizeof
(
ant_value_t
));
if
(
!
collected
)
goto
oom
;
js_iter_t
it
;
if
(
js_iter_open
(
js
,
source
,
&
it
))
{
ant_value_t
item
;
while
(
js_iter_next
(
js
,
&
it
,
&
item
))
{
if
(
count
>=
cap
)
{
cap
*=
2
;
ant_value_t
*
tmp
=
realloc
(
collected
,
cap
*
sizeof
(
ant_value_t
));
if
(
!
tmp
)
goto
oom
;
collected
=
tmp
;
}
if
(
has_map
)
{
ant_value_t
map_args
[
2
]
=
{
item
,
js_mknum
((
double
)
count
)
};
item
=
sv_vm_call
(
js
->
vm
,
js
,
map_fn
,
this_arg
,
map_args
,
2
,
NULL
,
false
);
if
(
is_err
(
item
))
{
result
=
item
;
goto
done
;
}
}
collected
[
count
++
]
=
item
;
if
(
!
gc_temp_root_handle_valid
(
gc_temp_root_add
(
&
temp_roots
,
item
)))
goto
oom
;
}
js_iter_close
(
js
,
&
it
);
}
else
{
ant_value_t
len_val
=
js_get
(
js
,
source
,
"length"
);
size_t
len
=
vtype
(
len_val
)
==
T_NUM
?
(
size_t
)
js_getnum
(
len_val
)
:
0
;
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
char
idx
[
16
];
snprintf
(
idx
,
sizeof
(
idx
),
"%zu"
,
i
);
ant_value_t
item
=
js_get
(
js
,
source
,
idx
);
if
(
count
>=
cap
)
{
cap
*=
2
;
ant_value_t
*
tmp
=
realloc
(
collected
,
cap
*
sizeof
(
ant_value_t
));
if
(
!
tmp
)
goto
oom
;
collected
=
tmp
;
}
if
(
has_map
)
{
ant_value_t
map_args
[
2
]
=
{
item
,
js_mknum
((
double
)
i
)
};
item
=
sv_vm_call
(
js
->
vm
,
js
,
map_fn
,
this_arg
,
map_args
,
2
,
NULL
,
false
);
if
(
is_err
(
item
))
{
result
=
item
;
goto
done
;
}
}
collected
[
count
++
]
=
item
;
if
(
!
gc_temp_root_handle_valid
(
gc_temp_root_add
(
&
temp_roots
,
item
)))
goto
oom
;
}
}
size_t
elem_size
=
get_element_size
(
type
);
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
count
*
elem_size
);
if
(
!
buffer
)
goto
oom
;
result
=
create_typed_array
(
js
,
type
,
buffer
,
0
,
count
,
type_name
);
if
(
is_err
(
result
))
goto
done
;
if
(
!
gc_temp_root_handle_valid
(
gc_temp_root_add
(
&
temp_roots
,
result
)))
goto
oom
;
TypedArrayData
*
result_ta
=
buffer_get_typedarray_data
(
result
);
for
(
size_t
i
=
0
;
i
<
count
;
i
++
)
{
ant_value_t
write_result
=
typedarray_write_value
(
js
,
result_ta
,
i
,
collected
[
i
]);
if
(
is_err
(
write_result
))
{
result
=
write_result
;
goto
done
;
}
}
done
:
if
(
temp_roots_active
)
gc_temp_root_scope_end
(
&
temp_roots
);
free
(
collected
);
return
result
;
oom
:
result
=
js_mkerr
(
js
,
"oom"
);
goto
done
;
}
#define DEFINE_TYPEDARRAY_FROM(name, type) \
static ant_value_t js_##name##_from(ant_t *js, ant_value_t *args, int nargs) { \
return js_typedarray_from(js, args, nargs, type, #name); \
}
DEFINE_TYPEDARRAY_FROM
(
Int8Array
,
TYPED_ARRAY_INT8
)
DEFINE_TYPEDARRAY_FROM
(
Uint8Array
,
TYPED_ARRAY_UINT8
)
DEFINE_TYPEDARRAY_FROM
(
Uint8ClampedArray
,
TYPED_ARRAY_UINT8_CLAMPED
)
DEFINE_TYPEDARRAY_FROM
(
Int16Array
,
TYPED_ARRAY_INT16
)
DEFINE_TYPEDARRAY_FROM
(
Uint16Array
,
TYPED_ARRAY_UINT16
)
DEFINE_TYPEDARRAY_FROM
(
Int32Array
,
TYPED_ARRAY_INT32
)
DEFINE_TYPEDARRAY_FROM
(
Uint32Array
,
TYPED_ARRAY_UINT32
)
DEFINE_TYPEDARRAY_FROM
(
Float16Array
,
TYPED_ARRAY_FLOAT16
)
DEFINE_TYPEDARRAY_FROM
(
Float32Array
,
TYPED_ARRAY_FLOAT32
)
DEFINE_TYPEDARRAY_FROM
(
Float64Array
,
TYPED_ARRAY_FLOAT64
)
DEFINE_TYPEDARRAY_FROM
(
BigInt64Array
,
TYPED_ARRAY_BIGINT64
)
DEFINE_TYPEDARRAY_FROM
(
BigUint64Array
,
TYPED_ARRAY_BIGUINT64
)
static
ant_value_t
js_dataview_constructor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
vtype
(
js
->
new_target
)
==
T_UNDEF
)
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"DataView constructor requires 'new'"
);
}
if
(
nargs
<
1
)
{
return
js_mkerr
(
js
,
"DataView requires an ArrayBuffer"
);
}
ArrayBufferData
*
buffer
=
buffer_get_arraybuffer_data
(
args
[
0
]);
if
(
!
buffer
)
{
return
js_mkerr
(
js
,
"First argument must be an ArrayBuffer"
);
}
size_t
byte_offset
=
0
;
size_t
byte_length
=
buffer
->
length
;
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
{
byte_offset
=
(
size_t
)
js_getnum
(
args
[
1
]);
}
if
(
byte_offset
>
buffer
->
length
)
{
return
js_mkerr
(
js
,
"Start offset is outside the bounds of the buffer"
);
}
if
(
nargs
>
2
&&
vtype
(
args
[
2
])
==
T_NUM
)
{
byte_length
=
(
size_t
)
js_getnum
(
args
[
2
]);
if
(
byte_length
>
buffer
->
length
-
byte_offset
)
{
return
js_mkerr
(
js
,
"Invalid DataView length"
);
}
}
else
byte_length
=
buffer
->
length
-
byte_offset
;
DataViewData
*
dv_data
=
ta_meta_alloc
(
sizeof
(
DataViewData
));
if
(
!
dv_data
)
return
js_mkerr
(
js
,
"Failed to allocate DataView"
);
dv_data
->
buffer
=
buffer
;
dv_data
->
byte_offset
=
byte_offset
;
dv_data
->
byte_length
=
byte_length
;
buffer
->
ref_count
++
;
ant_value_t
obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_get_ctor_proto
(
js
,
"DataView"
,
8
);
if
(
is_special_object
(
proto
))
js_set_proto_init
(
obj
,
proto
);
js_set_native_ptr
(
obj
,
dv_data
);
js_set_native_tag
(
obj
,
BUFFER_DATAVIEW_NATIVE_TAG
);
js_set_slot
(
obj
,
SLOT_BRAND
,
js_mknum
(
BRAND_DATAVIEW
));
js_mkprop_fast
(
js
,
obj
,
"buffer"
,
6
,
args
[
0
]);
js_set_descriptor
(
js
,
obj
,
"buffer"
,
6
,
0
);
js_set
(
js
,
obj
,
"byteLength"
,
js_mknum
((
double
)
byte_length
));
js_set
(
js
,
obj
,
"byteOffset"
,
js_mknum
((
double
)
byte_offset
));
js_set_finalizer
(
obj
,
dataview_finalize
);
return
obj
;
}
// DataView.prototype.getUint8(byteOffset)
static
ant_value_t
js_dataview_getInt8
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getInt8 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
if
(
offset
>=
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
int8_t
value
=
(
int8_t
)
dv
->
buffer
->
data
[
dv
->
byte_offset
+
offset
];
return
js_mknum
((
double
)
value
);
}
// DataView.prototype.setInt8(byteOffset, value)
static
ant_value_t
js_dataview_setInt8
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setInt8 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
int8_t
value
=
(
int8_t
)
js_to_int32
(
js_getnum
(
args
[
1
]));
if
(
offset
>=
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
dv
->
buffer
->
data
[
dv
->
byte_offset
+
offset
]
=
(
uint8_t
)
value
;
return
js_mkundef
();
}
// DataView.prototype.getUint8(byteOffset)
static
ant_value_t
js_dataview_getUint8
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getUint8 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
if
(
offset
>=
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
value
=
dv
->
buffer
->
data
[
dv
->
byte_offset
+
offset
];
return
js_mknum
((
double
)
value
);
}
// DataView.prototype.setUint8(byteOffset, value)
static
ant_value_t
js_dataview_setUint8
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setUint8 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
uint8_t
value
=
(
uint8_t
)
js_to_uint32
(
js_getnum
(
args
[
1
]));
if
(
offset
>=
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
dv
->
buffer
->
data
[
dv
->
byte_offset
+
offset
]
=
value
;
return
js_mkundef
();
}
// DataView.prototype.getInt16(byteOffset, littleEndian)
static
ant_value_t
js_dataview_getInt16
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getInt16 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
bool
little_endian
=
(
nargs
>
1
&&
js_truthy
(
js
,
args
[
1
]));
if
(
offset
+
2
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
int16_t
value
;
if
(
little_endian
)
{
value
=
(
int16_t
)(
ptr
[
0
]
|
(
ptr
[
1
]
<<
8
));
}
else
{
value
=
(
int16_t
)((
ptr
[
0
]
<<
8
)
|
ptr
[
1
]);
}
return
js_mknum
((
double
)
value
);
}
// DataView.prototype.getUint16(byteOffset, littleEndian)
static
ant_value_t
js_dataview_getUint16
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getUint16 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
bool
little_endian
=
(
nargs
>
1
&&
js_truthy
(
js
,
args
[
1
]));
if
(
offset
+
2
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
uint16_t
value
;
if
(
little_endian
)
value
=
(
uint16_t
)(
ptr
[
0
]
|
(
ptr
[
1
]
<<
8
));
else
value
=
(
uint16_t
)((
ptr
[
0
]
<<
8
)
|
ptr
[
1
]);
return
js_mknum
((
double
)
value
);
}
// DataView.prototype.setUint16(byteOffset, value, littleEndian)
static
ant_value_t
js_dataview_setUint16
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setUint16 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
uint16_t
value
=
(
uint16_t
)
js_to_uint32
(
js_getnum
(
args
[
1
]));
bool
little_endian
=
(
nargs
>
2
&&
js_truthy
(
js
,
args
[
2
]));
if
(
offset
+
2
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
if
(
little_endian
)
{
ptr
[
0
]
=
(
uint8_t
)(
value
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
value
>>
8
)
&
0xFF
);
}
else
{
ptr
[
0
]
=
(
uint8_t
)((
value
>>
8
)
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)(
value
&
0xFF
);
}
return
js_mkundef
();
}
// DataView.prototype.getInt32(byteOffset, littleEndian)
static
ant_value_t
js_dataview_getInt32
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getInt32 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
bool
little_endian
=
(
nargs
>
1
&&
js_truthy
(
js
,
args
[
1
]));
if
(
offset
+
4
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
int32_t
value
;
if
(
little_endian
)
{
value
=
(
int32_t
)(
ptr
[
0
]
|
(
ptr
[
1
]
<<
8
)
|
(
ptr
[
2
]
<<
16
)
|
(
ptr
[
3
]
<<
24
));
}
else
{
value
=
(
int32_t
)((
ptr
[
0
]
<<
24
)
|
(
ptr
[
1
]
<<
16
)
|
(
ptr
[
2
]
<<
8
)
|
ptr
[
3
]);
}
return
js_mknum
((
double
)
value
);
}
// DataView.prototype.getFloat32(byteOffset, littleEndian)
static
ant_value_t
js_dataview_getFloat32
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getFloat32 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
bool
little_endian
=
(
nargs
>
1
&&
js_truthy
(
js
,
args
[
1
]));
if
(
offset
+
4
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
uint32_t
bits
;
if
(
little_endian
)
{
bits
=
ptr
[
0
]
|
(
ptr
[
1
]
<<
8
)
|
(
ptr
[
2
]
<<
16
)
|
(
ptr
[
3
]
<<
24
);
}
else
{
bits
=
(
ptr
[
0
]
<<
24
)
|
(
ptr
[
1
]
<<
16
)
|
(
ptr
[
2
]
<<
8
)
|
ptr
[
3
];
}
float
value
;
memcpy
(
&
value
,
&
bits
,
4
);
return
js_mknum
((
double
)
value
);
}
// DataView.prototype.setInt16(byteOffset, value, littleEndian)
static
ant_value_t
js_dataview_setInt16
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setInt16 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
int16_t
value
=
(
int16_t
)
js_to_int32
(
js_getnum
(
args
[
1
]));
bool
little_endian
=
(
nargs
>
2
&&
js_truthy
(
js
,
args
[
2
]));
if
(
offset
+
2
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
if
(
little_endian
)
{
ptr
[
0
]
=
(
uint8_t
)(
value
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
value
>>
8
)
&
0xFF
);
}
else
{
ptr
[
0
]
=
(
uint8_t
)((
value
>>
8
)
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)(
value
&
0xFF
);
}
return
js_mkundef
();
}
// DataView.prototype.setInt32(byteOffset, value, littleEndian)
static
ant_value_t
js_dataview_setInt32
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setInt32 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
int32_t
value
=
js_to_int32
(
js_getnum
(
args
[
1
]));
bool
little_endian
=
(
nargs
>
2
&&
js_truthy
(
js
,
args
[
2
]));
if
(
offset
+
4
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
if
(
little_endian
)
{
ptr
[
0
]
=
(
uint8_t
)(
value
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
value
>>
8
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
value
>>
16
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)((
value
>>
24
)
&
0xFF
);
}
else
{
ptr
[
0
]
=
(
uint8_t
)((
value
>>
24
)
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
value
>>
16
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
value
>>
8
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)(
value
&
0xFF
);
}
return
js_mkundef
();
}
// DataView.prototype.getUint32(byteOffset, littleEndian)
static
ant_value_t
js_dataview_getUint32
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getUint32 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
bool
little_endian
=
(
nargs
>
1
&&
js_truthy
(
js
,
args
[
1
]));
if
(
offset
+
4
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
uint32_t
value
;
if
(
little_endian
)
value
=
(
uint32_t
)(
ptr
[
0
]
|
(
ptr
[
1
]
<<
8
)
|
(
ptr
[
2
]
<<
16
)
|
(
ptr
[
3
]
<<
24
));
else
value
=
(
uint32_t
)((
ptr
[
0
]
<<
24
)
|
(
ptr
[
1
]
<<
16
)
|
(
ptr
[
2
]
<<
8
)
|
ptr
[
3
]);
return
js_mknum
((
double
)
value
);
}
// DataView.prototype.setUint32(byteOffset, value, littleEndian)
static
ant_value_t
js_dataview_setUint32
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setUint32 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
uint32_t
value
=
js_to_uint32
(
js_getnum
(
args
[
1
]));
bool
little_endian
=
(
nargs
>
2
&&
js_truthy
(
js
,
args
[
2
]));
if
(
offset
+
4
>
dv
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
if
(
little_endian
)
{
ptr
[
0
]
=
(
uint8_t
)(
value
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
value
>>
8
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
value
>>
16
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)((
value
>>
24
)
&
0xFF
);
}
else
{
ptr
[
0
]
=
(
uint8_t
)((
value
>>
24
)
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
value
>>
16
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
value
>>
8
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)(
value
&
0xFF
);
}
return
js_mkundef
();
}
// DataView.prototype.setFloat32(byteOffset, value, littleEndian)
static
ant_value_t
js_dataview_setFloat32
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setFloat32 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
float
value
=
(
float
)
js_getnum
(
args
[
1
]);
bool
little_endian
=
(
nargs
>
2
&&
js_truthy
(
js
,
args
[
2
]));
if
(
offset
+
4
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
uint32_t
bits
;
memcpy
(
&
bits
,
&
value
,
4
);
if
(
little_endian
)
{
ptr
[
0
]
=
(
uint8_t
)(
bits
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
bits
>>
8
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
bits
>>
16
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)((
bits
>>
24
)
&
0xFF
);
}
else
{
ptr
[
0
]
=
(
uint8_t
)((
bits
>>
24
)
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
bits
>>
16
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
bits
>>
8
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)(
bits
&
0xFF
);
}
return
js_mkundef
();
}
// DataView.prototype.getFloat64(byteOffset, littleEndian)
static
ant_value_t
js_dataview_getFloat64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getFloat64 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
bool
little_endian
=
(
nargs
>
1
&&
js_truthy
(
js
,
args
[
1
]));
if
(
offset
+
8
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
uint64_t
bits
;
if
(
little_endian
)
{
bits
=
(
uint64_t
)
ptr
[
0
]
|
((
uint64_t
)
ptr
[
1
]
<<
8
)
|
((
uint64_t
)
ptr
[
2
]
<<
16
)
|
((
uint64_t
)
ptr
[
3
]
<<
24
)
|
((
uint64_t
)
ptr
[
4
]
<<
32
)
|
((
uint64_t
)
ptr
[
5
]
<<
40
)
|
((
uint64_t
)
ptr
[
6
]
<<
48
)
|
((
uint64_t
)
ptr
[
7
]
<<
56
);
}
else
{
bits
=
((
uint64_t
)
ptr
[
0
]
<<
56
)
|
((
uint64_t
)
ptr
[
1
]
<<
48
)
|
((
uint64_t
)
ptr
[
2
]
<<
40
)
|
((
uint64_t
)
ptr
[
3
]
<<
32
)
|
((
uint64_t
)
ptr
[
4
]
<<
24
)
|
((
uint64_t
)
ptr
[
5
]
<<
16
)
|
((
uint64_t
)
ptr
[
6
]
<<
8
)
|
(
uint64_t
)
ptr
[
7
];
}
double
value
;
memcpy
(
&
value
,
&
bits
,
8
);
return
js_mknum
(
value
);
}
// DataView.prototype.setFloat64(byteOffset, value, littleEndian)
static
ant_value_t
js_dataview_setFloat64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setFloat64 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
double
value
=
js_getnum
(
args
[
1
]);
bool
little_endian
=
(
nargs
>
2
&&
js_truthy
(
js
,
args
[
2
]));
if
(
offset
+
8
>
dv
->
byte_length
)
{
return
js_mkerr
(
js
,
"Offset out of bounds"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
uint64_t
bits
;
memcpy
(
&
bits
,
&
value
,
8
);
if
(
little_endian
)
{
ptr
[
0
]
=
(
uint8_t
)(
bits
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
bits
>>
8
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
bits
>>
16
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)((
bits
>>
24
)
&
0xFF
);
ptr
[
4
]
=
(
uint8_t
)((
bits
>>
32
)
&
0xFF
);
ptr
[
5
]
=
(
uint8_t
)((
bits
>>
40
)
&
0xFF
);
ptr
[
6
]
=
(
uint8_t
)((
bits
>>
48
)
&
0xFF
);
ptr
[
7
]
=
(
uint8_t
)((
bits
>>
56
)
&
0xFF
);
}
else
{
ptr
[
0
]
=
(
uint8_t
)((
bits
>>
56
)
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
bits
>>
48
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
bits
>>
40
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)((
bits
>>
32
)
&
0xFF
);
ptr
[
4
]
=
(
uint8_t
)((
bits
>>
24
)
&
0xFF
);
ptr
[
5
]
=
(
uint8_t
)((
bits
>>
16
)
&
0xFF
);
ptr
[
6
]
=
(
uint8_t
)((
bits
>>
8
)
&
0xFF
);
ptr
[
7
]
=
(
uint8_t
)(
bits
&
0xFF
);
}
return
js_mkundef
();
}
static
ant_value_t
js_dataview_getBigInt64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getBigInt64 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
bool
little_endian
=
(
nargs
>
1
&&
js_truthy
(
js
,
args
[
1
]));
if
(
offset
+
8
>
dv
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
uint64_t
bits
;
if
(
little_endian
)
{
bits
=
(
uint64_t
)
ptr
[
0
]
|
((
uint64_t
)
ptr
[
1
]
<<
8
)
|
((
uint64_t
)
ptr
[
2
]
<<
16
)
|
((
uint64_t
)
ptr
[
3
]
<<
24
)
|
((
uint64_t
)
ptr
[
4
]
<<
32
)
|
((
uint64_t
)
ptr
[
5
]
<<
40
)
|
((
uint64_t
)
ptr
[
6
]
<<
48
)
|
((
uint64_t
)
ptr
[
7
]
<<
56
);
}
else
{
bits
=
((
uint64_t
)
ptr
[
0
]
<<
56
)
|
((
uint64_t
)
ptr
[
1
]
<<
48
)
|
((
uint64_t
)
ptr
[
2
]
<<
40
)
|
((
uint64_t
)
ptr
[
3
]
<<
32
)
|
((
uint64_t
)
ptr
[
4
]
<<
24
)
|
((
uint64_t
)
ptr
[
5
]
<<
16
)
|
((
uint64_t
)
ptr
[
6
]
<<
8
)
|
(
uint64_t
)
ptr
[
7
];
}
return
bigint_from_int64
(
js
,
(
int64_t
)
bits
);
}
static
ant_value_t
js_dataview_setBigInt64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setBigInt64 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
ant_value_t
bigint
=
buffer_require_bigint_value
(
js
,
args
[
1
]);
bool
little_endian
=
(
nargs
>
2
&&
js_truthy
(
js
,
args
[
2
]));
int64_t
wrapped
=
0
;
if
(
is_err
(
bigint
))
return
bigint
;
if
(
offset
+
8
>
dv
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
if
(
!
bigint_to_int64_wrapping
(
js
,
bigint
,
&
wrapped
))
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Cannot convert to BigInt"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
uint64_t
bits
=
(
uint64_t
)
wrapped
;
if
(
little_endian
)
{
ptr
[
0
]
=
(
uint8_t
)(
bits
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
bits
>>
8
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
bits
>>
16
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)((
bits
>>
24
)
&
0xFF
);
ptr
[
4
]
=
(
uint8_t
)((
bits
>>
32
)
&
0xFF
);
ptr
[
5
]
=
(
uint8_t
)((
bits
>>
40
)
&
0xFF
);
ptr
[
6
]
=
(
uint8_t
)((
bits
>>
48
)
&
0xFF
);
ptr
[
7
]
=
(
uint8_t
)((
bits
>>
56
)
&
0xFF
);
}
else
{
ptr
[
0
]
=
(
uint8_t
)((
bits
>>
56
)
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
bits
>>
48
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
bits
>>
40
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)((
bits
>>
32
)
&
0xFF
);
ptr
[
4
]
=
(
uint8_t
)((
bits
>>
24
)
&
0xFF
);
ptr
[
5
]
=
(
uint8_t
)((
bits
>>
16
)
&
0xFF
);
ptr
[
6
]
=
(
uint8_t
)((
bits
>>
8
)
&
0xFF
);
ptr
[
7
]
=
(
uint8_t
)(
bits
&
0xFF
);
}
return
js_mkundef
();
}
static
ant_value_t
js_dataview_getBigUint64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"getBigUint64 requires byteOffset"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
bool
little_endian
=
(
nargs
>
1
&&
js_truthy
(
js
,
args
[
1
]));
if
(
offset
+
8
>
dv
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
uint64_t
bits
;
if
(
little_endian
)
{
bits
=
(
uint64_t
)
ptr
[
0
]
|
((
uint64_t
)
ptr
[
1
]
<<
8
)
|
((
uint64_t
)
ptr
[
2
]
<<
16
)
|
((
uint64_t
)
ptr
[
3
]
<<
24
)
|
((
uint64_t
)
ptr
[
4
]
<<
32
)
|
((
uint64_t
)
ptr
[
5
]
<<
40
)
|
((
uint64_t
)
ptr
[
6
]
<<
48
)
|
((
uint64_t
)
ptr
[
7
]
<<
56
);
}
else
{
bits
=
((
uint64_t
)
ptr
[
0
]
<<
56
)
|
((
uint64_t
)
ptr
[
1
]
<<
48
)
|
((
uint64_t
)
ptr
[
2
]
<<
40
)
|
((
uint64_t
)
ptr
[
3
]
<<
32
)
|
((
uint64_t
)
ptr
[
4
]
<<
24
)
|
((
uint64_t
)
ptr
[
5
]
<<
16
)
|
((
uint64_t
)
ptr
[
6
]
<<
8
)
|
(
uint64_t
)
ptr
[
7
];
}
return
bigint_from_uint64
(
js
,
bits
);
}
static
ant_value_t
js_dataview_setBigUint64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"setBigUint64 requires byteOffset and value"
);
ant_value_t
this_val
=
js_getthis
(
js
);
DataViewData
*
dv
=
buffer_get_dataview_data
(
this_val
);
if
(
!
dv
)
return
js_mkerr
(
js
,
"Not a DataView"
);
size_t
offset
=
(
size_t
)
js_getnum
(
args
[
0
]);
ant_value_t
bigint
=
buffer_require_bigint_value
(
js
,
args
[
1
]);
bool
little_endian
=
(
nargs
>
2
&&
js_truthy
(
js
,
args
[
2
]));
uint64_t
wrapped
=
0
;
if
(
is_err
(
bigint
))
return
bigint
;
if
(
offset
+
8
>
dv
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
if
(
!
bigint_to_uint64_wrapping
(
js
,
bigint
,
&
wrapped
))
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Cannot convert to BigInt"
);
}
uint8_t
*
ptr
=
dv
->
buffer
->
data
+
dv
->
byte_offset
+
offset
;
if
(
little_endian
)
{
ptr
[
0
]
=
(
uint8_t
)(
wrapped
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
wrapped
>>
8
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
wrapped
>>
16
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)((
wrapped
>>
24
)
&
0xFF
);
ptr
[
4
]
=
(
uint8_t
)((
wrapped
>>
32
)
&
0xFF
);
ptr
[
5
]
=
(
uint8_t
)((
wrapped
>>
40
)
&
0xFF
);
ptr
[
6
]
=
(
uint8_t
)((
wrapped
>>
48
)
&
0xFF
);
ptr
[
7
]
=
(
uint8_t
)((
wrapped
>>
56
)
&
0xFF
);
}
else
{
ptr
[
0
]
=
(
uint8_t
)((
wrapped
>>
56
)
&
0xFF
);
ptr
[
1
]
=
(
uint8_t
)((
wrapped
>>
48
)
&
0xFF
);
ptr
[
2
]
=
(
uint8_t
)((
wrapped
>>
40
)
&
0xFF
);
ptr
[
3
]
=
(
uint8_t
)((
wrapped
>>
32
)
&
0xFF
);
ptr
[
4
]
=
(
uint8_t
)((
wrapped
>>
24
)
&
0xFF
);
ptr
[
5
]
=
(
uint8_t
)((
wrapped
>>
16
)
&
0xFF
);
ptr
[
6
]
=
(
uint8_t
)((
wrapped
>>
8
)
&
0xFF
);
ptr
[
7
]
=
(
uint8_t
)(
wrapped
&
0xFF
);
}
return
js_mkundef
();
}
static
uint8_t
*
hex_decode
(
const
char
*
data
,
size_t
len
,
size_t
*
out_len
)
{
if
(
len
%
2
!=
0
)
return
NULL
;
size_t
decoded_len
=
len
/
2
;
size_t
alloc_len
=
decoded_len
;
if
(
alloc_len
==
0
)
alloc_len
=
1
;
uint8_t
*
decoded
=
malloc
(
alloc_len
);
if
(
!
decoded
)
return
NULL
;
for
(
size_t
i
=
0
;
i
<
decoded_len
;
i
++
)
{
unsigned
char
hi_ch
=
(
unsigned
char
)
data
[
i
*
2
];
unsigned
char
lo_ch
=
(
unsigned
char
)
data
[
i
*
2
+
1
];
int
hi
;
int
lo
;
if
(
hi_ch
>=
'0'
&&
hi_ch
<=
'9'
)
{
hi
=
hi_ch
-
'0'
;
goto
have_hi
;
}
if
(
hi_ch
>=
'a'
&&
hi_ch
<=
'f'
)
{
hi
=
hi_ch
-
'a'
+
10
;
goto
have_hi
;
}
if
(
hi_ch
>=
'A'
&&
hi_ch
<=
'F'
)
{
hi
=
hi_ch
-
'A'
+
10
;
goto
have_hi
;
}
goto
fail
;
have_hi
:
if
(
lo_ch
>=
'0'
&&
lo_ch
<=
'9'
)
{
lo
=
lo_ch
-
'0'
;
goto
have_lo
;
}
if
(
lo_ch
>=
'a'
&&
lo_ch
<=
'f'
)
{
lo
=
lo_ch
-
'a'
+
10
;
goto
have_lo
;
}
if
(
lo_ch
>=
'A'
&&
lo_ch
<=
'F'
)
{
lo
=
lo_ch
-
'A'
+
10
;
goto
have_lo
;
}
goto
fail
;
have_lo
:
decoded
[
i
]
=
(
uint8_t
)((
hi
<<
4
)
|
lo
);
}
*
out_len
=
decoded_len
;
return
decoded
;
fail
:
free
(
decoded
);
return
NULL
;
}
static
ant_value_t
uint8array_from_bytes
(
ant_t
*
js
,
const
uint8_t
*
bytes
,
size_t
len
)
{
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
len
);
if
(
!
buffer
)
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
if
(
len
>
0
)
memcpy
(
buffer
->
data
,
bytes
,
len
);
return
create_typed_array
(
js
,
TYPED_ARRAY_UINT8
,
buffer
,
0
,
len
,
"Uint8Array"
);
}
static
ant_value_t
js_uint8array_fromHex
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
source
=
nargs
>
0
?
js_tostring_val
(
js
,
args
[
0
])
:
js_mkstr
(
js
,
""
,
0
);
if
(
is_err
(
source
))
return
source
;
size_t
len
=
0
;
char
*
str
=
js_getstr
(
js
,
source
,
&
len
);
size_t
decoded_len
=
0
;
uint8_t
*
decoded
=
hex_decode
(
str
,
len
,
&
decoded_len
);
if
(
!
decoded
)
return
js_mkerr_typed
(
js
,
JS_ERR_SYNTAX
,
"Invalid hex string"
);
ant_value_t
result
=
uint8array_from_bytes
(
js
,
decoded
,
decoded_len
);
free
(
decoded
);
return
result
;
}
static
ant_value_t
js_uint8array_fromBase64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
source
=
nargs
>
0
?
js_tostring_val
(
js
,
args
[
0
])
:
js_mkstr
(
js
,
""
,
0
);
if
(
is_err
(
source
))
return
source
;
size_t
len
=
0
;
char
*
str
=
js_getstr
(
js
,
source
,
&
len
);
size_t
decoded_len
=
0
;
uint8_t
*
decoded
=
ant_base64_decode
(
str
,
len
,
&
decoded_len
);
if
(
!
decoded
)
return
js_mkerr_typed
(
js
,
JS_ERR_SYNTAX
,
"Invalid base64 string"
);
ant_value_t
result
=
uint8array_from_bytes
(
js
,
decoded
,
decoded_len
);
free
(
decoded
);
return
result
;
}
static
ant_value_t
js_uint8array_toHex
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
||
ta_data
->
type
!=
TYPED_ARRAY_UINT8
)
return
js_mkerr
(
js
,
"Uint8Array.prototype.toHex called on incompatible receiver"
);
if
(
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
return
js_mkerr
(
js
,
"Cannot read from detached Uint8Array"
);
uint8_t
*
data
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
size_t
len
=
ta_data
->
byte_length
;
char
*
hex
=
malloc
(
len
*
2
+
1
);
if
(
!
hex
)
return
js_mkerr
(
js
,
"Failed to allocate hex string"
);
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
snprintf
(
hex
+
i
*
2
,
3
,
"%02x"
,
data
[
i
]);
ant_value_t
result
=
js_mkstr
(
js
,
hex
,
len
*
2
);
free
(
hex
);
return
result
;
}
static
ant_value_t
js_uint8array_toBase64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
||
ta_data
->
type
!=
TYPED_ARRAY_UINT8
)
return
js_mkerr
(
js
,
"Uint8Array.prototype.toBase64 called on incompatible receiver"
);
if
(
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
return
js_mkerr
(
js
,
"Cannot read from detached Uint8Array"
);
size_t
out_len
=
0
;
char
*
encoded
=
ant_base64_encode
(
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
,
ta_data
->
byte_length
,
&
out_len
);
if
(
!
encoded
)
return
js_mkerr
(
js
,
"Failed to encode base64"
);
ant_value_t
result
=
js_mkstr
(
js
,
encoded
,
out_len
);
free
(
encoded
);
return
result
;
}
static
ant_value_t
uint8array_set_result
(
ant_t
*
js
,
size_t
read
,
size_t
written
)
{
ant_value_t
result
=
js_mkobj
(
js
);
js_set
(
js
,
result
,
"read"
,
js_mknum
((
double
)
read
));
js_set
(
js
,
result
,
"written"
,
js_mknum
((
double
)
written
));
return
result
;
}
static
ant_value_t
uint8array_set_bytes
(
ant_t
*
js
,
const
uint8_t
*
bytes
,
size_t
byte_len
,
size_t
read
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
||
ta_data
->
type
!=
TYPED_ARRAY_UINT8
)
return
js_mkerr
(
js
,
"Uint8Array setFrom called on incompatible receiver"
);
if
(
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
return
js_mkerr
(
js
,
"Cannot write to detached Uint8Array"
);
if
(
byte_len
>
ta_data
->
byte_length
)
return
js_mkerr_typed
(
js
,
JS_ERR_RANGE
,
"Decoded data does not fit in Uint8Array"
);
if
(
byte_len
>
0
)
memcpy
(
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
,
bytes
,
byte_len
);
return
uint8array_set_result
(
js
,
read
,
byte_len
);
}
static
ant_value_t
js_uint8array_setFromHex
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
source
=
nargs
>
0
?
js_tostring_val
(
js
,
args
[
0
])
:
js_mkstr
(
js
,
""
,
0
);
if
(
is_err
(
source
))
return
source
;
size_t
len
=
0
;
char
*
str
=
js_getstr
(
js
,
source
,
&
len
);
size_t
decoded_len
=
0
;
uint8_t
*
decoded
=
hex_decode
(
str
,
len
,
&
decoded_len
);
if
(
!
decoded
)
return
js_mkerr_typed
(
js
,
JS_ERR_SYNTAX
,
"Invalid hex string"
);
ant_value_t
result
=
uint8array_set_bytes
(
js
,
decoded
,
decoded_len
,
len
);
free
(
decoded
);
return
result
;
}
static
ant_value_t
js_uint8array_setFromBase64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
source
=
nargs
>
0
?
js_tostring_val
(
js
,
args
[
0
])
:
js_mkstr
(
js
,
""
,
0
);
if
(
is_err
(
source
))
return
source
;
size_t
len
=
0
;
char
*
str
=
js_getstr
(
js
,
source
,
&
len
);
size_t
decoded_len
=
0
;
uint8_t
*
decoded
=
ant_base64_decode
(
str
,
len
,
&
decoded_len
);
if
(
!
decoded
)
return
js_mkerr_typed
(
js
,
JS_ERR_SYNTAX
,
"Invalid base64 string"
);
ant_value_t
result
=
uint8array_set_bytes
(
js
,
decoded
,
decoded_len
,
len
);
free
(
decoded
);
return
result
;
}
typedef
enum
{
ENC_UTF8
,
ENC_HEX
,
ENC_BASE64
,
ENC_ASCII
,
ENC_LATIN1
,
ENC_UCS2
,
ENC_UNKNOWN
}
BufferEncoding
;
static
BufferEncoding
parse_encoding
(
const
char
*
enc
,
size_t
len
)
{
if
(
len
==
3
&&
strncasecmp
(
enc
,
"hex"
,
3
)
==
0
)
return
ENC_HEX
;
if
(
len
==
5
&&
strncasecmp
(
enc
,
"ascii"
,
5
)
==
0
)
return
ENC_ASCII
;
if
(
len
==
6
&&
strncasecmp
(
enc
,
"base64"
,
6
)
==
0
)
return
ENC_BASE64
;
if
((
len
==
4
&&
strncasecmp
(
enc
,
"utf8"
,
4
)
==
0
)
||
(
len
==
5
&&
strncasecmp
(
enc
,
"utf-8"
,
5
)
==
0
))
return
ENC_UTF8
;
if
((
len
==
6
&&
strncasecmp
(
enc
,
"latin1"
,
6
)
==
0
)
||
(
len
==
6
&&
strncasecmp
(
enc
,
"binary"
,
6
)
==
0
))
return
ENC_LATIN1
;
if
(
(
len
==
4
&&
strncasecmp
(
enc
,
"ucs2"
,
4
)
==
0
)
||
(
len
==
5
&&
strncasecmp
(
enc
,
"ucs-2"
,
5
)
==
0
)
||
(
len
==
7
&&
strncasecmp
(
enc
,
"utf16le"
,
7
)
==
0
)
||
(
len
==
8
&&
strncasecmp
(
enc
,
"utf-16le"
,
8
)
==
0
)
)
return
ENC_UCS2
;
return
ENC_UNKNOWN
;
}
// Buffer.from(array/string/buffer, encoding)
static
ant_value_t
js_buffer_from
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"Buffer.from requires at least one argument"
);
if
(
vtype
(
args
[
0
])
==
T_STR
)
{
size_t
len
;
char
*
str
=
js_getstr
(
js
,
args
[
0
],
&
len
);
BufferEncoding
encoding
=
ENC_UTF8
;
if
(
nargs
>=
2
&&
vtype
(
args
[
1
])
==
T_STR
)
{
size_t
enc_len
;
char
*
enc_str
=
js_getstr
(
js
,
args
[
1
],
&
enc_len
);
encoding
=
parse_encoding
(
enc_str
,
enc_len
);
if
(
encoding
==
ENC_UNKNOWN
)
encoding
=
ENC_UTF8
;
}
if
(
encoding
==
ENC_BASE64
)
{
size_t
decoded_len
;
uint8_t
*
decoded
=
ant_base64_decode
(
str
,
len
,
&
decoded_len
);
if
(
!
decoded
)
return
js_mkerr
(
js
,
"Failed to decode base64"
);
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
decoded_len
);
if
(
!
buffer
)
{
free
(
decoded
);
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
}
memcpy
(
buffer
->
data
,
decoded
,
decoded_len
);
free
(
decoded
);
return
create_typed_array
(
js
,
TYPED_ARRAY_UINT8
,
buffer
,
0
,
decoded_len
,
"Buffer"
);
}
else
if
(
encoding
==
ENC_HEX
)
{
size_t
decoded_len
;
uint8_t
*
decoded
=
hex_decode
(
str
,
len
,
&
decoded_len
);
if
(
!
decoded
)
return
js_mkerr
(
js
,
"Failed to decode hex"
);
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
decoded_len
);
if
(
!
buffer
)
{
free
(
decoded
);
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
}
memcpy
(
buffer
->
data
,
decoded
,
decoded_len
);
free
(
decoded
);
return
create_typed_array
(
js
,
TYPED_ARRAY_UINT8
,
buffer
,
0
,
decoded_len
,
"Buffer"
);
}
else
if
(
encoding
==
ENC_UCS2
)
{
size_t
decoded_len
=
len
*
2
;
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
decoded_len
);
if
(
!
buffer
)
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
buffer
->
data
[
i
*
2
]
=
(
uint8_t
)
str
[
i
];
buffer
->
data
[
i
*
2
+
1
]
=
0
;
}
return
create_typed_array
(
js
,
TYPED_ARRAY_UINT8
,
buffer
,
0
,
decoded_len
,
"Buffer"
);
}
else
{
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
len
);
if
(
!
buffer
)
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
memcpy
(
buffer
->
data
,
str
,
len
);
return
create_typed_array
(
js
,
TYPED_ARRAY_UINT8
,
buffer
,
0
,
len
,
"Buffer"
);
}
}
ant_value_t
length_val
=
js_get
(
js
,
args
[
0
],
"length"
);
if
(
vtype
(
length_val
)
==
T_NUM
)
{
size_t
len
=
(
size_t
)
js_getnum
(
length_val
);
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
len
);
if
(
!
buffer
)
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
char
idx_str
[
32
];
snprintf
(
idx_str
,
sizeof
(
idx_str
),
"%zu"
,
i
);
ant_value_t
elem
=
js_get
(
js
,
args
[
0
],
idx_str
);
if
(
vtype
(
elem
)
==
T_NUM
)
{
buffer
->
data
[
i
]
=
(
uint8_t
)
js_getnum
(
elem
);
}
}
return
create_typed_array
(
js
,
TYPED_ARRAY_UINT8
,
buffer
,
0
,
len
,
"Buffer"
);
}
return
js_mkerr
(
js
,
"Invalid argument to Buffer.from"
);
}
// Buffer.alloc(size)
static
ant_value_t
js_buffer_alloc
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
{
return
js_mkerr
(
js
,
"Buffer.alloc requires a size argument"
);
}
size_t
size
=
(
size_t
)
js_getnum
(
args
[
0
]);
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
size
);
if
(
!
buffer
)
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
memset
(
buffer
->
data
,
0
,
size
);
return
create_typed_array
(
js
,
TYPED_ARRAY_UINT8
,
buffer
,
0
,
size
,
"Buffer"
);
}
// Buffer.allocUnsafe(size)
static
ant_value_t
js_buffer_allocUnsafe
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
{
return
js_mkerr
(
js
,
"Buffer.allocUnsafe requires a size argument"
);
}
size_t
size
=
(
size_t
)
js_getnum
(
args
[
0
]);
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
size
);
if
(
!
buffer
)
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
return
create_typed_array
(
js
,
TYPED_ARRAY_UINT8
,
buffer
,
0
,
size
,
"Buffer"
);
}
static
ant_value_t
typedarray_join_with
(
ant_t
*
js
,
ant_value_t
this_val
,
const
char
*
sep
,
size_t
sep_len
)
{
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkstr
(
js
,
""
,
0
);
if
(
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
||
ta_data
->
length
==
0
)
return
js_mkstr
(
js
,
""
,
0
);
uint8_t
*
data
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
size_t
len
=
ta_data
->
length
;
size_t
cap
=
len
*
12
;
char
*
buf
=
malloc
(
cap
);
if
(
!
buf
)
return
js_mkerr
(
js
,
"Out of memory"
);
size_t
pos
=
0
;
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
if
(
i
>
0
)
{
if
(
pos
+
sep_len
+
32
>
cap
)
{
cap
*=
2
;
char
*
tmp
=
realloc
(
buf
,
cap
);
if
(
!
tmp
)
{
free
(
buf
);
return
js_mkerr
(
js
,
"Out of memory"
);
}
buf
=
tmp
;
}
memcpy
(
buf
+
pos
,
sep
,
sep_len
);
pos
+=
sep_len
;
}
if
(
pos
+
32
>
cap
)
{
cap
*=
2
;
char
*
tmp
=
realloc
(
buf
,
cap
);
if
(
!
tmp
)
{
free
(
buf
);
return
js_mkerr
(
js
,
"Out of memory"
);
}
buf
=
tmp
;
}
int
written
=
0
;
switch
(
ta_data
->
type
)
{
case
TYPED_ARRAY_INT8
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%d"
,
((
int8_t
*
)
data
)[
i
]);
break
;
case
TYPED_ARRAY_UINT8
:
case
TYPED_ARRAY_UINT8_CLAMPED
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%u"
,
data
[
i
]);
break
;
case
TYPED_ARRAY_INT16
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%d"
,
((
int16_t
*
)
data
)[
i
]);
break
;
case
TYPED_ARRAY_UINT16
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%u"
,
((
uint16_t
*
)
data
)[
i
]);
break
;
case
TYPED_ARRAY_INT32
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%d"
,
((
int32_t
*
)
data
)[
i
]);
break
;
case
TYPED_ARRAY_UINT32
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%u"
,
((
uint32_t
*
)
data
)[
i
]);
break
;
case
TYPED_ARRAY_FLOAT16
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%g"
,
half_to_double
(((
uint16_t
*
)
data
)[
i
]));
break
;
case
TYPED_ARRAY_FLOAT32
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%g"
,
(
double
)((
float
*
)
data
)[
i
]);
break
;
case
TYPED_ARRAY_FLOAT64
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%g"
,
((
double
*
)
data
)[
i
]);
break
;
case
TYPED_ARRAY_BIGINT64
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%lld"
,
((
long
long
*
)
data
)[
i
]);
break
;
case
TYPED_ARRAY_BIGUINT64
:
written
=
snprintf
(
buf
+
pos
,
cap
-
pos
,
"%llu"
,
((
unsigned
long
long
*
)
data
)[
i
]);
break
;
default
:
break
;
}
if
(
written
>
0
)
pos
+=
(
size_t
)
written
;
}
ant_value_t
ret
=
js_mkstr
(
js
,
buf
,
pos
);
free
(
buf
);
return
ret
;
}
// TypedArray.prototype.toString()
static
ant_value_t
js_typedarray_toString
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
typedarray_join_with
(
js
,
js_getthis
(
js
),
","
,
1
);
}
// TypedArray.prototype.join(separator)
static
ant_value_t
js_typedarray_join
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
const
char
*
sep
=
","
;
size_t
sep_len
=
1
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_STR
)
sep
=
js_getstr
(
js
,
args
[
0
],
&
sep_len
);
return
typedarray_join_with
(
js
,
js_getthis
(
js
),
sep
,
sep_len
);
}
static
ant_value_t
js_typedarray_indexOf
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
||
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
return
js_mknum
(
-1
);
size_t
len
=
ta_data
->
length
;
if
(
len
==
0
||
nargs
<
1
)
return
js_mknum
(
-1
);
int64_t
from_index
=
0
;
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
!=
T_UNDEF
)
{
from_index
=
(
int64_t
)
js_to_number
(
js
,
args
[
1
]);
if
(
from_index
<
0
)
{
from_index
+=
(
int64_t
)
len
;
if
(
from_index
<
0
)
from_index
=
0
;
}}
if
((
size_t
)
from_index
>=
len
)
return
js_mknum
(
-1
);
uint8_t
*
data
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
double
needle_num
=
js_to_number
(
js
,
args
[
0
]);
for
(
size_t
i
=
(
size_t
)
from_index
;
i
<
len
;
i
++
)
{
bool
match
=
false
;
switch
(
ta_data
->
type
)
{
case
TYPED_ARRAY_INT8
:
match
=
((
int8_t
*
)
data
)[
i
]
==
(
int8_t
)
needle_num
;
break
;
case
TYPED_ARRAY_UINT8
:
case
TYPED_ARRAY_UINT8_CLAMPED
:
match
=
data
[
i
]
==
(
uint8_t
)
needle_num
;
break
;
case
TYPED_ARRAY_INT16
:
match
=
((
int16_t
*
)
data
)[
i
]
==
(
int16_t
)
needle_num
;
break
;
case
TYPED_ARRAY_UINT16
:
match
=
((
uint16_t
*
)
data
)[
i
]
==
(
uint16_t
)
needle_num
;
break
;
case
TYPED_ARRAY_INT32
:
match
=
((
int32_t
*
)
data
)[
i
]
==
(
int32_t
)
needle_num
;
break
;
case
TYPED_ARRAY_UINT32
:
match
=
((
uint32_t
*
)
data
)[
i
]
==
(
uint32_t
)
needle_num
;
break
;
case
TYPED_ARRAY_FLOAT16
:
match
=
half_to_double
(((
uint16_t
*
)
data
)[
i
])
==
needle_num
;
break
;
case
TYPED_ARRAY_FLOAT32
:
match
=
((
float
*
)
data
)[
i
]
==
(
float
)
needle_num
;
break
;
case
TYPED_ARRAY_FLOAT64
:
match
=
((
double
*
)
data
)[
i
]
==
needle_num
;
break
;
case
TYPED_ARRAY_BIGINT64
:
match
=
((
int64_t
*
)
data
)[
i
]
==
(
int64_t
)
needle_num
;
break
;
case
TYPED_ARRAY_BIGUINT64
:
match
=
((
uint64_t
*
)
data
)[
i
]
==
(
uint64_t
)
needle_num
;
break
;
default
:
break
;
}
if
(
match
)
return
js_mknum
((
double
)
i
);
}
return
js_mknum
(
-1
);
}
static
ant_value_t
js_typedarray_includes
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
||
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
{
return
js_mkerr
(
js
,
"Invalid TypedArray"
);
}
size_t
len
=
ta_data
->
length
;
ant_value_t
search
=
(
nargs
>
0
)
?
args
[
0
]
:
js_mkundef
();
if
(
len
==
0
)
return
js_false
;
int64_t
from_index
=
0
;
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
!=
T_UNDEF
)
{
double
from_index_num
=
js_to_number
(
js
,
args
[
1
]);
if
(
!
isnan
(
from_index_num
))
from_index
=
(
int64_t
)
from_index_num
;
if
(
from_index
<
0
)
{
from_index
+=
(
int64_t
)
len
;
if
(
from_index
<
0
)
from_index
=
0
;
}}
if
((
size_t
)
from_index
>=
len
)
return
js_false
;
if
(
ta_data
->
type
==
TYPED_ARRAY_BIGINT64
)
{
int64_t
needle
=
0
;
if
(
vtype
(
search
)
==
T_BIGINT
)
{
if
(
!
bigint_to_int64_wrapping
(
js
,
search
,
&
needle
))
return
js_false
;
}
else
needle
=
(
int64_t
)
js_to_number
(
js
,
search
);
int64_t
*
data
=
(
int64_t
*
)(
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
);
for
(
size_t
i
=
(
size_t
)
from_index
;
i
<
len
;
i
++
)
{
if
(
data
[
i
]
==
needle
)
return
js_true
;
}
return
js_false
;
}
if
(
ta_data
->
type
==
TYPED_ARRAY_BIGUINT64
)
{
uint64_t
needle
=
0
;
if
(
vtype
(
search
)
==
T_BIGINT
)
{
if
(
!
bigint_to_uint64_wrapping
(
js
,
search
,
&
needle
))
return
js_false
;
}
else
needle
=
(
uint64_t
)
js_to_number
(
js
,
search
);
uint64_t
*
data
=
(
uint64_t
*
)(
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
);
for
(
size_t
i
=
(
size_t
)
from_index
;
i
<
len
;
i
++
)
{
if
(
data
[
i
]
==
needle
)
return
js_true
;
}
return
js_false
;
}
double
needle
=
js_to_number
(
js
,
search
);
for
(
size_t
i
=
(
size_t
)
from_index
;
i
<
len
;
i
++
)
{
double
value
=
0
;
if
(
!
typedarray_read_number
(
ta_data
,
i
,
&
value
))
return
js_false
;
if
(
isnan
(
value
)
&&
isnan
(
needle
))
return
js_true
;
if
(
value
==
needle
)
return
js_true
;
}
return
js_false
;
}
// Buffer.prototype.toString(encoding)
static
ant_value_t
js_buffer_slice
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_typedarray_subarray
(
js
,
args
,
nargs
);
}
// Buffer.prototype.toString(encoding)
static
ant_value_t
js_buffer_toString
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid Buffer"
);
BufferEncoding
encoding
=
ENC_UTF8
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_STR
)
{
size_t
enc_len
;
char
*
enc_str
=
js_getstr
(
js
,
args
[
0
],
&
enc_len
);
encoding
=
parse_encoding
(
enc_str
,
enc_len
);
if
(
encoding
==
ENC_UNKNOWN
)
encoding
=
ENC_UTF8
;
}
if
(
!
ta_data
->
buffer
||
ta_data
->
buffer
->
is_detached
)
{
return
js_mkerr
(
js
,
"Cannot read from detached buffer"
);
}
uint8_t
*
data
=
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
;
size_t
len
=
ta_data
->
byte_length
;
if
(
encoding
==
ENC_BASE64
)
{
size_t
out_len
;
char
*
encoded
=
ant_base64_encode
(
data
,
len
,
&
out_len
);
if
(
!
encoded
)
return
js_mkerr
(
js
,
"Failed to encode base64"
);
ant_value_t
result
=
js_mkstr
(
js
,
encoded
,
out_len
);
free
(
encoded
);
return
result
;
}
else
if
(
encoding
==
ENC_HEX
)
{
char
*
hex
=
malloc
(
len
*
2
+
1
);
if
(
!
hex
)
return
js_mkerr
(
js
,
"Failed to allocate hex string"
);
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
snprintf
(
hex
+
i
*
2
,
3
,
"%02x"
,
data
[
i
]);
}
ant_value_t
result
=
js_mkstr
(
js
,
hex
,
len
*
2
);
free
(
hex
);
return
result
;
}
else
if
(
encoding
==
ENC_UCS2
)
{
size_t
char_count
=
len
/
2
;
char
*
str
=
malloc
(
char_count
+
1
);
if
(
!
str
)
return
js_mkerr
(
js
,
"Failed to allocate string"
);
for
(
size_t
i
=
0
;
i
<
char_count
;
i
++
)
str
[
i
]
=
(
char
)
data
[
i
*
2
];
str
[
char_count
]
=
'\0'
;
ant_value_t
result
=
js_mkstr
(
js
,
str
,
char_count
);
free
(
str
);
return
result
;
}
else
{
size_t
out_cap
=
len
*
3
+
1
;
char
*
out
=
malloc
(
out_cap
);
if
(
!
out
)
return
js_mkerr
(
js
,
"Failed to allocate string"
);
utf8_dec_t
dec
=
{
.
bom_seen
=
true
,
.
ignore_bom
=
true
};
utf8proc_ssize_t
out_len
=
utf8_whatwg_decode
(
&
dec
,
data
,
len
,
out
,
false
,
false
);
if
(
out_len
<
0
)
{
free
(
out
);
return
js_mkerr
(
js
,
"Failed to decode buffer as UTF-8"
);
}
ant_value_t
result
=
js_mkstr
(
js
,
out
,
(
size_t
)
out_len
);
free
(
out
);
return
result
;
}
}
// Buffer.prototype.toBase64()
static
ant_value_t
js_buffer_toBase64
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
ant_value_t
encoding_arg
=
js_mkstr
(
js
,
"base64"
,
6
);
ant_value_t
new_args
[
1
]
=
{
encoding_arg
};
return
js_buffer_toString
(
js
,
new_args
,
1
);
}
// Buffer.prototype.write(string, offset, length, encoding)
static
ant_value_t
js_buffer_write
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"write requires a string"
);
ant_value_t
this_val
=
js_getthis
(
js
);
TypedArrayData
*
ta_data
=
buffer_get_typedarray_data
(
this_val
);
if
(
!
ta_data
)
return
js_mkerr
(
js
,
"Invalid Buffer"
);
size_t
str_len
;
char
*
str
=
js_getstr
(
js
,
args
[
0
],
&
str_len
);
size_t
offset
=
0
;
size_t
length
=
ta_data
->
byte_length
;
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
{
offset
=
(
size_t
)
js_getnum
(
args
[
1
]);
}
if
(
nargs
>
2
&&
vtype
(
args
[
2
])
==
T_NUM
)
{
length
=
(
size_t
)
js_getnum
(
args
[
2
]);
}
if
(
offset
>=
ta_data
->
byte_length
)
{
return
js_mknum
(
0
);
}
size_t
available
=
ta_data
->
byte_length
-
offset
;
size_t
to_write
=
(
str_len
<
length
)
?
str_len
:
length
;
to_write
=
(
to_write
<
available
)
?
to_write
:
available
;
memcpy
(
ta_data
->
buffer
->
data
+
ta_data
->
byte_offset
+
offset
,
str
,
to_write
);
return
js_mknum
((
double
)
to_write
);
}
static
ant_value_t
js_buffer_copy
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"copy requires a target buffer"
);
TypedArrayData
*
src
=
buffer_get_typedarray_data
(
js_getthis
(
js
));
TypedArrayData
*
dst
=
buffer_get_typedarray_data
(
args
[
0
]);
if
(
!
src
||
!
dst
)
return
js_mkerr
(
js
,
"copy requires Buffer arguments"
);
size_t
target_start
=
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
?
(
size_t
)
js_getnum
(
args
[
1
])
:
0
;
size_t
source_start
=
(
nargs
>
2
&&
vtype
(
args
[
2
])
==
T_NUM
)
?
(
size_t
)
js_getnum
(
args
[
2
])
:
0
;
size_t
source_end
=
(
nargs
>
3
&&
vtype
(
args
[
3
])
==
T_NUM
)
?
(
size_t
)
js_getnum
(
args
[
3
])
:
src
->
byte_length
;
if
(
target_start
>
dst
->
byte_length
)
target_start
=
dst
->
byte_length
;
if
(
source_start
>
src
->
byte_length
)
source_start
=
src
->
byte_length
;
if
(
source_end
>
src
->
byte_length
)
source_end
=
src
->
byte_length
;
if
(
source_end
<
source_start
)
source_end
=
source_start
;
size_t
src_len
=
source_end
-
source_start
;
size_t
dst_len
=
dst
->
byte_length
-
target_start
;
size_t
copy_len
=
src_len
<
dst_len
?
src_len
:
dst_len
;
if
(
copy_len
==
0
)
return
js_mknum
(
0
);
uint8_t
*
src_ptr
=
src
->
buffer
->
data
+
src
->
byte_offset
+
source_start
;
uint8_t
*
dst_ptr
=
dst
->
buffer
->
data
+
dst
->
byte_offset
+
target_start
;
memmove
(
dst_ptr
,
src_ptr
,
copy_len
);
return
js_mknum
((
double
)
copy_len
);
}
static
ant_value_t
js_buffer_writeInt16BE
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"writeInt16BE requires a value"
);
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
js_getthis
(
js
));
if
(
!
ta
)
return
js_mkerr
(
js
,
"Invalid Buffer"
);
int16_t
value
=
(
int16_t
)
js_to_int32
(
js_getnum
(
args
[
0
]));
size_t
offset
=
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
?
(
size_t
)
js_getnum
(
args
[
1
])
:
0
;
if
(
offset
+
2
>
ta
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
uint8_t
*
ptr
=
ta
->
buffer
->
data
+
ta
->
byte_offset
+
offset
;
ptr
[
0
]
=
(
uint8_t
)((
value
>>
8
)
&
0xff
);
ptr
[
1
]
=
(
uint8_t
)(
value
&
0xff
);
return
js_mknum
((
double
)(
offset
+
2
));
}
static
ant_value_t
js_buffer_writeInt32BE
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"writeInt32BE requires a value"
);
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
js_getthis
(
js
));
if
(
!
ta
)
return
js_mkerr
(
js
,
"Invalid Buffer"
);
int32_t
value
=
js_to_int32
(
js_getnum
(
args
[
0
]));
size_t
offset
=
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
?
(
size_t
)
js_getnum
(
args
[
1
])
:
0
;
if
(
offset
+
4
>
ta
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
uint8_t
*
ptr
=
ta
->
buffer
->
data
+
ta
->
byte_offset
+
offset
;
ptr
[
0
]
=
(
uint8_t
)((
value
>>
24
)
&
0xff
);
ptr
[
1
]
=
(
uint8_t
)((
value
>>
16
)
&
0xff
);
ptr
[
2
]
=
(
uint8_t
)((
value
>>
8
)
&
0xff
);
ptr
[
3
]
=
(
uint8_t
)(
value
&
0xff
);
return
js_mknum
((
double
)(
offset
+
4
));
}
static
ant_value_t
js_buffer_writeUInt32BE
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"writeUInt32BE requires a value"
);
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
js_getthis
(
js
));
if
(
!
ta
)
return
js_mkerr
(
js
,
"Invalid Buffer"
);
uint32_t
value
=
js_to_uint32
(
js_getnum
(
args
[
0
]));
size_t
offset
=
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
?
(
size_t
)
js_getnum
(
args
[
1
])
:
0
;
if
(
offset
+
4
>
ta
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
uint8_t
*
ptr
=
ta
->
buffer
->
data
+
ta
->
byte_offset
+
offset
;
ptr
[
0
]
=
(
uint8_t
)((
value
>>
24
)
&
0xff
);
ptr
[
1
]
=
(
uint8_t
)((
value
>>
16
)
&
0xff
);
ptr
[
2
]
=
(
uint8_t
)((
value
>>
8
)
&
0xff
);
ptr
[
3
]
=
(
uint8_t
)(
value
&
0xff
);
return
js_mknum
((
double
)(
offset
+
4
));
}
static
ant_value_t
js_buffer_readInt16BE
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
js_getthis
(
js
));
if
(
!
ta
)
return
js_mkerr
(
js
,
"Invalid Buffer"
);
size_t
offset
=
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
?
(
size_t
)
js_getnum
(
args
[
0
])
:
0
;
if
(
offset
+
2
>
ta
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
uint8_t
*
ptr
=
ta
->
buffer
->
data
+
ta
->
byte_offset
+
offset
;
int16_t
value
=
(
int16_t
)((
ptr
[
0
]
<<
8
)
|
ptr
[
1
]);
return
js_mknum
((
double
)
value
);
}
static
ant_value_t
js_buffer_readInt32BE
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
js_getthis
(
js
));
if
(
!
ta
)
return
js_mkerr
(
js
,
"Invalid Buffer"
);
size_t
offset
=
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
?
(
size_t
)
js_getnum
(
args
[
0
])
:
0
;
if
(
offset
+
4
>
ta
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
uint8_t
*
ptr
=
ta
->
buffer
->
data
+
ta
->
byte_offset
+
offset
;
int32_t
value
=
(
int32_t
)(((
uint32_t
)
ptr
[
0
]
<<
24
)
|
((
uint32_t
)
ptr
[
1
]
<<
16
)
|
((
uint32_t
)
ptr
[
2
]
<<
8
)
|
(
uint32_t
)
ptr
[
3
]);
return
js_mknum
((
double
)
value
);
}
static
ant_value_t
js_buffer_readUInt32BE
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
js_getthis
(
js
));
if
(
!
ta
)
return
js_mkerr
(
js
,
"Invalid Buffer"
);
size_t
offset
=
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
?
(
size_t
)
js_getnum
(
args
[
0
])
:
0
;
if
(
offset
+
4
>
ta
->
byte_length
)
return
js_mkerr
(
js
,
"Offset out of bounds"
);
uint8_t
*
ptr
=
ta
->
buffer
->
data
+
ta
->
byte_offset
+
offset
;
uint32_t
value
=
((
uint32_t
)
ptr
[
0
]
<<
24
)
|
((
uint32_t
)
ptr
[
1
]
<<
16
)
|
((
uint32_t
)
ptr
[
2
]
<<
8
)
|
(
uint32_t
)
ptr
[
3
];
return
js_mknum
((
double
)
value
);
}
// Buffer.isBuffer(obj)
static
ant_value_t
js_buffer_isBuffer
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
if
(
!
is_special_object
(
args
[
0
]))
return
js_false
;
ant_value_t
proto
=
js_get_proto
(
js
,
args
[
0
]);
ant_value_t
buffer_proto
=
js_get_ctor_proto
(
js
,
"Buffer"
,
6
);
return
js_bool
(
proto
==
buffer_proto
);
}
// Buffer.isEncoding(encoding)
static
ant_value_t
js_buffer_isEncoding
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_STR
)
return
js_false
;
size_t
len
;
char
*
enc
=
js_getstr
(
js
,
args
[
0
],
&
len
);
if
((
len
==
4
&&
strncasecmp
(
enc
,
"utf8"
,
4
)
==
0
)
||
(
len
==
5
&&
strncasecmp
(
enc
,
"utf-8"
,
5
)
==
0
)
||
(
len
==
3
&&
strncasecmp
(
enc
,
"hex"
,
3
)
==
0
)
||
(
len
==
6
&&
strncasecmp
(
enc
,
"base64"
,
6
)
==
0
)
||
(
len
==
5
&&
strncasecmp
(
enc
,
"ascii"
,
5
)
==
0
)
||
(
len
==
6
&&
strncasecmp
(
enc
,
"latin1"
,
6
)
==
0
)
||
(
len
==
6
&&
strncasecmp
(
enc
,
"binary"
,
6
)
==
0
)
||
(
len
==
4
&&
strncasecmp
(
enc
,
"ucs2"
,
4
)
==
0
)
||
(
len
==
5
&&
strncasecmp
(
enc
,
"ucs-2"
,
5
)
==
0
)
||
(
len
==
7
&&
strncasecmp
(
enc
,
"utf16le"
,
7
)
==
0
)
||
(
len
==
8
&&
strncasecmp
(
enc
,
"utf-16le"
,
8
)
==
0
))
{
return
js_true
;
}
return
js_false
;
}
// Buffer.byteLength(string, encoding)
static
ant_value_t
js_buffer_byteLength
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mknum
(
0
);
ant_value_t
arg
=
args
[
0
];
if
(
is_special_object
(
arg
))
{
ant_value_t
bytelen
=
js_get
(
js
,
arg
,
"byteLength"
);
if
(
vtype
(
bytelen
)
==
T_NUM
)
return
bytelen
;
ant_value_t
len
=
js_get
(
js
,
arg
,
"length"
);
if
(
vtype
(
len
)
==
T_NUM
)
return
len
;
}
if
(
vtype
(
arg
)
==
T_STR
)
{
size_t
len
;
js_getstr
(
js
,
arg
,
&
len
);
return
js_mknum
((
double
)
len
);
}
return
js_mknum
(
0
);
}
// Buffer.concat(list, totalLength)
static
ant_value_t
js_buffer_concat
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_special_object
(
args
[
0
]))
{
return
js_mkerr
(
js
,
"First argument must be an array"
);
}
ant_value_t
list
=
args
[
0
];
ant_value_t
len_val
=
js_get
(
js
,
list
,
"length"
);
if
(
vtype
(
len_val
)
!=
T_NUM
)
{
return
js_mkerr
(
js
,
"First argument must be an array"
);
}
size_t
list_len
=
(
size_t
)
js_getnum
(
len_val
);
size_t
total_length
=
0
;
if
(
nargs
>
1
&&
vtype
(
args
[
1
])
==
T_NUM
)
{
total_length
=
(
size_t
)
js_getnum
(
args
[
1
]);
}
else
{
for
(
size_t
i
=
0
;
i
<
list_len
;
i
++
)
{
char
idx
[
16
];
snprintf
(
idx
,
sizeof
(
idx
),
"%zu"
,
i
);
ant_value_t
buf
=
js_get
(
js
,
list
,
idx
);
ant_value_t
buf_len
=
js_get
(
js
,
buf
,
"length"
);
if
(
vtype
(
buf_len
)
==
T_NUM
)
total_length
+=
(
size_t
)
js_getnum
(
buf_len
);
}
}
ArrayBufferData
*
buffer
=
create_array_buffer_data
(
total_length
);
if
(
!
buffer
)
return
js_mkerr
(
js
,
"Failed to allocate buffer"
);
size_t
offset
=
0
;
for
(
size_t
i
=
0
;
i
<
list_len
&&
offset
<
total_length
;
i
++
)
{
char
idx
[
16
];
snprintf
(
idx
,
sizeof
(
idx
),
"%zu"
,
i
);
ant_value_t
buf
=
js_get
(
js
,
list
,
idx
);
TypedArrayData
*
ta
=
buffer_get_typedarray_data
(
buf
);
if
(
!
ta
||
!
ta
->
buffer
)
continue
;
size_t
copy_len
=
ta
->
byte_length
;
if
(
offset
+
copy_len
>
total_length
)
{
copy_len
=
total_length
-
offset
;
}
memcpy
(
buffer
->
data
+
offset
,
ta
->
buffer
->
data
+
ta
->
byte_offset
,
copy_len
);
offset
+=
copy_len
;
}
return
create_typed_array
(
js
,
TYPED_ARRAY_UINT8
,
buffer
,
0
,
total_length
,
"Buffer"
);
}
// Buffer.compare(buf1, buf2)
static
ant_value_t
js_buffer_compare
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"Buffer.compare requires two arguments"
);
TypedArrayData
*
ta1
=
buffer_get_typedarray_data
(
args
[
0
]);
TypedArrayData
*
ta2
=
buffer_get_typedarray_data
(
args
[
1
]);
if
(
!
ta1
||
!
ta2
)
{
return
js_mkerr
(
js
,
"Arguments must be Buffers"
);
}
if
(
!
ta1
||
!
ta1
->
buffer
||
!
ta2
||
!
ta2
->
buffer
)
{
return
js_mkerr
(
js
,
"Invalid buffer"
);
}
size_t
len
=
ta1
->
byte_length
<
ta2
->
byte_length
?
ta1
->
byte_length
:
ta2
->
byte_length
;
int
cmp
=
memcmp
(
ta1
->
buffer
->
data
+
ta1
->
byte_offset
,
ta2
->
buffer
->
data
+
ta2
->
byte_offset
,
len
);
if
(
cmp
==
0
)
{
if
(
ta1
->
byte_length
<
ta2
->
byte_length
)
cmp
=
-1
;
else
if
(
ta1
->
byte_length
>
ta2
->
byte_length
)
cmp
=
1
;
}
else
cmp
=
cmp
<
0
?
-1
:
1
;
return
js_mknum
((
double
)
cmp
);
}
static
ant_value_t
js_sharedarraybuffer_constructor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
vtype
(
js
->
new_target
)
==
T_UNDEF
)
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"SharedArrayBuffer constructor requires 'new'"
);
}
size_t
length
=
0
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
{
length
=
(
size_t
)
js_getnum
(
args
[
0
]);
}
ArrayBufferData
*
data
=
create_shared_array_buffer_data
(
length
);
if
(
!
data
)
{
return
js_mkerr
(
js
,
"Failed to allocate SharedArrayBuffer"
);
}
ant_value_t
obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_get_ctor_proto
(
js
,
"SharedArrayBuffer"
,
17
);
if
(
is_special_object
(
proto
))
js_set_proto_init
(
obj
,
proto
);
js_set_native_ptr
(
obj
,
data
);
js_set_native_tag
(
obj
,
BUFFER_ARRAYBUFFER_NATIVE_TAG
);
js_set
(
js
,
obj
,
"byteLength"
,
js_mknum
((
double
)
length
));
js_set_finalizer
(
obj
,
arraybuffer_finalize
);
return
obj
;
}
static
ant_value_t
buffer_make_constants
(
ant_t
*
js
)
{
ant_value_t
constants
=
js_newobj
(
js
);
js_set
(
js
,
constants
,
"MAX_LENGTH"
,
js_mknum
(
BUFFER_COMPAT_MAX_LENGTH
));
js_set
(
js
,
constants
,
"MAX_STRING_LENGTH"
,
js_mknum
(
BUFFER_COMPAT_MAX_STRING_LENGTH
));
return
constants
;
}
ant_value_t
buffer_library
(
ant_t
*
js
)
{
ant_value_t
glob
=
js_glob
(
js
);
ant_value_t
lib
=
js_newobj
(
js
);
js_set
(
js
,
lib
,
"Buffer"
,
js_get
(
js
,
glob
,
"Buffer"
));
js_set
(
js
,
lib
,
"Blob"
,
js_get
(
js
,
glob
,
"Blob"
));
js_set
(
js
,
lib
,
"File"
,
js_get
(
js
,
glob
,
"File"
));
js_set
(
js
,
lib
,
"atob"
,
js_get
(
js
,
glob
,
"atob"
));
js_set
(
js
,
lib
,
"btoa"
,
js_get
(
js
,
glob
,
"btoa"
));
js_set
(
js
,
lib
,
"constants"
,
buffer_make_constants
(
js
));
js_set
(
js
,
lib
,
"kMaxLength"
,
js_mknum
(
BUFFER_COMPAT_MAX_LENGTH
));
js_set
(
js
,
lib
,
"kStringMaxLength"
,
js_mknum
(
BUFFER_COMPAT_MAX_STRING_LENGTH
));
js_set
(
js
,
lib
,
"INSPECT_MAX_BYTES"
,
js_mknum
(
BUFFER_COMPAT_INSPECT_MAX_BYTES
));
return
lib
;
}
void
init_buffer_module
()
{
ant_t
*
js
=
rt
->
js
;
ant_value_t
glob
=
js
->
global
;
ant_value_t
object_proto
=
js
->
sym
.
object_proto
;
ant_value_t
arraybuffer_ctor_obj
=
js_mkobj
(
js
);
ant_value_t
arraybuffer_proto
=
js_mkobj
(
js
);
js_set_proto_init
(
arraybuffer_proto
,
object_proto
);
js_set
(
js
,
arraybuffer_proto
,
"slice"
,
js_mkfun
(
js_arraybuffer_slice
));
js_set
(
js
,
arraybuffer_proto
,
"transfer"
,
js_mkfun
(
js_arraybuffer_transfer
));
js_set
(
js
,
arraybuffer_proto
,
"transferToFixedLength"
,
js_mkfun
(
js_arraybuffer_transferToFixedLength
));
js_set_getter_desc
(
js
,
arraybuffer_proto
,
"detached"
,
8
,
js_mkfun
(
js_arraybuffer_detached_getter
),
JS_DESC_E
);
js_set_getter_desc
(
js
,
arraybuffer_proto
,
"byteLength"
,
10
,
js_mkfun
(
js_arraybuffer_byteLength_getter
),
JS_DESC_C
);
js_set_sym
(
js
,
arraybuffer_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"ArrayBuffer"
,
11
));
js_set_slot
(
arraybuffer_ctor_obj
,
SLOT_CFUNC
,
js_mkfun
(
js_arraybuffer_constructor
));
js_mkprop_fast
(
js
,
arraybuffer_ctor_obj
,
"prototype"
,
9
,
arraybuffer_proto
);
js_mkprop_fast
(
js
,
arraybuffer_ctor_obj
,
"name"
,
4
,
ANT_STRING
(
"ArrayBuffer"
));
js_set_descriptor
(
js
,
arraybuffer_ctor_obj
,
"name"
,
4
,
0
);
js_set
(
js
,
arraybuffer_ctor_obj
,
"isView"
,
js_mkfun
(
js_arraybuffer_isView
));
js_define_species_getter
(
js
,
arraybuffer_ctor_obj
);
ant_value_t
arraybuffer_ctor
=
js_obj_to_func
(
arraybuffer_ctor_obj
);
js_set
(
js
,
arraybuffer_proto
,
"constructor"
,
arraybuffer_ctor
);
js_set_descriptor
(
js
,
arraybuffer_proto
,
"constructor"
,
11
,
JS_DESC_W
|
JS_DESC_C
);
js_set
(
js
,
glob
,
"ArrayBuffer"
,
arraybuffer_ctor
);
ant_value_t
typedarray_proto
=
js_mkobj
(
js
);
js_set_proto_init
(
typedarray_proto
,
object_proto
);
js_set
(
js
,
typedarray_proto
,
"at"
,
js_mkfun
(
js_typedarray_at
));
js_set
(
js
,
typedarray_proto
,
"set"
,
js_mkfun
(
js_typedarray_set
));
js_set
(
js
,
typedarray_proto
,
"copyWithin"
,
js_mkfun
(
js_typedarray_copyWithin
));
js_set
(
js
,
typedarray_proto
,
"slice"
,
js_mkfun
(
js_typedarray_slice
));
js_set
(
js
,
typedarray_proto
,
"subarray"
,
js_mkfun
(
js_typedarray_subarray
));
js_set
(
js
,
typedarray_proto
,
"fill"
,
js_mkfun
(
js_typedarray_fill
));
js_set
(
js
,
typedarray_proto
,
"toReversed"
,
js_mkfun
(
js_typedarray_toReversed
));
js_set
(
js
,
typedarray_proto
,
"toSorted"
,
js_mkfun
(
js_typedarray_toSorted
));
js_set
(
js
,
typedarray_proto
,
"with"
,
js_mkfun
(
js_typedarray_with
));
js_set
(
js
,
typedarray_proto
,
"toString"
,
js_mkfun
(
js_typedarray_toString
));
js_set
(
js
,
typedarray_proto
,
"join"
,
js_mkfun
(
js_typedarray_join
));
js_set
(
js
,
typedarray_proto
,
"indexOf"
,
js_mkfun
(
js_typedarray_indexOf
));
js_set
(
js
,
typedarray_proto
,
"includes"
,
js_mkfun
(
js_typedarray_includes
));
js_set
(
js
,
typedarray_proto
,
"every"
,
js_mkfun
(
js_typedarray_every
));
js_set_sym
(
js
,
typedarray_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"TypedArray"
,
10
));
g_typedarray_iter_proto
=
js_mkobj
(
js
);
js_set_proto_init
(
g_typedarray_iter_proto
,
js
->
sym
.
iterator_proto
);
js_set
(
js
,
g_typedarray_iter_proto
,
"next"
,
js_mkfun
(
ta_iter_next
));
js_iter_register_advance
(
g_typedarray_iter_proto
,
advance_typedarray
);
js_set
(
js
,
typedarray_proto
,
"values"
,
js_mkfun
(
ta_values
));
js_set
(
js
,
typedarray_proto
,
"keys"
,
js_mkfun
(
ta_keys
));
js_set
(
js
,
typedarray_proto
,
"entries"
,
js_mkfun
(
ta_entries
));
js_set_sym
(
js
,
typedarray_proto
,
get_iterator_sym
(),
js_get
(
js
,
typedarray_proto
,
"values"
));
// TODO: find a better way of doing this, macro is code smell
#define SETUP_TYPEDARRAY(name) \
do { \
ant_value_t name##_ctor_obj = js_mkobj(js); \
ant_value_t name##_proto = js_mkobj(js); \
js_set_proto_init(name##_proto, typedarray_proto); \
js_set_sym(js, name##_proto, get_toStringTag_sym(), js_mkstr(js, #name, sizeof(#name) - 1)); \
js_set_slot(name##_ctor_obj, SLOT_CFUNC, js_mkfun(js_##name##_constructor)); \
js_setprop(js, name##_ctor_obj, js_mkstr(js, "prototype", 9), name##_proto); \
js_mkprop_fast(js, name##_ctor_obj, "name", 4, ANT_STRING(#name)); \
js_set_descriptor(js, name##_ctor_obj, "name", 4, 0); \
js_define_species_getter(js, name##_ctor_obj); \
js_set(js, name##_ctor_obj, "from", js_mkfun(js_##name##_from)); \
ant_value_t name##_ctor = js_obj_to_func(name##_ctor_obj); \
js_setprop(js, name##_proto, ANT_STRING("constructor"), name##_ctor); \
js_set_descriptor(js, name##_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); \
js_set(js, glob, #name, name##_ctor); \
} while(0)
SETUP_TYPEDARRAY
(
Int8Array
);
SETUP_TYPEDARRAY
(
Uint8Array
);
SETUP_TYPEDARRAY
(
Uint8ClampedArray
);
SETUP_TYPEDARRAY
(
Int16Array
);
SETUP_TYPEDARRAY
(
Uint16Array
);
SETUP_TYPEDARRAY
(
Int32Array
);
SETUP_TYPEDARRAY
(
Uint32Array
);
SETUP_TYPEDARRAY
(
Float16Array
);
SETUP_TYPEDARRAY
(
Float32Array
);
SETUP_TYPEDARRAY
(
Float64Array
);
SETUP_TYPEDARRAY
(
BigInt64Array
);
SETUP_TYPEDARRAY
(
BigUint64Array
);
ant_value_t
uint8array_codec_ctor
=
js_get
(
js
,
glob
,
"Uint8Array"
);
ant_value_t
uint8array_codec_proto
=
js_get
(
js
,
uint8array_codec_ctor
,
"prototype"
);
js_set
(
js
,
uint8array_codec_ctor
,
"fromHex"
,
js_mkfun
(
js_uint8array_fromHex
));
js_set
(
js
,
uint8array_codec_ctor
,
"fromBase64"
,
js_mkfun
(
js_uint8array_fromBase64
));
js_set
(
js
,
uint8array_codec_proto
,
"toHex"
,
js_mkfun
(
js_uint8array_toHex
));
js_set
(
js
,
uint8array_codec_proto
,
"toBase64"
,
js_mkfun
(
js_uint8array_toBase64
));
js_set
(
js
,
uint8array_codec_proto
,
"setFromHex"
,
js_mkfun
(
js_uint8array_setFromHex
));
js_set
(
js
,
uint8array_codec_proto
,
"setFromBase64"
,
js_mkfun
(
js_uint8array_setFromBase64
));
ant_value_t
dataview_ctor_obj
=
js_mkobj
(
js
);
ant_value_t
dataview_proto
=
js_mkobj
(
js
);
js_set_proto_init
(
dataview_proto
,
object_proto
);
js_set
(
js
,
dataview_proto
,
"getInt8"
,
js_mkfun
(
js_dataview_getInt8
));
js_set
(
js
,
dataview_proto
,
"setInt8"
,
js_mkfun
(
js_dataview_setInt8
));
js_set
(
js
,
dataview_proto
,
"getUint8"
,
js_mkfun
(
js_dataview_getUint8
));
js_set
(
js
,
dataview_proto
,
"setUint8"
,
js_mkfun
(
js_dataview_setUint8
));
js_set
(
js
,
dataview_proto
,
"getInt16"
,
js_mkfun
(
js_dataview_getInt16
));
js_set
(
js
,
dataview_proto
,
"setInt16"
,
js_mkfun
(
js_dataview_setInt16
));
js_set
(
js
,
dataview_proto
,
"getUint16"
,
js_mkfun
(
js_dataview_getUint16
));
js_set
(
js
,
dataview_proto
,
"setUint16"
,
js_mkfun
(
js_dataview_setUint16
));
js_set
(
js
,
dataview_proto
,
"getInt32"
,
js_mkfun
(
js_dataview_getInt32
));
js_set
(
js
,
dataview_proto
,
"setInt32"
,
js_mkfun
(
js_dataview_setInt32
));
js_set
(
js
,
dataview_proto
,
"getUint32"
,
js_mkfun
(
js_dataview_getUint32
));
js_set
(
js
,
dataview_proto
,
"setUint32"
,
js_mkfun
(
js_dataview_setUint32
));
js_set
(
js
,
dataview_proto
,
"getFloat32"
,
js_mkfun
(
js_dataview_getFloat32
));
js_set
(
js
,
dataview_proto
,
"setFloat32"
,
js_mkfun
(
js_dataview_setFloat32
));
js_set
(
js
,
dataview_proto
,
"getFloat64"
,
js_mkfun
(
js_dataview_getFloat64
));
js_set
(
js
,
dataview_proto
,
"setFloat64"
,
js_mkfun
(
js_dataview_setFloat64
));
js_set
(
js
,
dataview_proto
,
"getBigInt64"
,
js_mkfun
(
js_dataview_getBigInt64
));
js_set
(
js
,
dataview_proto
,
"setBigInt64"
,
js_mkfun
(
js_dataview_setBigInt64
));
js_set
(
js
,
dataview_proto
,
"getBigUint64"
,
js_mkfun
(
js_dataview_getBigUint64
));
js_set
(
js
,
dataview_proto
,
"setBigUint64"
,
js_mkfun
(
js_dataview_setBigUint64
));
js_set_sym
(
js
,
dataview_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"DataView"
,
8
));
js_set_slot
(
dataview_ctor_obj
,
SLOT_CFUNC
,
js_mkfun
(
js_dataview_constructor
));
js_mkprop_fast
(
js
,
dataview_ctor_obj
,
"prototype"
,
9
,
dataview_proto
);
js_mkprop_fast
(
js
,
dataview_ctor_obj
,
"name"
,
4
,
ANT_STRING
(
"DataView"
));
js_set_descriptor
(
js
,
dataview_ctor_obj
,
"name"
,
4
,
0
);
ant_value_t
dataview_ctor
=
js_obj_to_func
(
dataview_ctor_obj
);
js_set
(
js
,
dataview_proto
,
"constructor"
,
dataview_ctor
);
js_set_descriptor
(
js
,
dataview_proto
,
"constructor"
,
11
,
JS_DESC_W
|
JS_DESC_C
);
js_set
(
js
,
glob
,
"DataView"
,
dataview_ctor
);
ant_value_t
sharedarraybuffer_ctor_obj
=
js_mkobj
(
js
);
ant_value_t
sharedarraybuffer_proto
=
js_mkobj
(
js
);
js_set_proto_init
(
sharedarraybuffer_proto
,
object_proto
);
js_set
(
js
,
sharedarraybuffer_proto
,
"slice"
,
js_mkfun
(
js_arraybuffer_slice
));
js_set_getter_desc
(
js
,
sharedarraybuffer_proto
,
"byteLength"
,
10
,
js_mkfun
(
js_arraybuffer_byteLength_getter
),
JS_DESC_C
);
js_set_sym
(
js
,
sharedarraybuffer_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"SharedArrayBuffer"
,
17
));
js_set_slot
(
sharedarraybuffer_ctor_obj
,
SLOT_CFUNC
,
js_mkfun
(
js_sharedarraybuffer_constructor
));
js_mkprop_fast
(
js
,
sharedarraybuffer_ctor_obj
,
"prototype"
,
9
,
sharedarraybuffer_proto
);
js_mkprop_fast
(
js
,
sharedarraybuffer_ctor_obj
,
"name"
,
4
,
ANT_STRING
(
"SharedArrayBuffer"
));
js_set_descriptor
(
js
,
sharedarraybuffer_ctor_obj
,
"name"
,
4
,
0
);
js_define_species_getter
(
js
,
sharedarraybuffer_ctor_obj
);
ant_value_t
sharedarraybuffer_ctor
=
js_obj_to_func
(
sharedarraybuffer_ctor_obj
);
js_set
(
js
,
sharedarraybuffer_proto
,
"constructor"
,
sharedarraybuffer_ctor
);
js_set_descriptor
(
js
,
sharedarraybuffer_proto
,
"constructor"
,
11
,
JS_DESC_W
|
JS_DESC_C
);
js_set
(
js
,
glob
,
"SharedArrayBuffer"
,
sharedarraybuffer_ctor
);
ant_value_t
buffer_ctor_obj
=
js_mkobj
(
js
);
ant_value_t
buffer_proto
=
js_mkobj
(
js
);
ant_value_t
uint8array_ctor
=
js_get
(
js
,
glob
,
"Uint8Array"
);
ant_value_t
uint8array_proto
=
js_get
(
js
,
uint8array_ctor
,
"prototype"
);
if
(
is_special_object
(
uint8array_proto
))
js_set_proto_init
(
buffer_proto
,
uint8array_proto
);
else
js_set_proto_init
(
buffer_proto
,
typedarray_proto
);
js_set
(
js
,
buffer_proto
,
"slice"
,
js_mkfun
(
js_buffer_slice
));
js_set
(
js
,
buffer_proto
,
"toString"
,
js_mkfun
(
js_buffer_toString
));
js_set
(
js
,
buffer_proto
,
"toBase64"
,
js_mkfun
(
js_buffer_toBase64
));
js_set
(
js
,
buffer_proto
,
"write"
,
js_mkfun
(
js_buffer_write
));
js_set
(
js
,
buffer_proto
,
"copy"
,
js_mkfun
(
js_buffer_copy
));
js_set
(
js
,
buffer_proto
,
"writeInt16BE"
,
js_mkfun
(
js_buffer_writeInt16BE
));
js_set
(
js
,
buffer_proto
,
"writeInt32BE"
,
js_mkfun
(
js_buffer_writeInt32BE
));
js_set
(
js
,
buffer_proto
,
"writeUInt32BE"
,
js_mkfun
(
js_buffer_writeUInt32BE
));
js_set
(
js
,
buffer_proto
,
"readInt16BE"
,
js_mkfun
(
js_buffer_readInt16BE
));
js_set
(
js
,
buffer_proto
,
"readInt32BE"
,
js_mkfun
(
js_buffer_readInt32BE
));
js_set
(
js
,
buffer_proto
,
"readUInt32BE"
,
js_mkfun
(
js_buffer_readUInt32BE
));
js_set_sym
(
js
,
buffer_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"Buffer"
,
6
));
js_set
(
js
,
buffer_proto
,
"values"
,
js_get
(
js
,
typedarray_proto
,
"values"
));
js_set_sym
(
js
,
buffer_proto
,
get_iterator_sym
(),
js_get
(
js
,
buffer_proto
,
"values"
));
js_set
(
js
,
buffer_ctor_obj
,
"from"
,
js_mkfun
(
js_buffer_from
));
js_set
(
js
,
buffer_ctor_obj
,
"alloc"
,
js_mkfun
(
js_buffer_alloc
));
js_set
(
js
,
buffer_ctor_obj
,
"allocUnsafe"
,
js_mkfun
(
js_buffer_allocUnsafe
));
js_set
(
js
,
buffer_ctor_obj
,
"isBuffer"
,
js_mkfun
(
js_buffer_isBuffer
));
js_set
(
js
,
buffer_ctor_obj
,
"isEncoding"
,
js_mkfun
(
js_buffer_isEncoding
));
js_set
(
js
,
buffer_ctor_obj
,
"byteLength"
,
js_mkfun
(
js_buffer_byteLength
));
js_set
(
js
,
buffer_ctor_obj
,
"concat"
,
js_mkfun
(
js_buffer_concat
));
js_set
(
js
,
buffer_ctor_obj
,
"compare"
,
js_mkfun
(
js_buffer_compare
));
js_set_slot
(
buffer_ctor_obj
,
SLOT_CFUNC
,
js_mkfun
(
js_buffer_from
));
js_mkprop_fast
(
js
,
buffer_ctor_obj
,
"prototype"
,
9
,
buffer_proto
);
js_mkprop_fast
(
js
,
buffer_ctor_obj
,
"name"
,
4
,
ANT_STRING
(
"Buffer"
));
js_set_descriptor
(
js
,
buffer_ctor_obj
,
"name"
,
4
,
0
);
ant_value_t
buffer_ctor
=
js_obj_to_func
(
buffer_ctor_obj
);
js_set
(
js
,
buffer_proto
,
"constructor"
,
buffer_ctor
);
js_set_descriptor
(
js
,
buffer_proto
,
"constructor"
,
11
,
JS_DESC_W
|
JS_DESC_C
);
js_set
(
js
,
glob
,
"Buffer"
,
buffer_ctor
);
}
void
cleanup_buffer_module
(
void
)
{
if
(
buffer_registry
)
{
for
(
size_t
i
=
0
;
i
<
buffer_registry_count
;
i
++
)
{
if
(
buffer_registry
[
i
])
free
(
buffer_registry
[
i
]);
}
free
(
buffer_registry
);
buffer_registry
=
NULL
;
buffer_registry_count
=
0
;
buffer_registry_cap
=
0
;
}
ta_metadata_bytes
=
0
;
}
size_t
buffer_get_external_memory
(
void
)
{
size_t
total
=
ta_metadata_bytes
;
for
(
size_t
i
=
0
;
i
<
buffer_registry_count
;
i
++
)
{
if
(
buffer_registry
[
i
])
total
+=
sizeof
(
ArrayBufferData
)
+
buffer_registry
[
i
]
->
capacity
;
}
total
+=
buffer_registry_cap
*
sizeof
(
ArrayBufferData
*
);
return
total
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 2, 7:56 AM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
543752
Default Alt Text
buffer.c (118 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment