@@ -61,6 +61,133 @@ namespace v8impl {
61
61
62
62
namespace {
63
63
64
+ template <typename CCharType, typename StringMaker>
65
+ napi_status NewString (napi_env env,
66
+ const CCharType* str,
67
+ size_t length,
68
+ napi_value* result,
69
+ StringMaker string_maker) {
70
+ CHECK_ENV (env);
71
+ if (length > 0 ) CHECK_ARG (env, str);
72
+ CHECK_ARG (env, result);
73
+ RETURN_STATUS_IF_FALSE (
74
+ env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
75
+
76
+ auto isolate = env->isolate ;
77
+ auto str_maybe = string_maker (isolate);
78
+ CHECK_MAYBE_EMPTY (env, str_maybe, napi_generic_failure);
79
+ *result = v8impl::JsValueFromV8LocalValue (str_maybe.ToLocalChecked ());
80
+ return napi_clear_last_error (env);
81
+ }
82
+
83
+ template <typename CharType, typename CreateAPI, typename StringMaker>
84
+ napi_status NewExternalString (napi_env env,
85
+ CharType* str,
86
+ size_t length,
87
+ napi_finalize finalize_callback,
88
+ void * finalize_hint,
89
+ napi_value* result,
90
+ bool * copied,
91
+ CreateAPI create_api,
92
+ StringMaker string_maker) {
93
+ napi_status status;
94
+ #if defined(V8_ENABLE_SANDBOX)
95
+ status = create_api (env, str, length, result);
96
+ if (status == napi_ok) {
97
+ if (copied != nullptr ) {
98
+ *copied = true ;
99
+ }
100
+ if (finalize_callback) {
101
+ env->CallFinalizer (
102
+ finalize_callback, static_cast <CharType*>(str), finalize_hint);
103
+ }
104
+ }
105
+ #else
106
+ status = NewString (env, str, length, result, string_maker);
107
+ if (status == napi_ok && copied != nullptr ) {
108
+ *copied = false ;
109
+ }
110
+ #endif // V8_ENABLE_SANDBOX
111
+ return status;
112
+ }
113
+
114
+ class TrackedStringResource : public Finalizer , RefTracker {
115
+ public:
116
+ TrackedStringResource (napi_env env,
117
+ napi_finalize finalize_callback,
118
+ void * data,
119
+ void * finalize_hint)
120
+ : Finalizer(env, finalize_callback, data, finalize_hint) {
121
+ Link (finalize_callback == nullptr ? &env->reflist
122
+ : &env->finalizing_reflist );
123
+ }
124
+
125
+ protected:
126
+ // The only time Finalize() gets called before Dispose() is if the
127
+ // environment is dying. Finalize() expects that the item will be unlinked,
128
+ // so we do it here. V8 will still call Dispose() on us later, so we don't do
129
+ // any deleting here. We just null out env_ to avoid passing a stale pointer
130
+ // to the user's finalizer when V8 does finally call Dispose().
131
+ void Finalize () override {
132
+ Unlink ();
133
+ env_ = nullptr ;
134
+ }
135
+
136
+ ~TrackedStringResource () {
137
+ if (finalize_callback_ == nullptr ) return ;
138
+ if (env_ == nullptr ) {
139
+ // The environment is dead. Call the finalizer directly.
140
+ finalize_callback_ (nullptr , finalize_data_, finalize_hint_);
141
+ } else {
142
+ // The environment is still alive. Let's remove ourselves from its list
143
+ // of references and call the user's finalizer.
144
+ Unlink ();
145
+ env_->CallFinalizer (finalize_callback_, finalize_data_, finalize_hint_);
146
+ }
147
+ }
148
+ };
149
+
150
+ class ExternalOneByteStringResource
151
+ : public v8::String::ExternalOneByteStringResource,
152
+ TrackedStringResource {
153
+ public:
154
+ ExternalOneByteStringResource (napi_env env,
155
+ char * string,
156
+ const size_t length,
157
+ napi_finalize finalize_callback,
158
+ void * finalize_hint)
159
+ : TrackedStringResource(env, finalize_callback, string, finalize_hint),
160
+ string_ (string),
161
+ length_(length) {}
162
+
163
+ const char * data () const override { return string_; }
164
+ size_t length () const override { return length_; }
165
+
166
+ private:
167
+ const char * string_;
168
+ const size_t length_;
169
+ };
170
+
171
+ class ExternalStringResource : public v8 ::String::ExternalStringResource,
172
+ TrackedStringResource {
173
+ public:
174
+ ExternalStringResource (napi_env env,
175
+ char16_t * string,
176
+ const size_t length,
177
+ napi_finalize finalize_callback,
178
+ void * finalize_hint)
179
+ : TrackedStringResource(env, finalize_callback, string, finalize_hint),
180
+ string_ (reinterpret_cast <uint16_t *>(string)),
181
+ length_(length) {}
182
+
183
+ const uint16_t * data () const override { return string_; }
184
+ size_t length () const override { return length_; }
185
+
186
+ private:
187
+ const uint16_t * string_;
188
+ const size_t length_;
189
+ };
190
+
64
191
inline napi_status V8NameFromPropertyDescriptor (
65
192
napi_env env,
66
193
const napi_property_descriptor* p,
@@ -1389,62 +1516,88 @@ napi_status NAPI_CDECL napi_create_string_latin1(napi_env env,
1389
1516
const char * str,
1390
1517
size_t length,
1391
1518
napi_value* result) {
1392
- CHECK_ENV (env);
1393
- if (length > 0 ) CHECK_ARG (env, str);
1394
- CHECK_ARG (env, result);
1395
- RETURN_STATUS_IF_FALSE (
1396
- env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
1397
-
1398
- auto isolate = env->isolate ;
1399
- auto str_maybe =
1400
- v8::String::NewFromOneByte (isolate,
1401
- reinterpret_cast <const uint8_t *>(str),
1402
- v8::NewStringType::kNormal ,
1403
- length);
1404
- CHECK_MAYBE_EMPTY (env, str_maybe, napi_generic_failure);
1405
-
1406
- *result = v8impl::JsValueFromV8LocalValue (str_maybe.ToLocalChecked ());
1407
- return napi_clear_last_error (env);
1519
+ return v8impl::NewString (env, str, length, result, [&](v8::Isolate* isolate) {
1520
+ return v8::String::NewFromOneByte (isolate,
1521
+ reinterpret_cast <const uint8_t *>(str),
1522
+ v8::NewStringType::kNormal ,
1523
+ length);
1524
+ });
1408
1525
}
1409
1526
1410
1527
napi_status NAPI_CDECL napi_create_string_utf8 (napi_env env,
1411
1528
const char * str,
1412
1529
size_t length,
1413
1530
napi_value* result) {
1414
- CHECK_ENV (env);
1415
- if (length > 0 ) CHECK_ARG (env, str);
1416
- CHECK_ARG (env, result);
1417
- RETURN_STATUS_IF_FALSE (
1418
- env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
1419
-
1420
- auto isolate = env->isolate ;
1421
- auto str_maybe = v8::String::NewFromUtf8 (
1422
- isolate, str, v8::NewStringType::kNormal , static_cast <int >(length));
1423
- CHECK_MAYBE_EMPTY (env, str_maybe, napi_generic_failure);
1424
- *result = v8impl::JsValueFromV8LocalValue (str_maybe.ToLocalChecked ());
1425
- return napi_clear_last_error (env);
1531
+ return v8impl::NewString (env, str, length, result, [&](v8::Isolate* isolate) {
1532
+ return v8::String::NewFromUtf8 (
1533
+ isolate, str, v8::NewStringType::kNormal , static_cast <int >(length));
1534
+ });
1426
1535
}
1427
1536
1428
1537
napi_status NAPI_CDECL napi_create_string_utf16 (napi_env env,
1429
1538
const char16_t * str,
1430
1539
size_t length,
1431
1540
napi_value* result) {
1432
- CHECK_ENV (env);
1433
- if (length > 0 ) CHECK_ARG (env, str);
1434
- CHECK_ARG (env, result);
1435
- RETURN_STATUS_IF_FALSE (
1436
- env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
1541
+ return v8impl::NewString (env, str, length, result, [&](v8::Isolate* isolate) {
1542
+ return v8::String::NewFromTwoByte (isolate,
1543
+ reinterpret_cast <const uint16_t *>(str),
1544
+ v8::NewStringType::kNormal ,
1545
+ length);
1546
+ });
1547
+ }
1437
1548
1438
- auto isolate = env->isolate ;
1439
- auto str_maybe =
1440
- v8::String::NewFromTwoByte (isolate,
1441
- reinterpret_cast <const uint16_t *>(str),
1442
- v8::NewStringType::kNormal ,
1443
- length);
1444
- CHECK_MAYBE_EMPTY (env, str_maybe, napi_generic_failure);
1549
+ napi_status NAPI_CDECL
1550
+ node_api_create_external_string_latin1 (napi_env env,
1551
+ char * str,
1552
+ size_t length,
1553
+ napi_finalize finalize_callback,
1554
+ void * finalize_hint,
1555
+ napi_value* result,
1556
+ bool * copied) {
1557
+ return v8impl::NewExternalString (
1558
+ env,
1559
+ str,
1560
+ length,
1561
+ finalize_callback,
1562
+ finalize_hint,
1563
+ result,
1564
+ copied,
1565
+ napi_create_string_latin1,
1566
+ [&](v8::Isolate* isolate) {
1567
+ if (length == NAPI_AUTO_LENGTH) {
1568
+ length = (std::string_view (str)).length ();
1569
+ }
1570
+ auto resource = new v8impl::ExternalOneByteStringResource (
1571
+ env, str, length, finalize_callback, finalize_hint);
1572
+ return v8::String::NewExternalOneByte (isolate, resource);
1573
+ });
1574
+ }
1445
1575
1446
- *result = v8impl::JsValueFromV8LocalValue (str_maybe.ToLocalChecked ());
1447
- return napi_clear_last_error (env);
1576
+ napi_status NAPI_CDECL
1577
+ node_api_create_external_string_utf16 (napi_env env,
1578
+ char16_t * str,
1579
+ size_t length,
1580
+ napi_finalize finalize_callback,
1581
+ void * finalize_hint,
1582
+ napi_value* result,
1583
+ bool * copied) {
1584
+ return v8impl::NewExternalString (
1585
+ env,
1586
+ str,
1587
+ length,
1588
+ finalize_callback,
1589
+ finalize_hint,
1590
+ result,
1591
+ copied,
1592
+ napi_create_string_utf16,
1593
+ [&](v8::Isolate* isolate) {
1594
+ if (length == NAPI_AUTO_LENGTH) {
1595
+ length = (std::u16string_view (str)).length ();
1596
+ }
1597
+ auto resource = new v8impl::ExternalStringResource (
1598
+ env, str, length, finalize_callback, finalize_hint);
1599
+ return v8::String::NewExternalTwoByte (isolate, resource);
1600
+ });
1448
1601
}
1449
1602
1450
1603
napi_status NAPI_CDECL napi_create_double (napi_env env,
0 commit comments