1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "tonic/typed_data/dart_byte_data.h"
6
7#include "tonic/logging/dart_error.h"
8
9namespace tonic {
10
11namespace {
12
13// For large objects it is more efficient to use an external typed data object
14// with a buffer allocated outside the Dart heap.
15const int kExternalSizeThreshold = 1000;
16
17void FreeFinalizer(void* isolate_callback_data,
18 Dart_WeakPersistentHandle handle,
19 void* peer) {
20 free(peer);
21}
22
23} // anonymous namespace
24
25Dart_Handle DartByteData::Create(const void* data, size_t length) {
26 if (length < kExternalSizeThreshold) {
27 auto handle = DartByteData{data, length}.dart_handle();
28 // The destructor should release the typed data.
29 return handle;
30 } else {
31 void* buf = ::malloc(length);
32 TONIC_DCHECK(buf);
33 ::memcpy(buf, data, length);
34 return Dart_NewExternalTypedDataWithFinalizer(
35 Dart_TypedData_kByteData, buf, length, buf, length, FreeFinalizer);
36 }
37}
38
39DartByteData::DartByteData()
40 : data_(nullptr), length_in_bytes_(0), dart_handle_(nullptr) {}
41
42DartByteData::DartByteData(const void* data, size_t length)
43 : data_(nullptr),
44 length_in_bytes_(0),
45 dart_handle_(Dart_NewTypedData(Dart_TypedData_kByteData, length)) {
46 if (!Dart_IsError(dart_handle_)) {
47 Dart_TypedData_Type type;
48 auto acquire_result = Dart_TypedDataAcquireData(dart_handle_, &type, &data_,
49 &length_in_bytes_);
50
51 if (!Dart_IsError(acquire_result)) {
52 ::memcpy(data_, data, length_in_bytes_);
53 }
54 }
55}
56
57DartByteData::DartByteData(Dart_Handle list)
58 : data_(nullptr), length_in_bytes_(0), dart_handle_(list) {
59 if (Dart_IsNull(list))
60 return;
61
62 Dart_TypedData_Type type;
63 Dart_TypedDataAcquireData(list, &type, &data_, &length_in_bytes_);
64 TONIC_DCHECK(!LogIfError(list));
65 if (type != Dart_TypedData_kByteData)
66 Dart_ThrowException(ToDart("Non-genuine ByteData passed to engine."));
67}
68
69DartByteData::DartByteData(DartByteData&& other)
70 : data_(other.data_),
71 length_in_bytes_(other.length_in_bytes_),
72 dart_handle_(other.dart_handle_) {
73 other.data_ = nullptr;
74 other.dart_handle_ = nullptr;
75}
76
77DartByteData::~DartByteData() {
78 Release();
79}
80
81std::vector<char> DartByteData::Copy() const {
82 const char* ptr = static_cast<const char*>(data_);
83 return std::vector<char>(ptr, ptr + length_in_bytes_);
84}
85
86void DartByteData::Release() const {
87 if (data_) {
88 Dart_TypedDataReleaseData(dart_handle_);
89 data_ = nullptr;
90 }
91}
92
93DartByteData DartConverter<DartByteData>::FromArguments(
94 Dart_NativeArguments args,
95 int index,
96 Dart_Handle& exception) {
97 Dart_Handle data = Dart_GetNativeArgument(args, index);
98 TONIC_DCHECK(!LogIfError(data));
99 return DartByteData(data);
100}
101
102void DartConverter<DartByteData>::SetReturnValue(Dart_NativeArguments args,
103 DartByteData val) {
104 Dart_SetReturnValue(args, val.dart_handle());
105}
106
107} // namespace tonic
108