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 | |
9 | namespace tonic { |
10 | |
11 | namespace { |
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. |
15 | const int kExternalSizeThreshold = 1000; |
16 | |
17 | void FreeFinalizer(void* isolate_callback_data, |
18 | Dart_WeakPersistentHandle handle, |
19 | void* peer) { |
20 | free(peer); |
21 | } |
22 | |
23 | } // anonymous namespace |
24 | |
25 | Dart_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 | |
39 | DartByteData::DartByteData() |
40 | : data_(nullptr), length_in_bytes_(0), dart_handle_(nullptr) {} |
41 | |
42 | DartByteData::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 | |
57 | DartByteData::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 | |
69 | DartByteData::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 | |
77 | DartByteData::~DartByteData() { |
78 | Release(); |
79 | } |
80 | |
81 | std::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 | |
86 | void DartByteData::Release() const { |
87 | if (data_) { |
88 | Dart_TypedDataReleaseData(dart_handle_); |
89 | data_ = nullptr; |
90 | } |
91 | } |
92 | |
93 | DartByteData 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 | |
102 | void DartConverter<DartByteData>::SetReturnValue(Dart_NativeArguments args, |
103 | DartByteData val) { |
104 | Dart_SetReturnValue(args, val.dart_handle()); |
105 | } |
106 | |
107 | } // namespace tonic |
108 | |