#include "node_blob.h"
#include "ada.h"
#include "async_wrap-inl.h"
#include "base_object-inl.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "node_bob-inl.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "node_file.h"
#include "permission/permission.h"
#include "util.h"
#include "v8.h"
#include
namespace node {
using v8::Array;
using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::BackingStore;
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Global;
using v8::HandleScope;
using v8::Int32;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::ObjectTemplate;
using v8::String;
using v8::Uint32;
using v8::Undefined;
using v8::Value;
namespace {
// Concatenate multiple ArrayBufferView/ArrayBuffers into a single ArrayBuffer.
// This method treats all ArrayBufferView types the same.
void Concat(const FunctionCallbackInfo& args) {
Isolate* isolate = args.GetIsolate();
Local context = isolate->GetCurrentContext();
Environment* env = Environment::GetCurrent(context);
CHECK(args[0]->IsArray());
Local array = args[0].As();
struct View {
std::shared_ptr store;
size_t length;
size_t offset = 0;
};
std::vector views;
size_t total = 0;
std::vector> buffers;
if (FromV8Array(context, array, &buffers).IsNothing()) {
return;
}
size_t count = buffers.size();
for (uint32_t i = 0; i < count; i++) {
Local val = buffers[i].Get(isolate);
if (val->IsArrayBuffer()) {
auto ab = val.As();
views.push_back(View{ab->GetBackingStore(), ab->ByteLength(), 0});
total += ab->ByteLength();
} else {
CHECK(val->IsArrayBufferView());
auto view = val.As();
views.push_back(View{view->Buffer()->GetBackingStore(),
view->ByteLength(),
view->ByteOffset()});
total += view->ByteLength();
}
}
std::shared_ptr store =
ArrayBuffer::NewBackingStore(env->isolate(), total);
uint8_t* ptr = static_cast(store->Data());
for (size_t n = 0; n < views.size(); n++) {
uint8_t* from =
static_cast(views[n].store->Data()) + views[n].offset;
std::copy(from, from + views[n].length, ptr);
ptr += views[n].length;
}
args.GetReturnValue().Set(ArrayBuffer::New(env->isolate(), std::move(store)));
}
void BlobFromFilePath(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
auto entry = DataQueue::CreateFdEntry(env, args[0]);
if (entry == nullptr) {
return THROW_ERR_INVALID_ARG_VALUE(env, "Unable to open file as blob");
}
std::vector> entries;
entries.push_back(std::move(entry));
auto blob =
Blob::Create(env, DataQueue::CreateIdempotent(std::move(entries)));
if (blob) {
auto array = Array::New(env->isolate(), 2);
USE(array->Set(env->context(), 0, blob->object()));
USE(array->Set(env->context(),
1,
Uint32::NewFromUnsigned(env->isolate(), blob->length())));
args.GetReturnValue().Set(array);
}
}
} // namespace
void Blob::CreatePerIsolateProperties(IsolateData* isolate_data,
Local target) {
Isolate* isolate = isolate_data->isolate();
SetMethod(isolate, target, "createBlob", New);
SetMethod(isolate, target, "storeDataObject", StoreDataObject);
SetMethod(isolate, target, "getDataObject", GetDataObject);
SetMethod(isolate, target, "revokeObjectURL", RevokeObjectURL);
SetMethod(isolate, target, "concat", Concat);
SetMethod(isolate, target, "createBlobFromFilePath", BlobFromFilePath);
}
void Blob::CreatePerContextProperties(Local