rclnodejs 1.5.1 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -2
- package/binding.gyp +2 -0
- package/index.js +1 -1
- package/lib/action/client.js +1 -1
- package/lib/action/graph.js +1 -1
- package/lib/action/server.js +1 -1
- package/lib/action/server_goal_handle.js +1 -1
- package/lib/client.js +1 -1
- package/lib/clock.js +1 -1
- package/lib/context.js +1 -1
- package/lib/duration.js +1 -1
- package/lib/event_handler.js +1 -1
- package/lib/guard_condition.js +1 -1
- package/lib/lifecycle.js +1 -1
- package/lib/lifecycle_publisher.js +1 -1
- package/lib/logging.js +1 -1
- package/lib/native_loader.js +173 -0
- package/lib/node.js +1 -1
- package/lib/publisher.js +1 -1
- package/lib/serialization.js +1 -1
- package/lib/service.js +1 -1
- package/lib/subscription.js +1 -1
- package/lib/time.js +1 -1
- package/lib/time_source.js +1 -1
- package/lib/timer.js +1 -1
- package/lib/type_description_service.js +1 -1
- package/lib/utils.js +37 -0
- package/lib/validator.js +1 -1
- package/package.json +13 -12
- package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
- package/rosidl_gen/deallocator.js +1 -1
- package/rosidl_gen/generator.json +1 -1
- package/rosidl_gen/primitive_types.js +2 -2
- package/rosidl_gen/templates/message.dot +2 -2
- package/scripts/install.js +113 -0
- package/scripts/tag_prebuilds.js +70 -0
- package/src/addon.cpp +3 -0
- package/third_party/ref-napi/index.js +15 -0
- package/third_party/ref-napi/lib/ref.js +1741 -0
- package/third_party/ref-napi/src/ref_napi_bindings.cpp +736 -0
- package/third_party/ref-napi/src/ref_napi_bindings.h +26 -0
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
// Copyright (c) 2025, The Robot Web Tools Contributors
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
#include "ref_napi_bindings.h"
|
|
16
|
+
|
|
17
|
+
#include <errno.h>
|
|
18
|
+
#include <stdint.h>
|
|
19
|
+
#include <stdlib.h>
|
|
20
|
+
#include <string.h>
|
|
21
|
+
|
|
22
|
+
#include <string>
|
|
23
|
+
#include <unordered_map>
|
|
24
|
+
|
|
25
|
+
#if !defined(NAPI_VERSION) || NAPI_VERSION < 6
|
|
26
|
+
#include <get-symbol-from-current-process.h>
|
|
27
|
+
#endif
|
|
28
|
+
|
|
29
|
+
namespace RefNapi {
|
|
30
|
+
|
|
31
|
+
class Instance {
|
|
32
|
+
public:
|
|
33
|
+
virtual napi_value WrapPointer(char* ptr, size_t length) = 0;
|
|
34
|
+
virtual char* GetBufferData(napi_value val) = 0;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} // namespace RefNapi
|
|
38
|
+
|
|
39
|
+
#ifndef _WIN32
|
|
40
|
+
#ifndef __STDC_FORMAT_MACROS
|
|
41
|
+
#define __STDC_FORMAT_MACROS
|
|
42
|
+
#endif
|
|
43
|
+
#include <inttypes.h>
|
|
44
|
+
#else
|
|
45
|
+
#define __alignof__ __alignof
|
|
46
|
+
#define snprintf(buf, bufSize, format, arg) \
|
|
47
|
+
_snprintf_s(buf, bufSize, _TRUNCATE, format, arg)
|
|
48
|
+
#define strtoll _strtoi64
|
|
49
|
+
#define strtoull _strtoui64
|
|
50
|
+
#define PRId64 "lld"
|
|
51
|
+
#define PRIu64 "llu"
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
namespace rclnodejs {
|
|
55
|
+
|
|
56
|
+
using namespace Napi;
|
|
57
|
+
|
|
58
|
+
namespace {
|
|
59
|
+
|
|
60
|
+
// used by the Int64 functions to determine whether to return a Number
|
|
61
|
+
// or String based on whether or not a Number will lose precision.
|
|
62
|
+
// http://stackoverflow.com/q/307179/376773
|
|
63
|
+
#define JS_MAX_INT +9007199254740992LL
|
|
64
|
+
#define JS_MIN_INT -9007199254740992LL
|
|
65
|
+
|
|
66
|
+
// mirrors deps/v8/src/objects.h.
|
|
67
|
+
// we could use `node::Buffer::kMaxLength`, but it's not defined on node v0.6.x
|
|
68
|
+
static const size_t kMaxLength = 0x3fffffff;
|
|
69
|
+
|
|
70
|
+
// Since Node.js v14.0.0, we have to keep a global list of all ArrayBuffer
|
|
71
|
+
// instances that we work with, in order not to create any duplicates.
|
|
72
|
+
// Luckily, N-API instance data is available on v14.x and above.
|
|
73
|
+
class InstanceData final : public RefNapi::Instance {
|
|
74
|
+
public:
|
|
75
|
+
explicit InstanceData(Env env) : env(env) {}
|
|
76
|
+
Env env;
|
|
77
|
+
FunctionReference pointer_ctor;
|
|
78
|
+
|
|
79
|
+
napi_value WrapPointer(char* ptr, size_t length) override;
|
|
80
|
+
char* GetBufferData(napi_value val) override;
|
|
81
|
+
|
|
82
|
+
static InstanceData* Get(Env env) {
|
|
83
|
+
return env.GetInstanceData<InstanceData>();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
class PointerBuffer : public ObjectWrap<PointerBuffer> {
|
|
88
|
+
public:
|
|
89
|
+
static Object Init(Napi::Env env, Object exports);
|
|
90
|
+
explicit PointerBuffer(Napi::CallbackInfo& info);
|
|
91
|
+
Napi::Value IsNull(const Napi::CallbackInfo& info);
|
|
92
|
+
Napi::Value Address(const Napi::CallbackInfo& info);
|
|
93
|
+
Napi::Value Length(const Napi::CallbackInfo& info);
|
|
94
|
+
Napi::Value Get(const Napi::CallbackInfo& info);
|
|
95
|
+
Napi::Value ToString(const Napi::CallbackInfo& info);
|
|
96
|
+
Napi::Value Copy(const Napi::CallbackInfo& info);
|
|
97
|
+
Napi::Value Slice(const Napi::CallbackInfo& info);
|
|
98
|
+
char* ptr_;
|
|
99
|
+
int length_;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
Object PointerBuffer::Init(Napi::Env env, Object exports) {
|
|
103
|
+
Function func =
|
|
104
|
+
DefineClass(env, "PointerBuffer",
|
|
105
|
+
{InstanceMethod("isNull", &PointerBuffer::IsNull),
|
|
106
|
+
InstanceMethod("get", &PointerBuffer::Get),
|
|
107
|
+
InstanceMethod("address", &PointerBuffer::Address),
|
|
108
|
+
InstanceMethod("toString", &PointerBuffer::ToString),
|
|
109
|
+
InstanceMethod("copy", &PointerBuffer::Copy),
|
|
110
|
+
InstanceMethod("slice", &PointerBuffer::Slice),
|
|
111
|
+
InstanceAccessor<&PointerBuffer::Length>("length")});
|
|
112
|
+
|
|
113
|
+
exports.Set("PointerBuffer", func);
|
|
114
|
+
InstanceData* data = InstanceData::Get(env);
|
|
115
|
+
data->pointer_ctor = Persistent(func);
|
|
116
|
+
return exports;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
PointerBuffer::PointerBuffer(Napi::CallbackInfo& info)
|
|
120
|
+
: Napi::ObjectWrap<PointerBuffer>(info) {
|
|
121
|
+
Napi::Env env = info.Env();
|
|
122
|
+
int length = info.Length();
|
|
123
|
+
if (length <= 0 || !info[0].IsNumber()) {
|
|
124
|
+
Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
Napi::Number value = info[0].As<Napi::Number>();
|
|
128
|
+
ptr_ = reinterpret_cast<char*>(value.Int64Value());
|
|
129
|
+
length_ = (ptr_ == nullptr ? 0 : info[1].As<Number>().Int32Value());
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Napi::Value PointerBuffer::IsNull(const Napi::CallbackInfo& info) {
|
|
133
|
+
return Boolean::New(info.Env(), ptr_ == nullptr);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
Napi::Value PointerBuffer::Address(const Napi::CallbackInfo& info) {
|
|
137
|
+
return Number::New(info.Env(), reinterpret_cast<int64_t>(ptr_));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
Napi::Value PointerBuffer::Length(const Napi::CallbackInfo& info) {
|
|
141
|
+
return Number::New(info.Env(), length_);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
Napi::Value PointerBuffer::Get(const Napi::CallbackInfo& info) {
|
|
145
|
+
int32_t offset = info[0].As<Number>().Int32Value();
|
|
146
|
+
return Number::New(info.Env(), ptr_[offset]);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
Napi::Value PointerBuffer::ToString(const Napi::CallbackInfo& info) {
|
|
150
|
+
Napi::Env env = info.Env();
|
|
151
|
+
int length = info.Length();
|
|
152
|
+
if (length == 1 || info[0].IsString()) {
|
|
153
|
+
std::string encoding = info[0].As<String>();
|
|
154
|
+
if (encoding == "utf-8") {
|
|
155
|
+
return String::New(info.Env(), ptr_, length_);
|
|
156
|
+
} else if (encoding == "ucs2") {
|
|
157
|
+
return String::New(info.Env(), reinterpret_cast<char16_t*>(ptr_),
|
|
158
|
+
length_ / 2);
|
|
159
|
+
} else {
|
|
160
|
+
Napi::TypeError::New(env, "Unknown encoding argument: " + encoding)
|
|
161
|
+
.ThrowAsJavaScriptException();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return String::New(info.Env(), ptr_, length_);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
char* ExtractBufferData(Value val);
|
|
169
|
+
|
|
170
|
+
Napi::Value PointerBuffer::Copy(const Napi::CallbackInfo& info) {
|
|
171
|
+
char* dest =
|
|
172
|
+
ExtractBufferData(info[0]) + info[1].As<Napi::Number>().Int64Value();
|
|
173
|
+
uint64_t length =
|
|
174
|
+
info[3].As<Number>().Int64Value() - info[2].As<Number>().Int64Value();
|
|
175
|
+
std::memcpy(dest, ptr_, length);
|
|
176
|
+
return Number::New(info.Env(), length);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
Value CreatePointerBuffer(Env env, char* ptr, size_t length);
|
|
180
|
+
|
|
181
|
+
Napi::Value PointerBuffer::Slice(const Napi::CallbackInfo& info) {
|
|
182
|
+
int64_t offset = info[0].As<Napi::Number>().Int64Value();
|
|
183
|
+
return CreatePointerBuffer(info.Env(), ptr_ + offset, length_ - offset);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
Value CreatePointerBuffer(Env env, char* ptr, size_t length) {
|
|
187
|
+
InstanceData* data = InstanceData::Get(env);
|
|
188
|
+
return data->pointer_ctor.New(
|
|
189
|
+
{Number::New(env, reinterpret_cast<int64_t>(ptr)),
|
|
190
|
+
Number::New(env, length)});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
char* ExtractBufferData(Value val) {
|
|
194
|
+
if (!val.IsBuffer() && val.IsObject()) {
|
|
195
|
+
auto p = PointerBuffer::Unwrap(val.As<Object>());
|
|
196
|
+
return p->ptr_;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
Buffer<char> buf = val.As<Buffer<char>>();
|
|
200
|
+
return buf.Data();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
napi_value InstanceData::WrapPointer(char* ptr, size_t length) {
|
|
204
|
+
return CreatePointerBuffer(env, ptr, length);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
char* InstanceData::GetBufferData(napi_value val) {
|
|
208
|
+
return ExtractBufferData(Value(env, val));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
char* AddressForArgs(const CallbackInfo& args, size_t offset_index = 1) {
|
|
212
|
+
Value buf = args[0];
|
|
213
|
+
if (!(buf.IsBuffer() || buf.IsObject())) {
|
|
214
|
+
throw TypeError::New(args.Env(),
|
|
215
|
+
"Buffer or PointerBuffer instance expected");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
int64_t offset = args[offset_index].ToNumber();
|
|
219
|
+
return ExtractBufferData(buf) + offset;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
Value Address(const CallbackInfo& args) {
|
|
223
|
+
char* ptr = AddressForArgs(args);
|
|
224
|
+
uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
|
|
225
|
+
|
|
226
|
+
return Number::New(args.Env(), static_cast<double>(intptr));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
Value HexAddress(const CallbackInfo& args) {
|
|
230
|
+
char* ptr = AddressForArgs(args);
|
|
231
|
+
char strbuf[30];
|
|
232
|
+
snprintf(strbuf, 30, "%p", ptr);
|
|
233
|
+
|
|
234
|
+
if (strbuf[0] == '0' && strbuf[1] == 'x') {
|
|
235
|
+
ptr = strbuf + 2;
|
|
236
|
+
} else {
|
|
237
|
+
ptr = strbuf;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return String::New(args.Env(), ptr);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
Value IsNull(const CallbackInfo& args) {
|
|
244
|
+
Value buf = args[0];
|
|
245
|
+
if (!(buf.IsBuffer() || buf.IsObject())) {
|
|
246
|
+
return Boolean::New(args.Env(), false);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
char* ptr = AddressForArgs(args);
|
|
250
|
+
return Boolean::New(args.Env(), ptr == nullptr);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
Value IsAddress(const CallbackInfo& args) {
|
|
254
|
+
Value buf = args[0];
|
|
255
|
+
if (!(buf.IsBuffer() || buf.IsObject())) {
|
|
256
|
+
return Boolean::New(args.Env(), false);
|
|
257
|
+
}
|
|
258
|
+
return Boolean::New(args.Env(), true);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
Value ReadObject(const CallbackInfo& args) {
|
|
262
|
+
char* ptr = AddressForArgs(args);
|
|
263
|
+
|
|
264
|
+
if (ptr == nullptr) {
|
|
265
|
+
throw Error::New(args.Env(),
|
|
266
|
+
"readObject: Cannot read from nullptr pointer");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
Reference<Object>* rptr = reinterpret_cast<Reference<Object>*>(ptr);
|
|
270
|
+
return rptr->Value();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
void WriteObject(const CallbackInfo& args) {
|
|
274
|
+
Env env = args.Env();
|
|
275
|
+
char* ptr = AddressForArgs(args);
|
|
276
|
+
|
|
277
|
+
if (ptr == nullptr) {
|
|
278
|
+
throw Error::New(env, "readObject: Cannot write to nullptr pointer");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
Reference<Object>* rptr = reinterpret_cast<Reference<Object>*>(ptr);
|
|
282
|
+
if (args[2].IsObject()) {
|
|
283
|
+
Object val = args[2].As<Object>();
|
|
284
|
+
*rptr = std::move(Reference<Object>::New(val));
|
|
285
|
+
} else if (args[2].IsNull()) {
|
|
286
|
+
rptr->Reset();
|
|
287
|
+
} else {
|
|
288
|
+
throw TypeError::New(env,
|
|
289
|
+
"WriteObject's 3rd argument needs to be an object");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
Value ReadPointer(const CallbackInfo& args) {
|
|
294
|
+
Env env = args.Env();
|
|
295
|
+
char* ptr = AddressForArgs(args);
|
|
296
|
+
|
|
297
|
+
if (ptr == nullptr) {
|
|
298
|
+
throw Error::New(env, "readPointer: Cannot read from nullptr pointer");
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
int64_t size = args[2].ToNumber();
|
|
302
|
+
|
|
303
|
+
char* val = *reinterpret_cast<char**>(ptr);
|
|
304
|
+
return CreatePointerBuffer(env, val, size);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
void WritePointer(const CallbackInfo& args) {
|
|
308
|
+
Env env = args.Env();
|
|
309
|
+
char* ptr = AddressForArgs(args);
|
|
310
|
+
Value input = args[2];
|
|
311
|
+
|
|
312
|
+
if (!input.IsNull() && !input.IsBuffer() && !input.IsObject()) {
|
|
313
|
+
throw TypeError::New(
|
|
314
|
+
env, "writePointer: Buffer instance expected as third argument");
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (input.IsNull()) {
|
|
318
|
+
*reinterpret_cast<char**>(ptr) = nullptr;
|
|
319
|
+
} else {
|
|
320
|
+
char* input_ptr = ExtractBufferData(input);
|
|
321
|
+
*reinterpret_cast<char**>(ptr) = input_ptr;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
Value ReadInt64(const CallbackInfo& args) {
|
|
326
|
+
Env env = args.Env();
|
|
327
|
+
char* ptr = AddressForArgs(args);
|
|
328
|
+
|
|
329
|
+
if (ptr == nullptr) {
|
|
330
|
+
throw TypeError::New(env, "readInt64: Cannot read from nullptr pointer");
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
int64_t val = *reinterpret_cast<int64_t*>(ptr);
|
|
334
|
+
|
|
335
|
+
if (val < JS_MIN_INT || val > JS_MAX_INT) {
|
|
336
|
+
char strbuf[128];
|
|
337
|
+
snprintf(strbuf, 128, "%" PRId64, val);
|
|
338
|
+
return String::New(env, strbuf);
|
|
339
|
+
} else {
|
|
340
|
+
return Number::New(env, val);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
Value ReadInt32(const CallbackInfo& args) {
|
|
345
|
+
Env env = args.Env();
|
|
346
|
+
char* ptr = AddressForArgs(args);
|
|
347
|
+
|
|
348
|
+
if (ptr == nullptr) {
|
|
349
|
+
throw TypeError::New(env, "readInt64: Cannot read from nullptr pointer");
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
int32_t val = *reinterpret_cast<int32_t*>(ptr);
|
|
353
|
+
return Number::New(env, val);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
void WriteInt64(const CallbackInfo& args) {
|
|
357
|
+
Env env = args.Env();
|
|
358
|
+
char* ptr = AddressForArgs(args);
|
|
359
|
+
|
|
360
|
+
Value in = args[2];
|
|
361
|
+
int64_t val;
|
|
362
|
+
if (in.IsNumber()) {
|
|
363
|
+
val = in.As<Number>();
|
|
364
|
+
} else if (in.IsString()) {
|
|
365
|
+
char* endptr;
|
|
366
|
+
char* str;
|
|
367
|
+
int base = 0;
|
|
368
|
+
std::string _str = in.As<String>();
|
|
369
|
+
str = &_str[0];
|
|
370
|
+
|
|
371
|
+
errno = 0;
|
|
372
|
+
val = strtoll(str, &endptr, base);
|
|
373
|
+
|
|
374
|
+
if (endptr == str) {
|
|
375
|
+
throw TypeError::New(env,
|
|
376
|
+
"writeInt64: no digits we found in input String");
|
|
377
|
+
} else if (errno == ERANGE && (val == INT64_MAX || val == INT64_MIN)) {
|
|
378
|
+
throw TypeError::New(
|
|
379
|
+
env, "writeInt64: input String numerical value out of range");
|
|
380
|
+
} else if (errno != 0 && val == 0) {
|
|
381
|
+
char errmsg[200];
|
|
382
|
+
snprintf(errmsg, sizeof(errmsg), "writeInt64: %s", strerror(errno));
|
|
383
|
+
throw TypeError::New(env, errmsg);
|
|
384
|
+
}
|
|
385
|
+
} else {
|
|
386
|
+
throw TypeError::New(env,
|
|
387
|
+
"writeInt64: Number/String 64-bit value required");
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
*reinterpret_cast<int64_t*>(ptr) = val;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
void WriteInt32(const CallbackInfo& args) {
|
|
394
|
+
Env env = args.Env();
|
|
395
|
+
char* ptr = AddressForArgs(args);
|
|
396
|
+
|
|
397
|
+
Value in = args[2];
|
|
398
|
+
int64_t val;
|
|
399
|
+
if (in.IsNumber()) {
|
|
400
|
+
val = in.As<Number>();
|
|
401
|
+
} else if (in.IsString()) {
|
|
402
|
+
char* endptr;
|
|
403
|
+
char* str;
|
|
404
|
+
int base = 0;
|
|
405
|
+
std::string _str = in.As<String>();
|
|
406
|
+
str = &_str[0];
|
|
407
|
+
|
|
408
|
+
errno = 0;
|
|
409
|
+
val = strtoll(str, &endptr, base);
|
|
410
|
+
|
|
411
|
+
if (endptr == str) {
|
|
412
|
+
throw TypeError::New(env,
|
|
413
|
+
"writeInt32: no digits we found in input String");
|
|
414
|
+
} else if (errno == ERANGE && (val == INT32_MAX || val == INT32_MIN)) {
|
|
415
|
+
throw TypeError::New(
|
|
416
|
+
env, "writeInt32: input String numerical value out of range");
|
|
417
|
+
} else if (errno != 0 && val == 0) {
|
|
418
|
+
char errmsg[200];
|
|
419
|
+
snprintf(errmsg, sizeof(errmsg), "writeInt32: %s", strerror(errno));
|
|
420
|
+
throw TypeError::New(env, errmsg);
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
throw TypeError::New(env,
|
|
424
|
+
"writeInt32: Number/String 32-bit value required");
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (val < INT32_MIN || val > INT32_MAX) {
|
|
428
|
+
throw TypeError::New(env, "writeInt32: value out of range");
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
*reinterpret_cast<int32_t*>(ptr) = static_cast<int32_t>(val);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
Value ReadUInt32(const CallbackInfo& args) {
|
|
435
|
+
Env env = args.Env();
|
|
436
|
+
char* ptr = AddressForArgs(args);
|
|
437
|
+
|
|
438
|
+
if (ptr == nullptr) {
|
|
439
|
+
throw TypeError::New(env, "readUInt32: Cannot read from nullptr pointer");
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
uint32_t val = *reinterpret_cast<uint32_t*>(ptr);
|
|
443
|
+
return Number::New(env, val);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
Value ReadInt8(const CallbackInfo& args) {
|
|
447
|
+
Env env = args.Env();
|
|
448
|
+
char* ptr = AddressForArgs(args);
|
|
449
|
+
|
|
450
|
+
if (ptr == nullptr) {
|
|
451
|
+
throw TypeError::New(env, "readInt8: Cannot read from nullptr pointer");
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
int8_t val = *reinterpret_cast<int8_t*>(ptr);
|
|
455
|
+
return Number::New(env, val);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
Value ReadUInt8(const CallbackInfo& args) {
|
|
459
|
+
Env env = args.Env();
|
|
460
|
+
char* ptr = AddressForArgs(args);
|
|
461
|
+
|
|
462
|
+
if (ptr == nullptr) {
|
|
463
|
+
throw TypeError::New(env, "readUInt8: Cannot read from nullptr pointer");
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
uint8_t val = *reinterpret_cast<uint8_t*>(ptr);
|
|
467
|
+
return Number::New(env, val);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
Value ReadFloat(const CallbackInfo& args) {
|
|
471
|
+
Env env = args.Env();
|
|
472
|
+
char* ptr = AddressForArgs(args);
|
|
473
|
+
|
|
474
|
+
if (ptr == nullptr) {
|
|
475
|
+
throw TypeError::New(env, "readFloat: Cannot read from nullptr pointer");
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
float val = *reinterpret_cast<float*>(ptr);
|
|
479
|
+
return Number::New(env, val);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
Value ReadDouble(const CallbackInfo& args) {
|
|
483
|
+
Env env = args.Env();
|
|
484
|
+
char* ptr = AddressForArgs(args);
|
|
485
|
+
|
|
486
|
+
if (ptr == nullptr) {
|
|
487
|
+
throw TypeError::New(env, "readDouble: Cannot read from nullptr pointer");
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
double val = *reinterpret_cast<double*>(ptr);
|
|
491
|
+
return Number::New(env, val);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
Value ReadInt16(const CallbackInfo& args) {
|
|
495
|
+
Env env = args.Env();
|
|
496
|
+
char* ptr = AddressForArgs(args);
|
|
497
|
+
|
|
498
|
+
if (ptr == nullptr) {
|
|
499
|
+
throw TypeError::New(env, "readInt16: Cannot read from nullptr pointer");
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
int16_t val = *reinterpret_cast<int16_t*>(ptr);
|
|
503
|
+
return Number::New(env, val);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
Value ReadUInt16(const CallbackInfo& args) {
|
|
507
|
+
Env env = args.Env();
|
|
508
|
+
char* ptr = AddressForArgs(args);
|
|
509
|
+
|
|
510
|
+
if (ptr == nullptr) {
|
|
511
|
+
throw TypeError::New(env, "readUInt16: Cannot read from nullptr pointer");
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
uint16_t val = *reinterpret_cast<uint16_t*>(ptr);
|
|
515
|
+
return Number::New(env, val);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
Value ReadUInt64(const CallbackInfo& args) {
|
|
519
|
+
Env env = args.Env();
|
|
520
|
+
char* ptr = AddressForArgs(args);
|
|
521
|
+
|
|
522
|
+
if (ptr == nullptr) {
|
|
523
|
+
throw TypeError::New(env, "readUInt64: Cannot read from nullptr pointer");
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
uint64_t val = *reinterpret_cast<uint64_t*>(ptr);
|
|
527
|
+
|
|
528
|
+
if (val > JS_MAX_INT) {
|
|
529
|
+
char strbuf[128];
|
|
530
|
+
snprintf(strbuf, 128, "%" PRIu64, val);
|
|
531
|
+
return String::New(env, strbuf);
|
|
532
|
+
} else {
|
|
533
|
+
return Number::New(env, val);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
void WriteUInt64(const CallbackInfo& args) {
|
|
538
|
+
Env env = args.Env();
|
|
539
|
+
char* ptr = AddressForArgs(args);
|
|
540
|
+
|
|
541
|
+
Value in = args[2];
|
|
542
|
+
uint64_t val;
|
|
543
|
+
if (in.IsNumber()) {
|
|
544
|
+
val = static_cast<int64_t>(in.As<Number>());
|
|
545
|
+
} else if (in.IsString()) {
|
|
546
|
+
char* endptr;
|
|
547
|
+
char* str;
|
|
548
|
+
int base = 0;
|
|
549
|
+
std::string _str = in.As<String>();
|
|
550
|
+
str = &_str[0];
|
|
551
|
+
|
|
552
|
+
errno = 0;
|
|
553
|
+
val = strtoull(str, &endptr, base);
|
|
554
|
+
|
|
555
|
+
if (endptr == str) {
|
|
556
|
+
throw TypeError::New(env,
|
|
557
|
+
"writeUInt64: no digits we found in input String");
|
|
558
|
+
} else if (errno == ERANGE && (val == UINT64_MAX)) {
|
|
559
|
+
throw TypeError::New(
|
|
560
|
+
env, "writeUInt64: input String numerical value out of range");
|
|
561
|
+
} else if (errno != 0 && val == 0) {
|
|
562
|
+
char errmsg[200];
|
|
563
|
+
snprintf(errmsg, sizeof(errmsg), "writeUInt64: %s", strerror(errno));
|
|
564
|
+
throw TypeError::New(env, errmsg);
|
|
565
|
+
}
|
|
566
|
+
} else {
|
|
567
|
+
throw TypeError::New(env,
|
|
568
|
+
"writeUInt64: Number/String 64-bit value required");
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
*reinterpret_cast<uint64_t*>(ptr) = val;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
Value ReadCString(const CallbackInfo& args) {
|
|
575
|
+
Env env = args.Env();
|
|
576
|
+
char* ptr = AddressForArgs(args);
|
|
577
|
+
|
|
578
|
+
if (ptr == nullptr) {
|
|
579
|
+
throw Error::New(env, "readCString: Cannot read from nullptr pointer");
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return String::New(env, ptr);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
Value ReinterpretBuffer(const CallbackInfo& args) {
|
|
586
|
+
Env env = args.Env();
|
|
587
|
+
char* ptr = AddressForArgs(args, 2);
|
|
588
|
+
|
|
589
|
+
if (ptr == nullptr) {
|
|
590
|
+
throw Error::New(env,
|
|
591
|
+
"reinterpret: Cannot reinterpret from nullptr pointer");
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
int64_t size = args[1].ToNumber();
|
|
595
|
+
|
|
596
|
+
return CreatePointerBuffer(env, ptr, size);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
Value ReinterpretBufferUntilZeros(const CallbackInfo& args) {
|
|
600
|
+
Env env = args.Env();
|
|
601
|
+
char* ptr = AddressForArgs(args, 2);
|
|
602
|
+
|
|
603
|
+
if (ptr == nullptr) {
|
|
604
|
+
throw Error::New(
|
|
605
|
+
env, "reinterpretUntilZeros: Cannot reinterpret from nullptr pointer");
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
uint32_t numZeros = args[1].ToNumber();
|
|
609
|
+
uint32_t i = 0;
|
|
610
|
+
size_t size = 0;
|
|
611
|
+
bool end = false;
|
|
612
|
+
|
|
613
|
+
while (!end && size < kMaxLength) {
|
|
614
|
+
end = true;
|
|
615
|
+
for (i = 0; i < numZeros; i++) {
|
|
616
|
+
if (ptr[size + i] != 0) {
|
|
617
|
+
end = false;
|
|
618
|
+
break;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
if (!end) {
|
|
622
|
+
size += numZeros;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return CreatePointerBuffer(env, ptr, size);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
} // namespace
|
|
630
|
+
|
|
631
|
+
Napi::Object InitRefNapi(Napi::Env env) {
|
|
632
|
+
Object exports = Object::New(env);
|
|
633
|
+
InstanceData* data = new InstanceData(env);
|
|
634
|
+
env.SetInstanceData<InstanceData>(data);
|
|
635
|
+
|
|
636
|
+
exports["instance"] = External<RefNapi::Instance>::New(env, data);
|
|
637
|
+
|
|
638
|
+
PointerBuffer::Init(env, exports);
|
|
639
|
+
|
|
640
|
+
Object smap = Object::New(env);
|
|
641
|
+
#define SET_SIZEOF(name, type) smap[#name] = Number::New(env, sizeof(type));
|
|
642
|
+
SET_SIZEOF(int8, int8_t);
|
|
643
|
+
SET_SIZEOF(uint8, uint8_t);
|
|
644
|
+
SET_SIZEOF(int16, int16_t);
|
|
645
|
+
SET_SIZEOF(uint16, uint16_t);
|
|
646
|
+
SET_SIZEOF(int32, int32_t);
|
|
647
|
+
SET_SIZEOF(uint32, uint32_t);
|
|
648
|
+
SET_SIZEOF(int64, int64_t);
|
|
649
|
+
SET_SIZEOF(uint64, uint64_t);
|
|
650
|
+
SET_SIZEOF(float, float);
|
|
651
|
+
SET_SIZEOF(double, double);
|
|
652
|
+
SET_SIZEOF(bool, bool);
|
|
653
|
+
SET_SIZEOF(byte, unsigned char);
|
|
654
|
+
SET_SIZEOF(char, char);
|
|
655
|
+
SET_SIZEOF(uchar, unsigned char);
|
|
656
|
+
SET_SIZEOF(short, short);
|
|
657
|
+
SET_SIZEOF(ushort, unsigned short);
|
|
658
|
+
SET_SIZEOF(int, int);
|
|
659
|
+
SET_SIZEOF(uint, unsigned int);
|
|
660
|
+
SET_SIZEOF(long, long);
|
|
661
|
+
SET_SIZEOF(ulong, unsigned long);
|
|
662
|
+
SET_SIZEOF(longlong, long long);
|
|
663
|
+
SET_SIZEOF(ulonglong, unsigned long long);
|
|
664
|
+
SET_SIZEOF(pointer, char*);
|
|
665
|
+
SET_SIZEOF(size_t, size_t);
|
|
666
|
+
SET_SIZEOF(Object, Reference<Object>);
|
|
667
|
+
#undef SET_SIZEOF
|
|
668
|
+
|
|
669
|
+
Object amap = Object::New(env);
|
|
670
|
+
#define SET_ALIGNOF(name, type) \
|
|
671
|
+
struct s_##name { \
|
|
672
|
+
type a; \
|
|
673
|
+
}; \
|
|
674
|
+
amap[#name] = Number::New(env, alignof(struct s_##name));
|
|
675
|
+
SET_ALIGNOF(int8, int8_t);
|
|
676
|
+
SET_ALIGNOF(uint8, uint8_t);
|
|
677
|
+
SET_ALIGNOF(int16, int16_t);
|
|
678
|
+
SET_ALIGNOF(uint16, uint16_t);
|
|
679
|
+
SET_ALIGNOF(int32, int32_t);
|
|
680
|
+
SET_ALIGNOF(uint32, uint32_t);
|
|
681
|
+
SET_ALIGNOF(int64, int64_t);
|
|
682
|
+
SET_ALIGNOF(uint64, uint64_t);
|
|
683
|
+
SET_ALIGNOF(float, float);
|
|
684
|
+
SET_ALIGNOF(double, double);
|
|
685
|
+
SET_ALIGNOF(bool, bool);
|
|
686
|
+
SET_ALIGNOF(char, char);
|
|
687
|
+
SET_ALIGNOF(uchar, unsigned char);
|
|
688
|
+
SET_ALIGNOF(short, short);
|
|
689
|
+
SET_ALIGNOF(ushort, unsigned short);
|
|
690
|
+
SET_ALIGNOF(int, int);
|
|
691
|
+
SET_ALIGNOF(uint, unsigned int);
|
|
692
|
+
SET_ALIGNOF(long, long);
|
|
693
|
+
SET_ALIGNOF(ulong, unsigned long);
|
|
694
|
+
SET_ALIGNOF(longlong, long long);
|
|
695
|
+
SET_ALIGNOF(ulonglong, unsigned long long);
|
|
696
|
+
SET_ALIGNOF(pointer, char*);
|
|
697
|
+
SET_ALIGNOF(size_t, size_t);
|
|
698
|
+
SET_ALIGNOF(Object, Reference<Object>);
|
|
699
|
+
#undef SET_ALIGNOF
|
|
700
|
+
|
|
701
|
+
exports["sizeof"] = smap;
|
|
702
|
+
exports["alignof"] = amap;
|
|
703
|
+
exports["nullptr"] = exports["NULL"] = CreatePointerBuffer(env, nullptr, 0);
|
|
704
|
+
exports["address"] = Function::New(env, Address);
|
|
705
|
+
exports["hexAddress"] = Function::New(env, HexAddress);
|
|
706
|
+
exports["isNull"] = Function::New(env, IsNull);
|
|
707
|
+
exports["isAddress"] = Function::New(env, IsAddress);
|
|
708
|
+
exports["readObject"] = Function::New(env, ReadObject);
|
|
709
|
+
exports["_writeObject"] = Function::New(env, WriteObject);
|
|
710
|
+
exports["readPointer"] = Function::New(env, ReadPointer);
|
|
711
|
+
exports["_writePointer"] = Function::New(env, WritePointer);
|
|
712
|
+
exports["readInt64"] = Function::New(env, ReadInt64);
|
|
713
|
+
exports["writeInt64"] = Function::New(env, WriteInt64);
|
|
714
|
+
exports["readUInt64"] = Function::New(env, ReadUInt64);
|
|
715
|
+
exports["writeUInt64"] = Function::New(env, WriteUInt64);
|
|
716
|
+
|
|
717
|
+
exports["readInt32"] = Function::New(env, ReadInt32);
|
|
718
|
+
exports["writeInt32"] = Function::New(env, WriteInt32);
|
|
719
|
+
|
|
720
|
+
exports["readUInt32"] = Function::New(env, ReadUInt32);
|
|
721
|
+
exports["readInt8"] = Function::New(env, ReadInt8);
|
|
722
|
+
exports["readUInt8"] = Function::New(env, ReadUInt8);
|
|
723
|
+
exports["readFloat"] = Function::New(env, ReadFloat);
|
|
724
|
+
exports["readDouble"] = Function::New(env, ReadDouble);
|
|
725
|
+
exports["readInt16"] = Function::New(env, ReadInt16);
|
|
726
|
+
exports["readUInt16"] = Function::New(env, ReadUInt16);
|
|
727
|
+
|
|
728
|
+
exports["readCString"] = Function::New(env, ReadCString);
|
|
729
|
+
exports["_reinterpret"] = Function::New(env, ReinterpretBuffer);
|
|
730
|
+
exports["_reinterpretUntilZeros"] =
|
|
731
|
+
Function::New(env, ReinterpretBufferUntilZeros);
|
|
732
|
+
|
|
733
|
+
return exports;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
} // namespace rclnodejs
|