Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add File interface #181

Merged
merged 13 commits into from
Jan 10, 2025
75 changes: 56 additions & 19 deletions builtins/web/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ namespace blob {

using js::Vector;

#define DEFINE_BLOB_METHOD(name) \
bool Blob::name(JSContext *cx, unsigned argc, JS::Value *vp) { \
METHOD_HEADER(0) \
return name(cx, self, args.rval()); \
}

#define DEFINE_BLOB_METHOD_W_ARGS(name) \
bool Blob::name(JSContext *cx, unsigned argc, JS::Value *vp) { \
METHOD_HEADER(0) \
return name(cx, self, args, args.rval()); \
}

const JSFunctionSpec Blob::static_methods[] = {
JS_FS_END,
};
Expand Down Expand Up @@ -269,15 +281,19 @@ JSObject *Blob::data_to_owned_array_buffer(JSContext *cx, HandleObject self, siz
return array_buffer;
}

bool Blob::arrayBuffer(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)
DEFINE_BLOB_METHOD(arrayBuffer)
DEFINE_BLOB_METHOD(bytes)
DEFINE_BLOB_METHOD(stream)
DEFINE_BLOB_METHOD(text)
DEFINE_BLOB_METHOD_W_ARGS(slice)
tschneidereit marked this conversation as resolved.
Show resolved Hide resolved

bool Blob::arrayBuffer(JSContext *cx, HandleObject self, MutableHandleValue rval) {
JS::RootedObject promise(cx, JS::NewPromiseObject(cx, nullptr));
if (!promise) {
return false;
}

args.rval().setObject(*promise);
rval.setObject(*promise);

auto buffer = data_to_owned_array_buffer(cx, self);
if (!buffer) {
Expand All @@ -291,15 +307,13 @@ bool Blob::arrayBuffer(JSContext *cx, unsigned argc, JS::Value *vp) {
return true;
}

bool Blob::bytes(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)

bool Blob::bytes(JSContext *cx, HandleObject self, MutableHandleValue rval) {
JS::RootedObject promise(cx, JS::NewPromiseObject(cx, nullptr));
if (!promise) {
return false;
}

args.rval().setObject(*promise);
rval.setObject(*promise);

JS::RootedObject buffer(cx, data_to_owned_array_buffer(cx, self));
if (!buffer) {
Expand All @@ -319,9 +333,7 @@ bool Blob::bytes(JSContext *cx, unsigned argc, JS::Value *vp) {
return true;
}

bool Blob::slice(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)

bool Blob::slice(JSContext *cx, HandleObject self, const CallArgs &args, MutableHandleValue rval) {
auto src = Blob::blob(self);
int64_t size = src->length();
int64_t start = 0;
Expand Down Expand Up @@ -366,13 +378,11 @@ bool Blob::slice(JSContext *cx, unsigned argc, JS::Value *vp) {
return false;
}

args.rval().setObject(*new_blob);
rval.setObject(*new_blob);
return true;
}

bool Blob::stream(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)

bool Blob::stream(JSContext *cx, HandleObject self, MutableHandleValue rval) {
auto native_stream = streams::NativeStreamSource::create(cx, self, JS::UndefinedHandleValue,
stream_pull, stream_cancel);

Expand All @@ -394,19 +404,17 @@ bool Blob::stream(JSContext *cx, unsigned argc, JS::Value *vp) {
return false;
}

args.rval().setObject(*stream);
rval.setObject(*stream);
return true;
}

bool Blob::text(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)

bool Blob::text(JSContext *cx, HandleObject self, MutableHandleValue rval) {
JS::RootedObject promise(cx, JS::NewPromiseObject(cx, nullptr));
if (!promise) {
return false;
}

args.rval().setObject(*promise);
rval.setObject(*promise);

auto src = Blob::blob(self);
auto encoding = const_cast<jsencoding::Encoding *>(jsencoding::encoding_for_label_no_replacement(
Expand Down Expand Up @@ -672,6 +680,35 @@ JSObject *Blob::create(JSContext *cx, UniqueChars data, size_t data_len, HandleS
return self;
}

JSObject *Blob::create(JSContext *cx, HandleValue blobParts, HandleValue opts) {
RootedObject self(cx, JS_NewObjectWithGivenProto(cx, &class_, proto_obj));

if (!self) {
return nullptr;
}

SetReservedSlot(self, static_cast<uint32_t>(Slots::Type), JS_GetEmptyStringValue(cx));
SetReservedSlot(self, static_cast<uint32_t>(Slots::Endings), JS::Int32Value(LineEndings::Transparent));
SetReservedSlot(self, static_cast<uint32_t>(Slots::Data), JS::PrivateValue(new ByteBuffer));
SetReservedSlot(self, static_cast<uint32_t>(Slots::Readers), JS::PrivateValue(new ReadersMap));

if (blobParts.isNull()) {
api::throw_error(cx, api::Errors::TypeError, "Blob.constructor", "blobParts", "be an object");
return nullptr;
}

// Walk the blob parts and append them to the blob's buffer.
if (!blobParts.isUndefined() && !init_blob_parts(cx, self, blobParts)) {
return nullptr;
}

if (!opts.isNullOrUndefined() && !init_options(cx, self, opts)) {
return nullptr;
}

return self;
}

bool Blob::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
CTOR_HEADER("Blob", 0);

Expand Down
8 changes: 8 additions & 0 deletions builtins/web/blob.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ class Blob : public TraceableBuiltinImpl<Blob> {
using ByteBuffer = js::Vector<uint8_t, 0, js::SystemAllocPolicy>;
using ReadersMap = JS::GCHashMap<HeapObj, BlobReader, js::StableCellHasher<HeapObj>, js::SystemAllocPolicy>;

static bool arrayBuffer(JSContext *cx, HandleObject self, MutableHandleValue rval);
static bool bytes(JSContext *cx, HandleObject self, MutableHandleValue rval);
static bool stream(JSContext *cx, HandleObject self, MutableHandleValue rval);
static bool text(JSContext *cx, HandleObject self, MutableHandleValue rval);
static bool slice(JSContext *cx, HandleObject self, const CallArgs &args, MutableHandleValue rval);

static ReadersMap *readers(JSObject *self);
static ByteBuffer *blob(JSObject *self);
static size_t blob_size(JSObject *self);
Expand All @@ -75,7 +81,9 @@ class Blob : public TraceableBuiltinImpl<Blob> {
static JSObject *data_to_owned_array_buffer(JSContext *cx, HandleObject self);
static JSObject *data_to_owned_array_buffer(JSContext *cx, HandleObject self, size_t offset,
size_t size, size_t *bytes_read);

static JSObject *create(JSContext *cx, UniqueChars data, size_t data_len, HandleString type);
static JSObject *create(JSContext *cx, HandleValue blobParts, HandleValue opts);

static bool init_class(JSContext *cx, HandleObject global);
static bool constructor(JSContext *cx, unsigned argc, Value *vp);
Expand Down
2 changes: 1 addition & 1 deletion builtins/web/fetch/request-response.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ bool RequestOrResponse::extract_body(JSContext *cx, JS::HandleObject self,

if (Blob::is_instance(body_obj)) {
RootedValue stream(cx);
if (!Call(cx, body_obj, "stream", HandleValueArray::empty(), &stream)) {
if (!Blob::stream(cx, body_obj, &stream)) {
return false;
}

Expand Down
Loading
Loading