msgpackr-extract 2.0.2 → 2.1.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/bin/download-prebuilds.js +11 -0
- package/package.json +21 -14
- package/src/.vs/ProjectSettings.json +3 -0
- package/src/.vs/VSWorkspaceState.json +7 -0
- package/src/.vs/slnx.sqlite +0 -0
- package/src/.vs/src/v16/.suo +0 -0
- package/src/.vs/src/v16/Browse.VC.db +0 -0
- package/src/.vs/src/v16/Browse.VC.db-shm +0 -0
- package/src/.vs/src/v16/Browse.VC.db-wal +0 -0
- package/src/extract.cpp +272 -272
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { dirname } = require('path');
|
|
4
|
+
const { fileURLToPath } = require('url');
|
|
5
|
+
const { exec } = require('child_process');
|
|
6
|
+
|
|
7
|
+
process.chdir(dirname(__dirname));
|
|
8
|
+
exec('prebuildify-ci download', (error, stdout, stderr) => {
|
|
9
|
+
console.error(stderr);
|
|
10
|
+
console.log(stdout);
|
|
11
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "msgpackr-extract",
|
|
3
3
|
"author": "Kris Zyp",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.1.2",
|
|
5
5
|
"description": "Node addon for string extraction for msgpackr",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -11,32 +11,39 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"install": "node-gyp-build-optional-packages",
|
|
13
13
|
"recompile": "node-gyp rebuild",
|
|
14
|
-
"before-publish": "prebuildify-ci download &&
|
|
15
|
-
"prebuild": "prebuildify --target 16.14.2",
|
|
16
|
-
"prebuild-
|
|
14
|
+
"before-publish": "prebuildify-ci download && node set-optional-deps.cjs",
|
|
15
|
+
"prebuild": "prebuildify-platform-packages --target 16.14.2",
|
|
16
|
+
"prebuild-win32": "prebuildify-platform-packages --target 16.14.2 && set ENABLE_V8_FUNCTIONS=false&& prebuildify-platform-packages --platform-packages --napi --target 16.14.2",
|
|
17
|
+
"prebuild-libc": "prebuildify-platform-packages --tag-libc --target 16.14.2 && ENABLE_V8_FUNCTIONS=false prebuildify-platform-packages --platform-packages --napi --tag-libc --target 16.14.2",
|
|
18
|
+
"prebuild-libc-alpine": "prebuildify-cross --image alpine --tag-libc --target 16.14.2",
|
|
17
19
|
"publish-all": "cd prebuilds/win32-x64 && npm publish --access public && cd ../darwin-x64 && npm publish --access public && cd ../darwin-arm64 && npm publish --access public && cd ../linux-x64 && npm publish --access public && cd ../linux-arm64 && npm publish --access public && cd ../linux-arm && npm publish --access public && cd ../.. && npm publish --access public",
|
|
18
20
|
"test": "node ./index.js"
|
|
19
21
|
},
|
|
20
22
|
"main": "./index.js",
|
|
21
23
|
"gypfile": true,
|
|
22
24
|
"dependencies": {
|
|
23
|
-
"node-gyp-build-optional-packages": "5.0.
|
|
25
|
+
"node-gyp-build-optional-packages": "5.0.3"
|
|
24
26
|
},
|
|
25
27
|
"files": [
|
|
26
28
|
"index.js",
|
|
27
29
|
"/src",
|
|
28
|
-
"/*.gyp"
|
|
30
|
+
"/*.gyp",
|
|
31
|
+
"/bin"
|
|
29
32
|
],
|
|
33
|
+
"bin": {
|
|
34
|
+
"download-msgpackr-prebuilds": "./bin/download-prebuilds.js"
|
|
35
|
+
},
|
|
30
36
|
"optionalDependencies": {
|
|
31
|
-
"@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.
|
|
32
|
-
"@msgpackr-extract/msgpackr-extract-darwin-x64": "2.
|
|
33
|
-
"@msgpackr-extract/msgpackr-extract-linux-arm": "2.
|
|
34
|
-
"@msgpackr-extract/msgpackr-extract-linux-arm64": "2.
|
|
35
|
-
"@msgpackr-extract/msgpackr-extract-linux-x64": "2.
|
|
36
|
-
"@msgpackr-extract/msgpackr-extract-win32-x64": "2.
|
|
37
|
+
"@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.1.2",
|
|
38
|
+
"@msgpackr-extract/msgpackr-extract-darwin-x64": "2.1.2",
|
|
39
|
+
"@msgpackr-extract/msgpackr-extract-linux-arm": "2.1.2",
|
|
40
|
+
"@msgpackr-extract/msgpackr-extract-linux-arm64": "2.1.2",
|
|
41
|
+
"@msgpackr-extract/msgpackr-extract-linux-x64": "2.1.2",
|
|
42
|
+
"@msgpackr-extract/msgpackr-extract-win32-x64": "2.1.2"
|
|
37
43
|
},
|
|
38
44
|
"devDependencies": {
|
|
39
|
-
"prebuildify": "
|
|
40
|
-
"prebuildify-ci": "^1.0.5"
|
|
45
|
+
"prebuildify-platform-packages": "5.0.0",
|
|
46
|
+
"prebuildify-ci": "^1.0.5",
|
|
47
|
+
"prebuildify-cross": "5.0.0"
|
|
41
48
|
}
|
|
42
49
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
package/src/extract.cpp
CHANGED
|
@@ -1,272 +1,272 @@
|
|
|
1
|
-
/*
|
|
2
|
-
This is responsible for extracting the strings, in bulk, from a MessagePack buffer. Creating strings from buffers can
|
|
3
|
-
be one of the biggest performance bottlenecks of parsing, but creating an array of extracting strings all at once
|
|
4
|
-
provides much better performance. This will parse and produce up to 256 strings at once .The JS parser can call this multiple
|
|
5
|
-
times as necessary to get more strings. This must be partially capable of parsing MessagePack so it can know where to
|
|
6
|
-
find the string tokens and determine their position and length. All strings are decoded as UTF-8.
|
|
7
|
-
*/
|
|
8
|
-
#include <node_api.h>
|
|
9
|
-
#if ENABLE_V8_API
|
|
10
|
-
#include <v8.h>
|
|
11
|
-
#endif
|
|
12
|
-
|
|
13
|
-
#ifndef thread_local
|
|
14
|
-
#ifdef __GNUC__
|
|
15
|
-
# define thread_local __thread
|
|
16
|
-
#elif __STDC_VERSION__ >= 201112L
|
|
17
|
-
# define thread_local _Thread_local
|
|
18
|
-
#elif defined(_MSC_VER)
|
|
19
|
-
# define thread_local __declspec(thread)
|
|
20
|
-
#else
|
|
21
|
-
# define thread_local
|
|
22
|
-
#endif
|
|
23
|
-
#endif
|
|
24
|
-
|
|
25
|
-
const int MAX_TARGET_SIZE = 255;
|
|
26
|
-
typedef int (*token_handler)(uint8_t* source, int position, int size);
|
|
27
|
-
token_handler tokenTable[256] = {};
|
|
28
|
-
napi_value unexpectedEnd(napi_env env) {
|
|
29
|
-
napi_value returnValue;
|
|
30
|
-
napi_get_undefined(env, &returnValue);
|
|
31
|
-
napi_throw_type_error(env, NULL, "Unexpected end of buffer reading string");
|
|
32
|
-
return returnValue;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
class Extractor {
|
|
36
|
-
public:
|
|
37
|
-
// napi_ref targetArray; // could consider reenabling this optimization for napi
|
|
38
|
-
bool hasTargetArray = false;
|
|
39
|
-
uint8_t* source;
|
|
40
|
-
int position = 0;
|
|
41
|
-
int writePosition = 0;
|
|
42
|
-
int stringStart = 0;
|
|
43
|
-
int lastStringEnd = 0;
|
|
44
|
-
|
|
45
|
-
void readString(napi_env env, int length, bool allowStringBlocks, napi_value* target) {
|
|
46
|
-
int start = position;
|
|
47
|
-
int end = position + length;
|
|
48
|
-
if (allowStringBlocks) { // for larger strings, we don't bother to check every character for being latin, and just go right to creating a new string
|
|
49
|
-
while(position < end) {
|
|
50
|
-
if (source[position] < 0x80) // ensure we character is latin and can be decoded as one byte
|
|
51
|
-
position++;
|
|
52
|
-
else {
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
if (position < end) {
|
|
58
|
-
// non-latin character
|
|
59
|
-
if (lastStringEnd) {
|
|
60
|
-
napi_value value;
|
|
61
|
-
napi_create_string_latin1(env, (const char*) source + stringStart, lastStringEnd - stringStart, &value);
|
|
62
|
-
target[writePosition++] = value;
|
|
63
|
-
lastStringEnd = 0;
|
|
64
|
-
}
|
|
65
|
-
// use standard utf-8 conversion
|
|
66
|
-
napi_value value;
|
|
67
|
-
napi_create_string_utf8(env, (const char*) source + start, (int) length, &value);
|
|
68
|
-
target[writePosition++] = value;
|
|
69
|
-
position = end;
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (lastStringEnd) {
|
|
74
|
-
if (start - lastStringEnd > 40 || end - stringStart > 6000) {
|
|
75
|
-
napi_value value;
|
|
76
|
-
napi_create_string_latin1(env, (const char*) source + stringStart, lastStringEnd - stringStart, &value);
|
|
77
|
-
target[writePosition++] = value;
|
|
78
|
-
stringStart = start;
|
|
79
|
-
}
|
|
80
|
-
} else {
|
|
81
|
-
stringStart = start;
|
|
82
|
-
}
|
|
83
|
-
lastStringEnd = end;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
napi_value extractStrings(napi_env env, int startingPosition, int size, uint8_t* inputSource) {
|
|
87
|
-
napi_value target[MAX_TARGET_SIZE + 1]; // leave one for the queued string
|
|
88
|
-
writePosition = 0;
|
|
89
|
-
lastStringEnd = 0;
|
|
90
|
-
position = startingPosition;
|
|
91
|
-
source = inputSource;
|
|
92
|
-
while (position < size) {
|
|
93
|
-
uint8_t token = source[position++];
|
|
94
|
-
if (token < 0xa0) {
|
|
95
|
-
// all one byte tokens
|
|
96
|
-
} else if (token < 0xc0) {
|
|
97
|
-
// fixstr, we want to convert this
|
|
98
|
-
token -= 0xa0;
|
|
99
|
-
if (token + position > size) {
|
|
100
|
-
return unexpectedEnd(env);
|
|
101
|
-
}
|
|
102
|
-
readString(env, token, true, target);
|
|
103
|
-
if (writePosition >= MAX_TARGET_SIZE)
|
|
104
|
-
break;
|
|
105
|
-
} else if (token <= 0xdb && token >= 0xd9) {
|
|
106
|
-
if (token == 0xd9) { //str 8
|
|
107
|
-
if (position >= size) {
|
|
108
|
-
return unexpectedEnd(env);
|
|
109
|
-
}
|
|
110
|
-
int length = source[position++];
|
|
111
|
-
if (length + position > size) {
|
|
112
|
-
return unexpectedEnd(env);
|
|
113
|
-
}
|
|
114
|
-
readString(env,length, true, target);
|
|
115
|
-
} else if (token == 0xda) { //str 16
|
|
116
|
-
if (2 + position > size) {
|
|
117
|
-
return unexpectedEnd(env);
|
|
118
|
-
}
|
|
119
|
-
int length = source[position++] << 8;
|
|
120
|
-
length += source[position++];
|
|
121
|
-
if (length + position > size) {
|
|
122
|
-
return unexpectedEnd(env);
|
|
123
|
-
}
|
|
124
|
-
readString(env,length, false, target);
|
|
125
|
-
} else { //str 32
|
|
126
|
-
if (4 + position > size) {
|
|
127
|
-
return unexpectedEnd(env);
|
|
128
|
-
}
|
|
129
|
-
int length = source[position++] << 24;
|
|
130
|
-
length += source[position++] << 16;
|
|
131
|
-
length += source[position++] << 8;
|
|
132
|
-
length += source[position++];
|
|
133
|
-
if (length + position > size) {
|
|
134
|
-
return unexpectedEnd(env);
|
|
135
|
-
}
|
|
136
|
-
readString(env, length, false, target);
|
|
137
|
-
}
|
|
138
|
-
if (writePosition >= MAX_TARGET_SIZE)
|
|
139
|
-
break;
|
|
140
|
-
} else {
|
|
141
|
-
auto handle = tokenTable[token];
|
|
142
|
-
if ((size_t ) handle < 20) {
|
|
143
|
-
position += (size_t ) handle;
|
|
144
|
-
} else {
|
|
145
|
-
position = tokenTable[token](source, position, size);
|
|
146
|
-
if (position < 0) {
|
|
147
|
-
return unexpectedEnd(env);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (lastStringEnd) {
|
|
154
|
-
napi_value value;
|
|
155
|
-
napi_create_string_latin1(env, (const char*) source + stringStart, lastStringEnd - stringStart, &value);
|
|
156
|
-
if (writePosition == 0) {
|
|
157
|
-
return value;
|
|
158
|
-
}
|
|
159
|
-
target[writePosition++] = value;
|
|
160
|
-
} else if (writePosition == 1) {
|
|
161
|
-
return target[0];
|
|
162
|
-
}
|
|
163
|
-
napi_value array;
|
|
164
|
-
#if ENABLE_V8_API
|
|
165
|
-
v8::Local<v8::Array> v8Array = v8::Array::New(v8::Isolate::GetCurrent(), (v8::Local<v8::Value>*) target, writePosition);
|
|
166
|
-
memcpy(&array, &v8Array, sizeof(array));
|
|
167
|
-
#else
|
|
168
|
-
napi_create_array_with_length(env, writePosition, &array);
|
|
169
|
-
for (int i = 0; i < writePosition; i++) {
|
|
170
|
-
napi_set_element(env, array, i, target[i]);
|
|
171
|
-
}
|
|
172
|
-
#endif
|
|
173
|
-
return array;
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
void setupTokenTable() {
|
|
178
|
-
for (int i = 0; i < 256; i++) {
|
|
179
|
-
tokenTable[i] = nullptr;
|
|
180
|
-
}
|
|
181
|
-
// uint8, int8
|
|
182
|
-
tokenTable[0xcc] = tokenTable[0xd0] = (token_handler) 1;
|
|
183
|
-
// uint16, int16, array 16, map 16, fixext 1
|
|
184
|
-
tokenTable[0xcd] = tokenTable[0xd1] = tokenTable[0xdc] = tokenTable[0xde] = tokenTable[0xd4] = (token_handler) 2;
|
|
185
|
-
// fixext 16
|
|
186
|
-
tokenTable[0xd5] = (token_handler) 3;
|
|
187
|
-
// uint32, int32, float32, array 32, map 32
|
|
188
|
-
tokenTable[0xce] = tokenTable[0xd2] = tokenTable[0xca] = tokenTable[0xdd] = tokenTable[0xdf] = (token_handler) 4;
|
|
189
|
-
// fixext 4
|
|
190
|
-
tokenTable[0xd6] = (token_handler) 5;
|
|
191
|
-
// uint64, int64, float64, fixext 8
|
|
192
|
-
tokenTable[0xcf] = tokenTable[0xd3] = tokenTable[0xcb] = (token_handler) 8;
|
|
193
|
-
// fixext 8
|
|
194
|
-
tokenTable[0xd7] = (token_handler) 9;
|
|
195
|
-
// fixext 16
|
|
196
|
-
tokenTable[0xd8] = (token_handler) 17;
|
|
197
|
-
// bin 8
|
|
198
|
-
tokenTable[0xc4] = ([](uint8_t* source, int position, int size) -> int {
|
|
199
|
-
if (position >= size) {
|
|
200
|
-
return -1;
|
|
201
|
-
}
|
|
202
|
-
int length = source[position++];
|
|
203
|
-
return position + length;
|
|
204
|
-
});
|
|
205
|
-
// bin 16
|
|
206
|
-
tokenTable[0xc5] = ([](uint8_t* source, int position, int size) -> int {
|
|
207
|
-
if (position + 2 > size) {
|
|
208
|
-
return -1;
|
|
209
|
-
}
|
|
210
|
-
int length = source[position++] << 8;
|
|
211
|
-
length += source[position++];
|
|
212
|
-
return position + length;
|
|
213
|
-
});
|
|
214
|
-
// bin 32
|
|
215
|
-
tokenTable[0xc6] = ([](uint8_t* source, int position, int size) -> int {
|
|
216
|
-
if (position + 4 > size)
|
|
217
|
-
return -1;
|
|
218
|
-
int length = source[position++] << 24;
|
|
219
|
-
length += source[position++] << 16;
|
|
220
|
-
length += source[position++] << 8;
|
|
221
|
-
length += source[position++];
|
|
222
|
-
return position + length;
|
|
223
|
-
});
|
|
224
|
-
// ext 8
|
|
225
|
-
tokenTable[0xc7] = ([](uint8_t* source, int position, int size) -> int {
|
|
226
|
-
if (position >= size)
|
|
227
|
-
return -1;
|
|
228
|
-
int length = source[position++];
|
|
229
|
-
position++;
|
|
230
|
-
return position + length;
|
|
231
|
-
});
|
|
232
|
-
// ext 16
|
|
233
|
-
tokenTable[0xc8] = ([](uint8_t* source, int position, int size) -> int {
|
|
234
|
-
if (position + 2 > size)
|
|
235
|
-
return -1;
|
|
236
|
-
int length = source[position++] << 8;
|
|
237
|
-
length += source[position++];
|
|
238
|
-
position++;
|
|
239
|
-
return position + length;
|
|
240
|
-
});
|
|
241
|
-
// ext 32
|
|
242
|
-
tokenTable[0xc9] = ([](uint8_t* source, int position, int size) -> int {
|
|
243
|
-
if (position + 4 > size)
|
|
244
|
-
return -1;
|
|
245
|
-
int length = source[position++] << 24;
|
|
246
|
-
length += source[position++] << 16;
|
|
247
|
-
length += source[position++] << 8;
|
|
248
|
-
length += source[position++];
|
|
249
|
-
position++;
|
|
250
|
-
return position + length;
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
static thread_local Extractor* extractor;
|
|
254
|
-
napi_value extractStrings(napi_env env, napi_callback_info info) {
|
|
255
|
-
size_t argc = 3;
|
|
256
|
-
napi_value args[3];
|
|
257
|
-
napi_get_cb_info(env, info, &argc, args, NULL, NULL);
|
|
258
|
-
uint32_t position;
|
|
259
|
-
uint32_t size;
|
|
260
|
-
napi_get_value_uint32(env, args[0], &position);
|
|
261
|
-
napi_get_value_uint32(env, args[1], &size);
|
|
262
|
-
uint8_t* source;
|
|
263
|
-
napi_get_typedarray_info(env, args[2], NULL, NULL, (void**) &source, NULL, NULL);
|
|
264
|
-
return extractor->extractStrings(env, position, size, source);
|
|
265
|
-
}
|
|
266
|
-
#define EXPORT_NAPI_FUNCTION(name, func) { napi_property_descriptor desc = { name, 0, func, 0, 0, 0, (napi_property_attributes) (napi_writable | napi_configurable), 0 }; napi_define_properties(env, exports, 1, &desc); }
|
|
267
|
-
NAPI_MODULE_INIT() {
|
|
268
|
-
extractor = new Extractor(); // create our thread-local extractor
|
|
269
|
-
setupTokenTable();
|
|
270
|
-
EXPORT_NAPI_FUNCTION("extractStrings", extractStrings);
|
|
271
|
-
return exports;
|
|
272
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
This is responsible for extracting the strings, in bulk, from a MessagePack buffer. Creating strings from buffers can
|
|
3
|
+
be one of the biggest performance bottlenecks of parsing, but creating an array of extracting strings all at once
|
|
4
|
+
provides much better performance. This will parse and produce up to 256 strings at once .The JS parser can call this multiple
|
|
5
|
+
times as necessary to get more strings. This must be partially capable of parsing MessagePack so it can know where to
|
|
6
|
+
find the string tokens and determine their position and length. All strings are decoded as UTF-8.
|
|
7
|
+
*/
|
|
8
|
+
#include <node_api.h>
|
|
9
|
+
#if ENABLE_V8_API
|
|
10
|
+
#include <v8.h>
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
#ifndef thread_local
|
|
14
|
+
#ifdef __GNUC__
|
|
15
|
+
# define thread_local __thread
|
|
16
|
+
#elif __STDC_VERSION__ >= 201112L
|
|
17
|
+
# define thread_local _Thread_local
|
|
18
|
+
#elif defined(_MSC_VER)
|
|
19
|
+
# define thread_local __declspec(thread)
|
|
20
|
+
#else
|
|
21
|
+
# define thread_local
|
|
22
|
+
#endif
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
const int MAX_TARGET_SIZE = 255;
|
|
26
|
+
typedef int (*token_handler)(uint8_t* source, int position, int size);
|
|
27
|
+
token_handler tokenTable[256] = {};
|
|
28
|
+
napi_value unexpectedEnd(napi_env env) {
|
|
29
|
+
napi_value returnValue;
|
|
30
|
+
napi_get_undefined(env, &returnValue);
|
|
31
|
+
napi_throw_type_error(env, NULL, "Unexpected end of buffer reading string");
|
|
32
|
+
return returnValue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class Extractor {
|
|
36
|
+
public:
|
|
37
|
+
// napi_ref targetArray; // could consider reenabling this optimization for napi
|
|
38
|
+
bool hasTargetArray = false;
|
|
39
|
+
uint8_t* source;
|
|
40
|
+
int position = 0;
|
|
41
|
+
int writePosition = 0;
|
|
42
|
+
int stringStart = 0;
|
|
43
|
+
int lastStringEnd = 0;
|
|
44
|
+
|
|
45
|
+
void readString(napi_env env, int length, bool allowStringBlocks, napi_value* target) {
|
|
46
|
+
int start = position;
|
|
47
|
+
int end = position + length;
|
|
48
|
+
if (allowStringBlocks) { // for larger strings, we don't bother to check every character for being latin, and just go right to creating a new string
|
|
49
|
+
while(position < end) {
|
|
50
|
+
if (source[position] < 0x80) // ensure we character is latin and can be decoded as one byte
|
|
51
|
+
position++;
|
|
52
|
+
else {
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (position < end) {
|
|
58
|
+
// non-latin character
|
|
59
|
+
if (lastStringEnd) {
|
|
60
|
+
napi_value value;
|
|
61
|
+
napi_create_string_latin1(env, (const char*) source + stringStart, lastStringEnd - stringStart, &value);
|
|
62
|
+
target[writePosition++] = value;
|
|
63
|
+
lastStringEnd = 0;
|
|
64
|
+
}
|
|
65
|
+
// use standard utf-8 conversion
|
|
66
|
+
napi_value value;
|
|
67
|
+
napi_create_string_utf8(env, (const char*) source + start, (int) length, &value);
|
|
68
|
+
target[writePosition++] = value;
|
|
69
|
+
position = end;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (lastStringEnd) {
|
|
74
|
+
if (start - lastStringEnd > 40 || end - stringStart > 6000) {
|
|
75
|
+
napi_value value;
|
|
76
|
+
napi_create_string_latin1(env, (const char*) source + stringStart, lastStringEnd - stringStart, &value);
|
|
77
|
+
target[writePosition++] = value;
|
|
78
|
+
stringStart = start;
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
stringStart = start;
|
|
82
|
+
}
|
|
83
|
+
lastStringEnd = end;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
napi_value extractStrings(napi_env env, int startingPosition, int size, uint8_t* inputSource) {
|
|
87
|
+
napi_value target[MAX_TARGET_SIZE + 1]; // leave one for the queued string
|
|
88
|
+
writePosition = 0;
|
|
89
|
+
lastStringEnd = 0;
|
|
90
|
+
position = startingPosition;
|
|
91
|
+
source = inputSource;
|
|
92
|
+
while (position < size) {
|
|
93
|
+
uint8_t token = source[position++];
|
|
94
|
+
if (token < 0xa0) {
|
|
95
|
+
// all one byte tokens
|
|
96
|
+
} else if (token < 0xc0) {
|
|
97
|
+
// fixstr, we want to convert this
|
|
98
|
+
token -= 0xa0;
|
|
99
|
+
if (token + position > size) {
|
|
100
|
+
return unexpectedEnd(env);
|
|
101
|
+
}
|
|
102
|
+
readString(env, token, true, target);
|
|
103
|
+
if (writePosition >= MAX_TARGET_SIZE)
|
|
104
|
+
break;
|
|
105
|
+
} else if (token <= 0xdb && token >= 0xd9) {
|
|
106
|
+
if (token == 0xd9) { //str 8
|
|
107
|
+
if (position >= size) {
|
|
108
|
+
return unexpectedEnd(env);
|
|
109
|
+
}
|
|
110
|
+
int length = source[position++];
|
|
111
|
+
if (length + position > size) {
|
|
112
|
+
return unexpectedEnd(env);
|
|
113
|
+
}
|
|
114
|
+
readString(env,length, true, target);
|
|
115
|
+
} else if (token == 0xda) { //str 16
|
|
116
|
+
if (2 + position > size) {
|
|
117
|
+
return unexpectedEnd(env);
|
|
118
|
+
}
|
|
119
|
+
int length = source[position++] << 8;
|
|
120
|
+
length += source[position++];
|
|
121
|
+
if (length + position > size) {
|
|
122
|
+
return unexpectedEnd(env);
|
|
123
|
+
}
|
|
124
|
+
readString(env,length, false, target);
|
|
125
|
+
} else { //str 32
|
|
126
|
+
if (4 + position > size) {
|
|
127
|
+
return unexpectedEnd(env);
|
|
128
|
+
}
|
|
129
|
+
int length = source[position++] << 24;
|
|
130
|
+
length += source[position++] << 16;
|
|
131
|
+
length += source[position++] << 8;
|
|
132
|
+
length += source[position++];
|
|
133
|
+
if (length + position > size) {
|
|
134
|
+
return unexpectedEnd(env);
|
|
135
|
+
}
|
|
136
|
+
readString(env, length, false, target);
|
|
137
|
+
}
|
|
138
|
+
if (writePosition >= MAX_TARGET_SIZE)
|
|
139
|
+
break;
|
|
140
|
+
} else {
|
|
141
|
+
auto handle = tokenTable[token];
|
|
142
|
+
if ((size_t ) handle < 20) {
|
|
143
|
+
position += (size_t ) handle;
|
|
144
|
+
} else {
|
|
145
|
+
position = tokenTable[token](source, position, size);
|
|
146
|
+
if (position < 0) {
|
|
147
|
+
return unexpectedEnd(env);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (lastStringEnd) {
|
|
154
|
+
napi_value value;
|
|
155
|
+
napi_create_string_latin1(env, (const char*) source + stringStart, lastStringEnd - stringStart, &value);
|
|
156
|
+
if (writePosition == 0) {
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
target[writePosition++] = value;
|
|
160
|
+
} else if (writePosition == 1) {
|
|
161
|
+
return target[0];
|
|
162
|
+
}
|
|
163
|
+
napi_value array;
|
|
164
|
+
#if ENABLE_V8_API
|
|
165
|
+
v8::Local<v8::Array> v8Array = v8::Array::New(v8::Isolate::GetCurrent(), (v8::Local<v8::Value>*) target, writePosition);
|
|
166
|
+
memcpy(&array, &v8Array, sizeof(array));
|
|
167
|
+
#else
|
|
168
|
+
napi_create_array_with_length(env, writePosition, &array);
|
|
169
|
+
for (int i = 0; i < writePosition; i++) {
|
|
170
|
+
napi_set_element(env, array, i, target[i]);
|
|
171
|
+
}
|
|
172
|
+
#endif
|
|
173
|
+
return array;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
void setupTokenTable() {
|
|
178
|
+
for (int i = 0; i < 256; i++) {
|
|
179
|
+
tokenTable[i] = nullptr;
|
|
180
|
+
}
|
|
181
|
+
// uint8, int8
|
|
182
|
+
tokenTable[0xcc] = tokenTable[0xd0] = (token_handler) 1;
|
|
183
|
+
// uint16, int16, array 16, map 16, fixext 1
|
|
184
|
+
tokenTable[0xcd] = tokenTable[0xd1] = tokenTable[0xdc] = tokenTable[0xde] = tokenTable[0xd4] = (token_handler) 2;
|
|
185
|
+
// fixext 16
|
|
186
|
+
tokenTable[0xd5] = (token_handler) 3;
|
|
187
|
+
// uint32, int32, float32, array 32, map 32
|
|
188
|
+
tokenTable[0xce] = tokenTable[0xd2] = tokenTable[0xca] = tokenTable[0xdd] = tokenTable[0xdf] = (token_handler) 4;
|
|
189
|
+
// fixext 4
|
|
190
|
+
tokenTable[0xd6] = (token_handler) 5;
|
|
191
|
+
// uint64, int64, float64, fixext 8
|
|
192
|
+
tokenTable[0xcf] = tokenTable[0xd3] = tokenTable[0xcb] = (token_handler) 8;
|
|
193
|
+
// fixext 8
|
|
194
|
+
tokenTable[0xd7] = (token_handler) 9;
|
|
195
|
+
// fixext 16
|
|
196
|
+
tokenTable[0xd8] = (token_handler) 17;
|
|
197
|
+
// bin 8
|
|
198
|
+
tokenTable[0xc4] = ([](uint8_t* source, int position, int size) -> int {
|
|
199
|
+
if (position >= size) {
|
|
200
|
+
return -1;
|
|
201
|
+
}
|
|
202
|
+
int length = source[position++];
|
|
203
|
+
return position + length;
|
|
204
|
+
});
|
|
205
|
+
// bin 16
|
|
206
|
+
tokenTable[0xc5] = ([](uint8_t* source, int position, int size) -> int {
|
|
207
|
+
if (position + 2 > size) {
|
|
208
|
+
return -1;
|
|
209
|
+
}
|
|
210
|
+
int length = source[position++] << 8;
|
|
211
|
+
length += source[position++];
|
|
212
|
+
return position + length;
|
|
213
|
+
});
|
|
214
|
+
// bin 32
|
|
215
|
+
tokenTable[0xc6] = ([](uint8_t* source, int position, int size) -> int {
|
|
216
|
+
if (position + 4 > size)
|
|
217
|
+
return -1;
|
|
218
|
+
int length = source[position++] << 24;
|
|
219
|
+
length += source[position++] << 16;
|
|
220
|
+
length += source[position++] << 8;
|
|
221
|
+
length += source[position++];
|
|
222
|
+
return position + length;
|
|
223
|
+
});
|
|
224
|
+
// ext 8
|
|
225
|
+
tokenTable[0xc7] = ([](uint8_t* source, int position, int size) -> int {
|
|
226
|
+
if (position >= size)
|
|
227
|
+
return -1;
|
|
228
|
+
int length = source[position++];
|
|
229
|
+
position++;
|
|
230
|
+
return position + length;
|
|
231
|
+
});
|
|
232
|
+
// ext 16
|
|
233
|
+
tokenTable[0xc8] = ([](uint8_t* source, int position, int size) -> int {
|
|
234
|
+
if (position + 2 > size)
|
|
235
|
+
return -1;
|
|
236
|
+
int length = source[position++] << 8;
|
|
237
|
+
length += source[position++];
|
|
238
|
+
position++;
|
|
239
|
+
return position + length;
|
|
240
|
+
});
|
|
241
|
+
// ext 32
|
|
242
|
+
tokenTable[0xc9] = ([](uint8_t* source, int position, int size) -> int {
|
|
243
|
+
if (position + 4 > size)
|
|
244
|
+
return -1;
|
|
245
|
+
int length = source[position++] << 24;
|
|
246
|
+
length += source[position++] << 16;
|
|
247
|
+
length += source[position++] << 8;
|
|
248
|
+
length += source[position++];
|
|
249
|
+
position++;
|
|
250
|
+
return position + length;
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
static thread_local Extractor* extractor;
|
|
254
|
+
napi_value extractStrings(napi_env env, napi_callback_info info) {
|
|
255
|
+
size_t argc = 3;
|
|
256
|
+
napi_value args[3];
|
|
257
|
+
napi_get_cb_info(env, info, &argc, args, NULL, NULL);
|
|
258
|
+
uint32_t position;
|
|
259
|
+
uint32_t size;
|
|
260
|
+
napi_get_value_uint32(env, args[0], &position);
|
|
261
|
+
napi_get_value_uint32(env, args[1], &size);
|
|
262
|
+
uint8_t* source;
|
|
263
|
+
napi_get_typedarray_info(env, args[2], NULL, NULL, (void**) &source, NULL, NULL);
|
|
264
|
+
return extractor->extractStrings(env, position, size, source);
|
|
265
|
+
}
|
|
266
|
+
#define EXPORT_NAPI_FUNCTION(name, func) { napi_property_descriptor desc = { name, 0, func, 0, 0, 0, (napi_property_attributes) (napi_writable | napi_configurable), 0 }; napi_define_properties(env, exports, 1, &desc); }
|
|
267
|
+
NAPI_MODULE_INIT() {
|
|
268
|
+
extractor = new Extractor(); // create our thread-local extractor
|
|
269
|
+
setupTokenTable();
|
|
270
|
+
EXPORT_NAPI_FUNCTION("extractStrings", extractStrings);
|
|
271
|
+
return exports;
|
|
272
|
+
}
|