11cb0ef41Sopenharmony_ci#include "node_blob.h"
21cb0ef41Sopenharmony_ci#include "async_wrap-inl.h"
31cb0ef41Sopenharmony_ci#include "base_object-inl.h"
41cb0ef41Sopenharmony_ci#include "env-inl.h"
51cb0ef41Sopenharmony_ci#include "memory_tracker-inl.h"
61cb0ef41Sopenharmony_ci#include "node_errors.h"
71cb0ef41Sopenharmony_ci#include "node_external_reference.h"
81cb0ef41Sopenharmony_ci#include "threadpoolwork-inl.h"
91cb0ef41Sopenharmony_ci#include "v8.h"
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#include <algorithm>
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cinamespace node {
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ciusing v8::Array;
161cb0ef41Sopenharmony_ciusing v8::ArrayBuffer;
171cb0ef41Sopenharmony_ciusing v8::ArrayBufferView;
181cb0ef41Sopenharmony_ciusing v8::BackingStore;
191cb0ef41Sopenharmony_ciusing v8::Context;
201cb0ef41Sopenharmony_ciusing v8::EscapableHandleScope;
211cb0ef41Sopenharmony_ciusing v8::Function;
221cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo;
231cb0ef41Sopenharmony_ciusing v8::FunctionTemplate;
241cb0ef41Sopenharmony_ciusing v8::HandleScope;
251cb0ef41Sopenharmony_ciusing v8::Isolate;
261cb0ef41Sopenharmony_ciusing v8::Local;
271cb0ef41Sopenharmony_ciusing v8::MaybeLocal;
281cb0ef41Sopenharmony_ciusing v8::Number;
291cb0ef41Sopenharmony_ciusing v8::Object;
301cb0ef41Sopenharmony_ciusing v8::String;
311cb0ef41Sopenharmony_ciusing v8::Uint32;
321cb0ef41Sopenharmony_ciusing v8::Undefined;
331cb0ef41Sopenharmony_ciusing v8::Value;
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_civoid Blob::Initialize(
361cb0ef41Sopenharmony_ci    Local<Object> target,
371cb0ef41Sopenharmony_ci    Local<Value> unused,
381cb0ef41Sopenharmony_ci    Local<Context> context,
391cb0ef41Sopenharmony_ci    void* priv) {
401cb0ef41Sopenharmony_ci  Realm* realm = Realm::GetCurrent(context);
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  BlobBindingData* const binding_data =
431cb0ef41Sopenharmony_ci      realm->AddBindingData<BlobBindingData>(context, target);
441cb0ef41Sopenharmony_ci  if (binding_data == nullptr) return;
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci  SetMethod(context, target, "createBlob", New);
471cb0ef41Sopenharmony_ci  SetMethod(context, target, "storeDataObject", StoreDataObject);
481cb0ef41Sopenharmony_ci  SetMethod(context, target, "getDataObject", GetDataObject);
491cb0ef41Sopenharmony_ci  SetMethod(context, target, "revokeDataObject", RevokeDataObject);
501cb0ef41Sopenharmony_ci  FixedSizeBlobCopyJob::Initialize(realm->env(), target);
511cb0ef41Sopenharmony_ci}
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ciLocal<FunctionTemplate> Blob::GetConstructorTemplate(Environment* env) {
541cb0ef41Sopenharmony_ci  Local<FunctionTemplate> tmpl = env->blob_constructor_template();
551cb0ef41Sopenharmony_ci  if (tmpl.IsEmpty()) {
561cb0ef41Sopenharmony_ci    Isolate* isolate = env->isolate();
571cb0ef41Sopenharmony_ci    tmpl = NewFunctionTemplate(isolate, nullptr);
581cb0ef41Sopenharmony_ci    tmpl->InstanceTemplate()->SetInternalFieldCount(
591cb0ef41Sopenharmony_ci        BaseObject::kInternalFieldCount);
601cb0ef41Sopenharmony_ci    tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
611cb0ef41Sopenharmony_ci    tmpl->SetClassName(
621cb0ef41Sopenharmony_ci        FIXED_ONE_BYTE_STRING(env->isolate(), "Blob"));
631cb0ef41Sopenharmony_ci    SetProtoMethod(isolate, tmpl, "toArrayBuffer", ToArrayBuffer);
641cb0ef41Sopenharmony_ci    SetProtoMethod(isolate, tmpl, "slice", ToSlice);
651cb0ef41Sopenharmony_ci    env->set_blob_constructor_template(tmpl);
661cb0ef41Sopenharmony_ci  }
671cb0ef41Sopenharmony_ci  return tmpl;
681cb0ef41Sopenharmony_ci}
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_cibool Blob::HasInstance(Environment* env, v8::Local<v8::Value> object) {
711cb0ef41Sopenharmony_ci  return GetConstructorTemplate(env)->HasInstance(object);
721cb0ef41Sopenharmony_ci}
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ciBaseObjectPtr<Blob> Blob::Create(Environment* env,
751cb0ef41Sopenharmony_ci                                 const std::vector<BlobEntry>& store,
761cb0ef41Sopenharmony_ci                                 size_t length) {
771cb0ef41Sopenharmony_ci  HandleScope scope(env->isolate());
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  Local<Function> ctor;
801cb0ef41Sopenharmony_ci  if (!GetConstructorTemplate(env)->GetFunction(env->context()).ToLocal(&ctor))
811cb0ef41Sopenharmony_ci    return BaseObjectPtr<Blob>();
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  Local<Object> obj;
841cb0ef41Sopenharmony_ci  if (!ctor->NewInstance(env->context()).ToLocal(&obj))
851cb0ef41Sopenharmony_ci    return BaseObjectPtr<Blob>();
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  return MakeBaseObject<Blob>(env, obj, store, length);
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_civoid Blob::New(const FunctionCallbackInfo<Value>& args) {
911cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
921cb0ef41Sopenharmony_ci  CHECK(args[0]->IsArray());  // sources
931cb0ef41Sopenharmony_ci  CHECK(args[1]->IsUint32());  // length
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  std::vector<BlobEntry> entries;
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  size_t length = args[1].As<Uint32>()->Value();
981cb0ef41Sopenharmony_ci  size_t len = 0;
991cb0ef41Sopenharmony_ci  Local<Array> ary = args[0].As<Array>();
1001cb0ef41Sopenharmony_ci  for (size_t n = 0; n < ary->Length(); n++) {
1011cb0ef41Sopenharmony_ci    Local<Value> entry;
1021cb0ef41Sopenharmony_ci    if (!ary->Get(env->context(), n).ToLocal(&entry))
1031cb0ef41Sopenharmony_ci      return;
1041cb0ef41Sopenharmony_ci    CHECK(entry->IsArrayBufferView() || Blob::HasInstance(env, entry));
1051cb0ef41Sopenharmony_ci    if (entry->IsArrayBufferView()) {
1061cb0ef41Sopenharmony_ci      Local<ArrayBufferView> view = entry.As<ArrayBufferView>();
1071cb0ef41Sopenharmony_ci      CHECK_EQ(view->ByteOffset(), 0);
1081cb0ef41Sopenharmony_ci      std::shared_ptr<BackingStore> store = view->Buffer()->GetBackingStore();
1091cb0ef41Sopenharmony_ci      size_t byte_length = view->ByteLength();
1101cb0ef41Sopenharmony_ci      view->Buffer()->Detach();  // The Blob will own the backing store now.
1111cb0ef41Sopenharmony_ci      entries.emplace_back(BlobEntry{std::move(store), byte_length, 0});
1121cb0ef41Sopenharmony_ci      len += byte_length;
1131cb0ef41Sopenharmony_ci    } else {
1141cb0ef41Sopenharmony_ci      Blob* blob;
1151cb0ef41Sopenharmony_ci      ASSIGN_OR_RETURN_UNWRAP(&blob, entry);
1161cb0ef41Sopenharmony_ci      auto source = blob->entries();
1171cb0ef41Sopenharmony_ci      entries.insert(entries.end(), source.begin(), source.end());
1181cb0ef41Sopenharmony_ci      len += blob->length();
1191cb0ef41Sopenharmony_ci    }
1201cb0ef41Sopenharmony_ci  }
1211cb0ef41Sopenharmony_ci  CHECK_EQ(length, len);
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  BaseObjectPtr<Blob> blob = Create(env, entries, length);
1241cb0ef41Sopenharmony_ci  if (blob)
1251cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(blob->object());
1261cb0ef41Sopenharmony_ci}
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_civoid Blob::ToArrayBuffer(const FunctionCallbackInfo<Value>& args) {
1291cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
1301cb0ef41Sopenharmony_ci  Blob* blob;
1311cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&blob, args.Holder());
1321cb0ef41Sopenharmony_ci  Local<Value> ret;
1331cb0ef41Sopenharmony_ci  if (blob->GetArrayBuffer(env).ToLocal(&ret))
1341cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(ret);
1351cb0ef41Sopenharmony_ci}
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_civoid Blob::ToSlice(const FunctionCallbackInfo<Value>& args) {
1381cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
1391cb0ef41Sopenharmony_ci  Blob* blob;
1401cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&blob, args.Holder());
1411cb0ef41Sopenharmony_ci  CHECK(args[0]->IsUint32());
1421cb0ef41Sopenharmony_ci  CHECK(args[1]->IsUint32());
1431cb0ef41Sopenharmony_ci  size_t start = args[0].As<Uint32>()->Value();
1441cb0ef41Sopenharmony_ci  size_t end = args[1].As<Uint32>()->Value();
1451cb0ef41Sopenharmony_ci  BaseObjectPtr<Blob> slice = blob->Slice(env, start, end);
1461cb0ef41Sopenharmony_ci  if (slice)
1471cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(slice->object());
1481cb0ef41Sopenharmony_ci}
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_civoid Blob::MemoryInfo(MemoryTracker* tracker) const {
1511cb0ef41Sopenharmony_ci  tracker->TrackFieldWithSize("store", length_);
1521cb0ef41Sopenharmony_ci}
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ciMaybeLocal<Value> Blob::GetArrayBuffer(Environment* env) {
1551cb0ef41Sopenharmony_ci  EscapableHandleScope scope(env->isolate());
1561cb0ef41Sopenharmony_ci  size_t len = length();
1571cb0ef41Sopenharmony_ci  std::shared_ptr<BackingStore> store =
1581cb0ef41Sopenharmony_ci      ArrayBuffer::NewBackingStore(env->isolate(), len);
1591cb0ef41Sopenharmony_ci  if (len > 0) {
1601cb0ef41Sopenharmony_ci    unsigned char* dest = static_cast<unsigned char*>(store->Data());
1611cb0ef41Sopenharmony_ci    size_t total = 0;
1621cb0ef41Sopenharmony_ci    for (const auto& entry : entries()) {
1631cb0ef41Sopenharmony_ci      unsigned char* src = static_cast<unsigned char*>(entry.store->Data());
1641cb0ef41Sopenharmony_ci      src += entry.offset;
1651cb0ef41Sopenharmony_ci      memcpy(dest, src, entry.length);
1661cb0ef41Sopenharmony_ci      dest += entry.length;
1671cb0ef41Sopenharmony_ci      total += entry.length;
1681cb0ef41Sopenharmony_ci      CHECK_LE(total, len);
1691cb0ef41Sopenharmony_ci    }
1701cb0ef41Sopenharmony_ci  }
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci  return scope.Escape(ArrayBuffer::New(env->isolate(), store));
1731cb0ef41Sopenharmony_ci}
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ciBaseObjectPtr<Blob> Blob::Slice(Environment* env, size_t start, size_t end) {
1761cb0ef41Sopenharmony_ci  CHECK_LE(start, length());
1771cb0ef41Sopenharmony_ci  CHECK_LE(end, length());
1781cb0ef41Sopenharmony_ci  CHECK_LE(start, end);
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci  std::vector<BlobEntry> slices;
1811cb0ef41Sopenharmony_ci  size_t total = end - start;
1821cb0ef41Sopenharmony_ci  size_t remaining = total;
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci  if (total == 0) return Create(env, slices, 0);
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  for (const auto& entry : entries()) {
1871cb0ef41Sopenharmony_ci    if (start + entry.offset > entry.store->ByteLength()) {
1881cb0ef41Sopenharmony_ci      start -= entry.length;
1891cb0ef41Sopenharmony_ci      continue;
1901cb0ef41Sopenharmony_ci    }
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_ci    size_t offset = entry.offset + start;
1931cb0ef41Sopenharmony_ci    size_t len = std::min(remaining, entry.store->ByteLength() - offset);
1941cb0ef41Sopenharmony_ci    slices.emplace_back(BlobEntry{entry.store, len, offset});
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci    remaining -= len;
1971cb0ef41Sopenharmony_ci    start = 0;
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci    if (remaining == 0)
2001cb0ef41Sopenharmony_ci      break;
2011cb0ef41Sopenharmony_ci  }
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci  return Create(env, slices, total);
2041cb0ef41Sopenharmony_ci}
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ciBlob::Blob(
2071cb0ef41Sopenharmony_ci    Environment* env,
2081cb0ef41Sopenharmony_ci    v8::Local<v8::Object> obj,
2091cb0ef41Sopenharmony_ci    const std::vector<BlobEntry>& store,
2101cb0ef41Sopenharmony_ci    size_t length)
2111cb0ef41Sopenharmony_ci    : BaseObject(env, obj),
2121cb0ef41Sopenharmony_ci      store_(store),
2131cb0ef41Sopenharmony_ci      length_(length) {
2141cb0ef41Sopenharmony_ci  MakeWeak();
2151cb0ef41Sopenharmony_ci}
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ciBaseObjectPtr<BaseObject>
2181cb0ef41Sopenharmony_ciBlob::BlobTransferData::Deserialize(
2191cb0ef41Sopenharmony_ci    Environment* env,
2201cb0ef41Sopenharmony_ci    Local<Context> context,
2211cb0ef41Sopenharmony_ci    std::unique_ptr<worker::TransferData> self) {
2221cb0ef41Sopenharmony_ci  if (context != env->context()) {
2231cb0ef41Sopenharmony_ci    THROW_ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE(env);
2241cb0ef41Sopenharmony_ci    return {};
2251cb0ef41Sopenharmony_ci  }
2261cb0ef41Sopenharmony_ci  return Blob::Create(env, store_, length_);
2271cb0ef41Sopenharmony_ci}
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ciBaseObject::TransferMode Blob::GetTransferMode() const {
2301cb0ef41Sopenharmony_ci  return BaseObject::TransferMode::kCloneable;
2311cb0ef41Sopenharmony_ci}
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_cistd::unique_ptr<worker::TransferData> Blob::CloneForMessaging() const {
2341cb0ef41Sopenharmony_ci  return std::make_unique<BlobTransferData>(store_, length_);
2351cb0ef41Sopenharmony_ci}
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_civoid Blob::StoreDataObject(const v8::FunctionCallbackInfo<v8::Value>& args) {
2381cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
2391cb0ef41Sopenharmony_ci  BlobBindingData* binding_data = Realm::GetBindingData<BlobBindingData>(args);
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  CHECK(args[0]->IsString());  // ID key
2421cb0ef41Sopenharmony_ci  CHECK(Blob::HasInstance(env, args[1]));  // Blob
2431cb0ef41Sopenharmony_ci  CHECK(args[2]->IsUint32());  // Length
2441cb0ef41Sopenharmony_ci  CHECK(args[3]->IsString());  // Type
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci  Utf8Value key(env->isolate(), args[0]);
2471cb0ef41Sopenharmony_ci  Blob* blob;
2481cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&blob, args[1]);
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci  size_t length = args[2].As<Uint32>()->Value();
2511cb0ef41Sopenharmony_ci  Utf8Value type(env->isolate(), args[3]);
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci  binding_data->store_data_object(
2541cb0ef41Sopenharmony_ci      std::string(*key, key.length()),
2551cb0ef41Sopenharmony_ci      BlobBindingData::StoredDataObject(
2561cb0ef41Sopenharmony_ci        BaseObjectPtr<Blob>(blob),
2571cb0ef41Sopenharmony_ci        length,
2581cb0ef41Sopenharmony_ci        std::string(*type, type.length())));
2591cb0ef41Sopenharmony_ci}
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_civoid Blob::RevokeDataObject(const v8::FunctionCallbackInfo<v8::Value>& args) {
2621cb0ef41Sopenharmony_ci  BlobBindingData* binding_data = Realm::GetBindingData<BlobBindingData>(args);
2631cb0ef41Sopenharmony_ci
2641cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
2651cb0ef41Sopenharmony_ci  CHECK(args[0]->IsString());  // ID key
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci  Utf8Value key(env->isolate(), args[0]);
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ci  binding_data->revoke_data_object(std::string(*key, key.length()));
2701cb0ef41Sopenharmony_ci}
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_civoid Blob::GetDataObject(const v8::FunctionCallbackInfo<v8::Value>& args) {
2731cb0ef41Sopenharmony_ci  BlobBindingData* binding_data = Realm::GetBindingData<BlobBindingData>(args);
2741cb0ef41Sopenharmony_ci
2751cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
2761cb0ef41Sopenharmony_ci  CHECK(args[0]->IsString());
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ci  Utf8Value key(env->isolate(), args[0]);
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci  BlobBindingData::StoredDataObject stored =
2811cb0ef41Sopenharmony_ci      binding_data->get_data_object(std::string(*key, key.length()));
2821cb0ef41Sopenharmony_ci  if (stored.blob) {
2831cb0ef41Sopenharmony_ci    Local<Value> type;
2841cb0ef41Sopenharmony_ci    if (!String::NewFromUtf8(
2851cb0ef41Sopenharmony_ci            env->isolate(),
2861cb0ef41Sopenharmony_ci            stored.type.c_str(),
2871cb0ef41Sopenharmony_ci            v8::NewStringType::kNormal,
2881cb0ef41Sopenharmony_ci            static_cast<int>(stored.type.length())).ToLocal(&type)) {
2891cb0ef41Sopenharmony_ci      return;
2901cb0ef41Sopenharmony_ci    }
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ci    Local<Value> values[] = {
2931cb0ef41Sopenharmony_ci      stored.blob->object(),
2941cb0ef41Sopenharmony_ci      Uint32::NewFromUnsigned(env->isolate(), stored.length),
2951cb0ef41Sopenharmony_ci      type
2961cb0ef41Sopenharmony_ci    };
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(
2991cb0ef41Sopenharmony_ci        Array::New(
3001cb0ef41Sopenharmony_ci            env->isolate(),
3011cb0ef41Sopenharmony_ci            values,
3021cb0ef41Sopenharmony_ci            arraysize(values)));
3031cb0ef41Sopenharmony_ci  }
3041cb0ef41Sopenharmony_ci}
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ciFixedSizeBlobCopyJob::FixedSizeBlobCopyJob(Environment* env,
3071cb0ef41Sopenharmony_ci                                           Local<Object> object,
3081cb0ef41Sopenharmony_ci                                           Blob* blob,
3091cb0ef41Sopenharmony_ci                                           FixedSizeBlobCopyJob::Mode mode)
3101cb0ef41Sopenharmony_ci    : AsyncWrap(env, object, AsyncWrap::PROVIDER_FIXEDSIZEBLOBCOPY),
3111cb0ef41Sopenharmony_ci      ThreadPoolWork(env, "blob"),
3121cb0ef41Sopenharmony_ci      mode_(mode) {
3131cb0ef41Sopenharmony_ci  if (mode == FixedSizeBlobCopyJob::Mode::SYNC) MakeWeak();
3141cb0ef41Sopenharmony_ci  source_ = blob->entries();
3151cb0ef41Sopenharmony_ci  length_ = blob->length();
3161cb0ef41Sopenharmony_ci}
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_civoid FixedSizeBlobCopyJob::AfterThreadPoolWork(int status) {
3191cb0ef41Sopenharmony_ci  Environment* env = AsyncWrap::env();
3201cb0ef41Sopenharmony_ci  CHECK_EQ(mode_, Mode::ASYNC);
3211cb0ef41Sopenharmony_ci  CHECK(status == 0 || status == UV_ECANCELED);
3221cb0ef41Sopenharmony_ci  std::unique_ptr<FixedSizeBlobCopyJob> ptr(this);
3231cb0ef41Sopenharmony_ci  HandleScope handle_scope(env->isolate());
3241cb0ef41Sopenharmony_ci  Context::Scope context_scope(env->context());
3251cb0ef41Sopenharmony_ci  Local<Value> args[2];
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci  if (status == UV_ECANCELED) {
3281cb0ef41Sopenharmony_ci    args[0] = Number::New(env->isolate(), status),
3291cb0ef41Sopenharmony_ci    args[1] = Undefined(env->isolate());
3301cb0ef41Sopenharmony_ci  } else {
3311cb0ef41Sopenharmony_ci    args[0] = Undefined(env->isolate());
3321cb0ef41Sopenharmony_ci    args[1] = ArrayBuffer::New(env->isolate(), destination_);
3331cb0ef41Sopenharmony_ci  }
3341cb0ef41Sopenharmony_ci
3351cb0ef41Sopenharmony_ci  ptr->MakeCallback(env->ondone_string(), arraysize(args), args);
3361cb0ef41Sopenharmony_ci}
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_civoid FixedSizeBlobCopyJob::DoThreadPoolWork() {
3391cb0ef41Sopenharmony_ci  unsigned char* dest = static_cast<unsigned char*>(destination_->Data());
3401cb0ef41Sopenharmony_ci  if (length_ > 0) {
3411cb0ef41Sopenharmony_ci    size_t total = 0;
3421cb0ef41Sopenharmony_ci    for (const auto& entry : source_) {
3431cb0ef41Sopenharmony_ci      unsigned char* src = static_cast<unsigned char*>(entry.store->Data());
3441cb0ef41Sopenharmony_ci      src += entry.offset;
3451cb0ef41Sopenharmony_ci      memcpy(dest, src, entry.length);
3461cb0ef41Sopenharmony_ci      dest += entry.length;
3471cb0ef41Sopenharmony_ci      total += entry.length;
3481cb0ef41Sopenharmony_ci      CHECK_LE(total, length_);
3491cb0ef41Sopenharmony_ci    }
3501cb0ef41Sopenharmony_ci  }
3511cb0ef41Sopenharmony_ci}
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_civoid FixedSizeBlobCopyJob::MemoryInfo(MemoryTracker* tracker) const {
3541cb0ef41Sopenharmony_ci  tracker->TrackFieldWithSize("source", length_);
3551cb0ef41Sopenharmony_ci  tracker->TrackFieldWithSize(
3561cb0ef41Sopenharmony_ci      "destination",
3571cb0ef41Sopenharmony_ci      destination_ ? destination_->ByteLength() : 0);
3581cb0ef41Sopenharmony_ci}
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_civoid FixedSizeBlobCopyJob::Initialize(Environment* env, Local<Object> target) {
3611cb0ef41Sopenharmony_ci  Isolate* isolate = env->isolate();
3621cb0ef41Sopenharmony_ci  v8::Local<v8::FunctionTemplate> job = NewFunctionTemplate(isolate, New);
3631cb0ef41Sopenharmony_ci  job->Inherit(AsyncWrap::GetConstructorTemplate(env));
3641cb0ef41Sopenharmony_ci  job->InstanceTemplate()->SetInternalFieldCount(
3651cb0ef41Sopenharmony_ci      AsyncWrap::kInternalFieldCount);
3661cb0ef41Sopenharmony_ci  SetProtoMethod(isolate, job, "run", Run);
3671cb0ef41Sopenharmony_ci  SetConstructorFunction(env->context(), target, "FixedSizeBlobCopyJob", job);
3681cb0ef41Sopenharmony_ci}
3691cb0ef41Sopenharmony_ci
3701cb0ef41Sopenharmony_civoid FixedSizeBlobCopyJob::New(const FunctionCallbackInfo<Value>& args) {
3711cb0ef41Sopenharmony_ci  static constexpr size_t kMaxSyncLength = 4096;
3721cb0ef41Sopenharmony_ci  static constexpr size_t kMaxEntryCount = 4;
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
3751cb0ef41Sopenharmony_ci  CHECK(args.IsConstructCall());
3761cb0ef41Sopenharmony_ci  CHECK(args[0]->IsObject());
3771cb0ef41Sopenharmony_ci  CHECK(Blob::HasInstance(env, args[0]));
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci  Blob* blob;
3801cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&blob, args[0]);
3811cb0ef41Sopenharmony_ci
3821cb0ef41Sopenharmony_ci  // This is a fairly arbitrary heuristic. We want to avoid deferring to
3831cb0ef41Sopenharmony_ci  // the threadpool if the amount of data being copied is small and there
3841cb0ef41Sopenharmony_ci  // aren't that many entries to copy.
3851cb0ef41Sopenharmony_ci  FixedSizeBlobCopyJob::Mode mode =
3861cb0ef41Sopenharmony_ci      (blob->length() < kMaxSyncLength &&
3871cb0ef41Sopenharmony_ci       blob->entries().size() < kMaxEntryCount) ?
3881cb0ef41Sopenharmony_ci          FixedSizeBlobCopyJob::Mode::SYNC :
3891cb0ef41Sopenharmony_ci          FixedSizeBlobCopyJob::Mode::ASYNC;
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_ci  new FixedSizeBlobCopyJob(env, args.This(), blob, mode);
3921cb0ef41Sopenharmony_ci}
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_civoid FixedSizeBlobCopyJob::Run(const FunctionCallbackInfo<Value>& args) {
3951cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
3961cb0ef41Sopenharmony_ci  FixedSizeBlobCopyJob* job;
3971cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&job, args.Holder());
3981cb0ef41Sopenharmony_ci  job->destination_ =
3991cb0ef41Sopenharmony_ci      ArrayBuffer::NewBackingStore(env->isolate(), job->length_);
4001cb0ef41Sopenharmony_ci  if (job->mode() == FixedSizeBlobCopyJob::Mode::ASYNC)
4011cb0ef41Sopenharmony_ci    return job->ScheduleWork();
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci  job->DoThreadPoolWork();
4041cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(
4051cb0ef41Sopenharmony_ci      ArrayBuffer::New(env->isolate(), job->destination_));
4061cb0ef41Sopenharmony_ci}
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_civoid FixedSizeBlobCopyJob::RegisterExternalReferences(
4091cb0ef41Sopenharmony_ci    ExternalReferenceRegistry* registry) {
4101cb0ef41Sopenharmony_ci  registry->Register(New);
4111cb0ef41Sopenharmony_ci  registry->Register(Run);
4121cb0ef41Sopenharmony_ci}
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_civoid BlobBindingData::StoredDataObject::MemoryInfo(
4151cb0ef41Sopenharmony_ci    MemoryTracker* tracker) const {
4161cb0ef41Sopenharmony_ci  tracker->TrackField("blob", blob);
4171cb0ef41Sopenharmony_ci  tracker->TrackFieldWithSize("type", type.length());
4181cb0ef41Sopenharmony_ci}
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ciBlobBindingData::StoredDataObject::StoredDataObject(
4211cb0ef41Sopenharmony_ci    const BaseObjectPtr<Blob>& blob_,
4221cb0ef41Sopenharmony_ci    size_t length_,
4231cb0ef41Sopenharmony_ci    const std::string& type_)
4241cb0ef41Sopenharmony_ci    : blob(blob_),
4251cb0ef41Sopenharmony_ci      length(length_),
4261cb0ef41Sopenharmony_ci      type(type_) {}
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ciBlobBindingData::BlobBindingData(Realm* realm, Local<Object> wrap)
4291cb0ef41Sopenharmony_ci    : SnapshotableObject(realm, wrap, type_int) {
4301cb0ef41Sopenharmony_ci  MakeWeak();
4311cb0ef41Sopenharmony_ci}
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_civoid BlobBindingData::MemoryInfo(MemoryTracker* tracker) const {
4341cb0ef41Sopenharmony_ci  tracker->TrackField("data_objects", data_objects_);
4351cb0ef41Sopenharmony_ci}
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_civoid BlobBindingData::store_data_object(
4381cb0ef41Sopenharmony_ci    const std::string& uuid,
4391cb0ef41Sopenharmony_ci    const BlobBindingData::StoredDataObject& object) {
4401cb0ef41Sopenharmony_ci  data_objects_[uuid] = object;
4411cb0ef41Sopenharmony_ci}
4421cb0ef41Sopenharmony_ci
4431cb0ef41Sopenharmony_civoid BlobBindingData::revoke_data_object(const std::string& uuid) {
4441cb0ef41Sopenharmony_ci  if (data_objects_.find(uuid) == data_objects_.end()) {
4451cb0ef41Sopenharmony_ci    return;
4461cb0ef41Sopenharmony_ci  }
4471cb0ef41Sopenharmony_ci  data_objects_.erase(uuid);
4481cb0ef41Sopenharmony_ci  CHECK_EQ(data_objects_.find(uuid), data_objects_.end());
4491cb0ef41Sopenharmony_ci}
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ciBlobBindingData::StoredDataObject BlobBindingData::get_data_object(
4521cb0ef41Sopenharmony_ci    const std::string& uuid) {
4531cb0ef41Sopenharmony_ci  auto entry = data_objects_.find(uuid);
4541cb0ef41Sopenharmony_ci  if (entry == data_objects_.end())
4551cb0ef41Sopenharmony_ci    return BlobBindingData::StoredDataObject {};
4561cb0ef41Sopenharmony_ci  return entry->second;
4571cb0ef41Sopenharmony_ci}
4581cb0ef41Sopenharmony_ci
4591cb0ef41Sopenharmony_civoid BlobBindingData::Deserialize(Local<Context> context,
4601cb0ef41Sopenharmony_ci                                  Local<Object> holder,
4611cb0ef41Sopenharmony_ci                                  int index,
4621cb0ef41Sopenharmony_ci                                  InternalFieldInfoBase* info) {
4631cb0ef41Sopenharmony_ci  DCHECK_EQ(index, BaseObject::kEmbedderType);
4641cb0ef41Sopenharmony_ci  HandleScope scope(context->GetIsolate());
4651cb0ef41Sopenharmony_ci  Realm* realm = Realm::GetCurrent(context);
4661cb0ef41Sopenharmony_ci  BlobBindingData* binding =
4671cb0ef41Sopenharmony_ci      realm->AddBindingData<BlobBindingData>(context, holder);
4681cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(binding);
4691cb0ef41Sopenharmony_ci}
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_cibool BlobBindingData::PrepareForSerialization(Local<Context> context,
4721cb0ef41Sopenharmony_ci                                              v8::SnapshotCreator* creator) {
4731cb0ef41Sopenharmony_ci  // Stored blob objects are not actually persisted.
4741cb0ef41Sopenharmony_ci  // Return true because we need to maintain the reference to the binding from
4751cb0ef41Sopenharmony_ci  // JS land.
4761cb0ef41Sopenharmony_ci  return true;
4771cb0ef41Sopenharmony_ci}
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ciInternalFieldInfoBase* BlobBindingData::Serialize(int index) {
4801cb0ef41Sopenharmony_ci  DCHECK_EQ(index, BaseObject::kEmbedderType);
4811cb0ef41Sopenharmony_ci  InternalFieldInfo* info =
4821cb0ef41Sopenharmony_ci      InternalFieldInfoBase::New<InternalFieldInfo>(type());
4831cb0ef41Sopenharmony_ci  return info;
4841cb0ef41Sopenharmony_ci}
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_civoid Blob::RegisterExternalReferences(ExternalReferenceRegistry* registry) {
4871cb0ef41Sopenharmony_ci  registry->Register(Blob::New);
4881cb0ef41Sopenharmony_ci  registry->Register(Blob::ToArrayBuffer);
4891cb0ef41Sopenharmony_ci  registry->Register(Blob::ToSlice);
4901cb0ef41Sopenharmony_ci  registry->Register(Blob::StoreDataObject);
4911cb0ef41Sopenharmony_ci  registry->Register(Blob::GetDataObject);
4921cb0ef41Sopenharmony_ci  registry->Register(Blob::RevokeDataObject);
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_ci  FixedSizeBlobCopyJob::RegisterExternalReferences(registry);
4951cb0ef41Sopenharmony_ci}
4961cb0ef41Sopenharmony_ci
4971cb0ef41Sopenharmony_ci}  // namespace node
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_ciNODE_BINDING_CONTEXT_AWARE_INTERNAL(blob, node::Blob::Initialize)
5001cb0ef41Sopenharmony_ciNODE_BINDING_EXTERNAL_REFERENCE(blob, node::Blob::RegisterExternalReferences)
501