yencode 1.0.8 → 1.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.
Files changed (49) hide show
  1. package/README.md +339 -231
  2. package/binding.gyp +292 -39
  3. package/crcutil-1.0/code/multiword_64_64_gcc_amd64_asm.cc +7 -7
  4. package/crcutil-1.0/code/multiword_64_64_gcc_i386_mmx.cc +14 -14
  5. package/crcutil-1.0/code/multiword_64_64_intrinsic_i386_mmx.cc +1 -1
  6. package/crcutil-1.0/code/uint128_sse2.h +2 -0
  7. package/index.js +329 -22
  8. package/package.json +2 -2
  9. package/src/common.h +299 -0
  10. package/src/crc.cc +95 -0
  11. package/src/crc.h +23 -0
  12. package/src/crc_arm.cc +175 -0
  13. package/src/crc_common.h +4 -0
  14. package/{crc_folding.c → src/crc_folding.cc} +175 -185
  15. package/src/decoder.cc +61 -0
  16. package/src/decoder.h +53 -0
  17. package/src/decoder_avx.cc +18 -0
  18. package/src/decoder_avx2.cc +18 -0
  19. package/src/decoder_avx2_base.h +615 -0
  20. package/src/decoder_common.h +512 -0
  21. package/src/decoder_neon.cc +474 -0
  22. package/src/decoder_neon64.cc +451 -0
  23. package/src/decoder_sse2.cc +16 -0
  24. package/src/decoder_sse_base.h +711 -0
  25. package/src/decoder_ssse3.cc +18 -0
  26. package/src/encoder.cc +170 -0
  27. package/src/encoder.h +21 -0
  28. package/src/encoder_avx.cc +16 -0
  29. package/src/encoder_avx2.cc +16 -0
  30. package/src/encoder_avx_base.h +564 -0
  31. package/src/encoder_common.h +109 -0
  32. package/src/encoder_neon.cc +547 -0
  33. package/src/encoder_sse2.cc +13 -0
  34. package/src/encoder_sse_base.h +724 -0
  35. package/src/encoder_ssse3.cc +18 -0
  36. package/src/hedley.h +1899 -0
  37. package/src/platform.cc +147 -0
  38. package/src/yencode.cc +449 -0
  39. package/test/_maxsize.js +9 -0
  40. package/test/_speedbase.js +147 -0
  41. package/test/speedcrc.js +20 -0
  42. package/test/speeddec.js +92 -0
  43. package/test/speedenc.js +44 -0
  44. package/{testcrc.js → test/testcrc.js} +53 -39
  45. package/test/testdec.js +183 -0
  46. package/test/testenc.js +163 -0
  47. package/test/testpostdec.js +126 -0
  48. package/test.js +0 -91
  49. package/yencode.cc +0 -1622
@@ -0,0 +1,147 @@
1
+ #include "common.h"
2
+ #ifdef PLATFORM_ARM
3
+ # ifdef __ANDROID__
4
+ # include <cpu-features.h>
5
+ # elif defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 12)
6
+ # include <sys/auxv.h>
7
+ # include <asm/hwcap.h>
8
+ # elif (defined(__FreeBSD__) && __FreeBSD__ < 12)
9
+ # include <sys/sysctl.h>
10
+ # include <asm/hwcap.h>
11
+ # elif defined(_WIN32)
12
+ # define WIN32_LEAN_AND_MEAN
13
+ # define NOMINMAX
14
+ # include <Windows.h>
15
+ # elif defined(__APPLE__)
16
+ # include <sys/types.h>
17
+ # include <sys/sysctl.h>
18
+ # endif
19
+ bool cpu_supports_neon() {
20
+ # if defined(AT_HWCAP)
21
+ # ifdef __FreeBSD__
22
+ unsigned long supported;
23
+ elf_aux_info(AT_HWCAP, &supported, sizeof(supported));
24
+ # ifdef __aarch64__
25
+ return supported & HWCAP_ASIMD;
26
+ # else
27
+ return supported & HWCAP_NEON;
28
+ # endif
29
+ # else
30
+ # ifdef __aarch64__
31
+ return getauxval(AT_HWCAP) & HWCAP_ASIMD;
32
+ # else
33
+ return getauxval(AT_HWCAP) & HWCAP_NEON;
34
+ # endif
35
+ # endif
36
+ # elif defined(ANDROID_CPU_FAMILY_ARM)
37
+ # ifdef __aarch64__
38
+ return android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_ASIMD;
39
+ # else
40
+ return android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON;
41
+ # endif
42
+ # elif defined(_WIN32)
43
+ return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
44
+ # elif defined(__APPLE__)
45
+ int supported = 0;
46
+ size_t len = sizeof(supported);
47
+ if(sysctlbyname("hw.optional.neon", &supported, &len, NULL, 0))
48
+ return false;
49
+ return (bool)supported;
50
+ # endif
51
+ return true; // assume NEON support, if compiled as such, otherwise (I think Windows and iOS require it)
52
+ }
53
+ #endif
54
+
55
+
56
+ #ifdef PLATFORM_X86
57
+ #ifdef _MSC_VER
58
+ # define _cpuid1x(ar) __cpuid(ar, 0x80000001)
59
+ # if _MSC_VER >= 1600
60
+ # define _cpuidX __cpuidex
61
+ # include <immintrin.h>
62
+ # define _GET_XCR() _xgetbv(_XCR_XFEATURE_ENABLED_MASK)
63
+ # else
64
+ // not supported
65
+ # define _cpuidX(ar, eax, ecx) ar[0]=0, ar[1]=0, ar[2]=0, ar[3]=0
66
+ # define _GET_XCR() 0
67
+ # endif
68
+ #else
69
+ # define _cpuid1x(ar) __cpuid(0x80000001, ar[0], ar[1], ar[2], ar[3])
70
+ # define _cpuidX(ar, eax, ecx) __cpuid_count(eax, ecx, ar[0], ar[1], ar[2], ar[3])
71
+ static inline int _GET_XCR() {
72
+ int xcr0;
73
+ __asm__ __volatile__("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx");
74
+ return xcr0;
75
+ }
76
+ #endif
77
+ // checks if CPU has 128-bit AVX units; currently not used as AVX2 is beneficial even on Zen1
78
+ // static bool cpu_has_slow_avx(cpuid1flag0) {
79
+ // int family = ((cpuid1flag0>>8) & 0xf) + ((cpuid1flag0>>16) & 0xff0),
80
+ // model = ((cpuid1flag0>>4) & 0xf) + ((cpuid1flag0>>12) & 0xf0);
81
+ // return (
82
+ // family == 0x6f // AMD Bulldozer family
83
+ // || family == 0x7f // AMD Jaguar/Puma family
84
+ // || (family == 0x8f && (model == 0 /*Summit Ridge ES*/ || model == 1 /*Zen*/ || model == 8 /*Zen+*/ || model == 0x11 /*Zen APU*/ || model == 0x18 /*Zen+ APU*/ || model == 0x50 /*Subor Z+*/)) // AMD Zen1 family
85
+ // || (family == 6 && model == 0xf) // Centaur/Zhaoxin; overlaps with Intel Core 2, but they don't support AVX
86
+ // );
87
+ // }
88
+
89
+
90
+ int cpu_supports_isa() {
91
+ int flags[4];
92
+ _cpuid1(flags);
93
+ int ret = 0;
94
+
95
+ if(flags[2] & 0x800000)
96
+ ret |= ISA_FEATURE_POPCNT;
97
+ int flags2[4];
98
+ _cpuid1x(flags2);
99
+ if(flags2[2] & 0x20) // ABM
100
+ ret |= ISA_FEATURE_LZCNT | ISA_FEATURE_POPCNT;
101
+
102
+ int family = ((flags[0]>>8) & 0xf) + ((flags[0]>>16) & 0xff0);
103
+ int model = ((flags[0]>>4) & 0xf) + ((flags[0]>>12) & 0xf0);
104
+
105
+ if(family == 6 && (
106
+ model == 0x1C || model == 0x26 || model == 0x27 || model == 0x35 || model == 0x36 || model == 0x37 || model == 0x4A || model == 0x4C || model == 0x4D || model == 0x5A || model == 0x5D
107
+ ))
108
+ // Intel Bonnell/Silvermont CPU with very slow PSHUFB and PBLENDVB - pretend SSSE3 doesn't exist
109
+ return ret | ISA_LEVEL_SSE2;
110
+
111
+ if(family == 0x5f && (model == 0 || model == 1 || model == 2))
112
+ // AMD Bobcat with slow SSSE3 instructions - pretend it doesn't exist
113
+ return ret | ISA_LEVEL_SSE2;
114
+
115
+ // Jaguar/Puma performance unkown (slowish PSHUFB/PBLENDVB)
116
+
117
+ if((flags[2] & 0x200) == 0x200) { // SSSE3
118
+ if(family == 6 && (model == 0x5c || model == 0x5f || model == 0x7a || model == 0x9c))
119
+ // Intel Goldmont/plus / Tremont with slow PBLENDVB
120
+ return ret | ISA_LEVEL_SSSE3;
121
+
122
+ if(flags[2] & 0x80000) { // SSE4.1
123
+ if((flags[2] & 0x18800000) == 0x18800000) { // POPCNT + OSXSAVE + AVX
124
+ int xcr = _GET_XCR() & 0xff; // ignore unused bits
125
+ if((xcr & 6) == 6) { // AVX enabled
126
+ int cpuInfo[4];
127
+ _cpuidX(cpuInfo, 7, 0);
128
+ if((cpuInfo[1] & 0x128) == 0x128 && (ret & ISA_FEATURE_LZCNT)) { // BMI2 + AVX2 + BMI1
129
+ if(((xcr & 0xE0) == 0xE0) && (cpuInfo[1] & 0xC0010000) == 0xC0010000) { // AVX512BW + AVX512VL + AVX512F
130
+ if(cpuInfo[2] & 0x40)
131
+ return ret | ISA_LEVEL_VBMI2;
132
+ return ret | ISA_LEVEL_AVX3;
133
+ }
134
+ // AVX2 is beneficial even on Zen1
135
+ return ret | ISA_LEVEL_AVX2;
136
+ }
137
+ return ret | ISA_LEVEL_AVX;
138
+ }
139
+ }
140
+ return ret | ISA_LEVEL_SSE41;
141
+ }
142
+ return ret | ISA_LEVEL_SSSE3;
143
+ }
144
+ return ret | ISA_LEVEL_SSE2;
145
+ }
146
+
147
+ #endif // PLATFORM_X86
package/src/yencode.cc ADDED
@@ -0,0 +1,449 @@
1
+
2
+ #include <node.h>
3
+ #include <node_buffer.h>
4
+ #include <node_version.h>
5
+ #include <v8.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+
9
+ #include "encoder.h"
10
+ #include "decoder.h"
11
+ #include "crc.h"
12
+
13
+ using namespace v8;
14
+
15
+ static void free_buffer(char* data, void* _size) {
16
+ #if !NODE_VERSION_AT_LEAST(0, 11, 0)
17
+ int size = (int)(size_t)_size;
18
+ V8::AdjustAmountOfExternalAllocatedMemory(-size);
19
+ #endif
20
+ //Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-size);
21
+ free(data);
22
+ }
23
+
24
+ // TODO: encode should return col num for incremental processing
25
+ // line limit + return input consumed
26
+ // async processing?
27
+
28
+ static inline size_t YENC_MAX_SIZE(size_t len, size_t line_size) {
29
+ size_t ret = len * 2 /* all characters escaped */
30
+ + 2 /* allocation for offset and that a newline may occur early */
31
+ #if !defined(YENC_DISABLE_AVX256)
32
+ + 64 /* allocation for YMM overflowing */
33
+ #else
34
+ + 32 /* allocation for XMM overflowing */
35
+ #endif
36
+ ;
37
+ /* add newlines, considering the possibility of all chars escaped */
38
+ if(line_size == 128) // optimize common case
39
+ return ret + 2 * (len >> 6);
40
+ return ret + 2 * ((len*2) / line_size);
41
+ }
42
+
43
+
44
+
45
+ #if NODE_VERSION_AT_LEAST(0, 11, 0)
46
+ // for node 0.12.x
47
+ # define FUNC(name) static void name(const FunctionCallbackInfo<Value>& args)
48
+ # define FUNC_START \
49
+ Isolate* isolate = args.GetIsolate(); \
50
+ HandleScope scope(isolate)
51
+
52
+ # if NODE_VERSION_AT_LEAST(8, 0, 0)
53
+ # define NEW_STRING(s) String::NewFromOneByte(isolate, (const uint8_t*)(s), NewStringType::kNormal).ToLocalChecked()
54
+ # define RETURN_ERROR(e) { isolate->ThrowException(Exception::Error(String::NewFromOneByte(isolate, (const uint8_t*)(e), NewStringType::kNormal).ToLocalChecked())); return; }
55
+ # define ARG_TO_INT(a) (a).As<Integer>()->Value()
56
+ # define ARG_TO_BOOL(a) (a).As<Boolean>()->Value()
57
+ # else
58
+ # define NEW_STRING(s) String::NewFromUtf8(isolate, s)
59
+ # define RETURN_ERROR(e) { isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, e))); return; }
60
+ # define ARG_TO_INT(a) (a)->ToInteger()->Value()
61
+ # define ARG_TO_BOOL(a) (a)->ToBoolean()->Value()
62
+ # endif
63
+ # define NEW_OBJECT Object::New(isolate)
64
+ # if NODE_VERSION_AT_LEAST(3, 0, 0) // iojs3
65
+ # define NEW_BUFFER(...) node::Buffer::New(ISOLATE __VA_ARGS__).ToLocalChecked()
66
+ # else
67
+ # define NEW_BUFFER(...) node::Buffer::New(ISOLATE __VA_ARGS__)
68
+ # endif
69
+
70
+ # define RETURN_VAL(v) { args.GetReturnValue().Set(v); return; }
71
+ # define RETURN_UNDEF return
72
+ # define ISOLATE isolate,
73
+ //# define MARK_EXT_MEM isolate->AdjustAmountOfExternalAllocatedMemory
74
+ # define MARK_EXT_MEM(x)
75
+
76
+ #else
77
+ // for node 0.10.x
78
+ #define FUNC(name) static Handle<Value> name(const Arguments& args)
79
+ #define FUNC_START HandleScope scope
80
+ #define NEW_STRING String::New
81
+ #define NEW_OBJECT Object::New()
82
+ #define NEW_BUFFER(...) Local<Object>::New(node::Buffer::New(ISOLATE __VA_ARGS__)->handle_)
83
+ #define ARG_TO_INT(a) (a)->ToInteger()->Value()
84
+ #define ARG_TO_BOOL(a) (a)->ToBoolean()->Value()
85
+
86
+ #define RETURN_ERROR(e) \
87
+ return ThrowException(Exception::Error( \
88
+ String::New(e)) \
89
+ )
90
+ #define RETURN_VAL(v) return scope.Close(v)
91
+ #define RETURN_UNDEF RETURN_VAL( Undefined() )
92
+ #define ISOLATE
93
+ #define MARK_EXT_MEM V8::AdjustAmountOfExternalAllocatedMemory
94
+ #endif
95
+
96
+ #if NODE_VERSION_AT_LEAST(12, 0, 0)
97
+ # define SET_OBJ(obj, key, val) (obj)->Set(isolate->GetCurrentContext(), NEW_STRING(key), val).Check()
98
+ #else
99
+ # define SET_OBJ(obj, key, val) (obj)->Set(NEW_STRING(key), val)
100
+ #endif
101
+
102
+
103
+ // encode(str, line_size, col)
104
+ FUNC(Encode) {
105
+ FUNC_START;
106
+
107
+ if (args.Length() == 0 || !node::Buffer::HasInstance(args[0]))
108
+ RETURN_ERROR("You must supply a Buffer");
109
+
110
+ size_t arg_len = node::Buffer::Length(args[0]);
111
+ if (arg_len == 0)
112
+ RETURN_VAL(NEW_BUFFER(0));
113
+
114
+ int line_size = 128, col = 0;
115
+ if (args.Length() >= 2) {
116
+ line_size = (int)ARG_TO_INT(args[1]);
117
+ if (line_size == 0) line_size = 128; // allow this case
118
+ if (line_size < 0)
119
+ RETURN_ERROR("Line size must be at least 1 byte");
120
+ if (args.Length() >= 3) {
121
+ col = (int)ARG_TO_INT(args[2]);
122
+ if (col > line_size || col < 0)
123
+ RETURN_ERROR("Column offset cannot exceed the line size and cannot be negative");
124
+ if (col == line_size) col = 0; // allow this case
125
+ }
126
+ }
127
+
128
+ // allocate enough memory to handle worst case requirements
129
+ size_t dest_len = YENC_MAX_SIZE(arg_len, line_size);
130
+
131
+ unsigned char *result = (unsigned char*) malloc(dest_len);
132
+ size_t len = do_encode(line_size, &col, (const unsigned char*)node::Buffer::Data(args[0]), result, arg_len, true);
133
+ result = (unsigned char*)realloc(result, len);
134
+ MARK_EXT_MEM(len);
135
+ RETURN_VAL( NEW_BUFFER((char*)result, len, free_buffer, (void*)len) );
136
+ }
137
+
138
+ FUNC(EncodeTo) {
139
+ FUNC_START;
140
+
141
+ if (args.Length() < 2 || !node::Buffer::HasInstance(args[0]) || !node::Buffer::HasInstance(args[1]))
142
+ RETURN_ERROR("You must supply two Buffers");
143
+
144
+ size_t arg_len = node::Buffer::Length(args[0]);
145
+ if (arg_len == 0)
146
+ RETURN_VAL(Integer::New(ISOLATE 0));
147
+
148
+ int line_size = 128, col = 0;
149
+ if (args.Length() >= 3) {
150
+ line_size = (int)ARG_TO_INT(args[2]);
151
+ if (line_size == 0) line_size = 128; // allow this case
152
+ if (line_size < 0)
153
+ RETURN_ERROR("Line size must be at least 1 byte");
154
+ if (args.Length() >= 4) {
155
+ col = (int)ARG_TO_INT(args[3]);
156
+ if (col > line_size || col < 0)
157
+ RETURN_ERROR("Column offset cannot exceed the line size and cannot be negative");
158
+ if (col == line_size) col = 0; // allow this case
159
+ }
160
+ }
161
+
162
+ // check that destination buffer has enough space
163
+ size_t dest_len = YENC_MAX_SIZE(arg_len, line_size);
164
+ if(node::Buffer::Length(args[1]) < dest_len)
165
+ RETURN_ERROR("Destination buffer does not have enough space (use `maxSize` to compute required space)");
166
+
167
+ size_t len = do_encode(line_size, &col, (const unsigned char*)node::Buffer::Data(args[0]), (unsigned char*)node::Buffer::Data(args[1]), arg_len, true);
168
+ RETURN_VAL( Integer::New(ISOLATE len) );
169
+ }
170
+
171
+ FUNC(EncodeIncr) {
172
+ FUNC_START;
173
+
174
+ if (args.Length() == 0 || !node::Buffer::HasInstance(args[0]))
175
+ RETURN_ERROR("You must supply a Buffer");
176
+
177
+ int line_size = 128, col = 0;
178
+ bool allocResult = true;
179
+ unsigned char* result;
180
+ size_t arg_len = node::Buffer::Length(args[0]);
181
+ if(args.Length() > 1) {
182
+ int argp = 1;
183
+ if(node::Buffer::HasInstance(args[1])) {
184
+ // grab destination
185
+ allocResult = false;
186
+ // check that destination buffer has enough space
187
+ size_t dest_len = YENC_MAX_SIZE(arg_len, line_size);
188
+ if(node::Buffer::Length(args[1]) < dest_len)
189
+ RETURN_ERROR("Destination buffer does not have enough space (use `maxSize` to compute required space)");
190
+ result = (unsigned char*)node::Buffer::Data(args[1]);
191
+ argp++;
192
+ }
193
+ if (args.Length() > argp) {
194
+ line_size = (int)ARG_TO_INT(args[argp]);
195
+ if (line_size == 0) line_size = 128; // allow this case
196
+ if (line_size < 0)
197
+ RETURN_ERROR("Line size must be at least 1 byte");
198
+ argp++;
199
+ if (args.Length() > argp) {
200
+ col = (int)ARG_TO_INT(args[argp]);
201
+ if (col > line_size || col < 0)
202
+ RETURN_ERROR("Column offset cannot exceed the line size and cannot be negative");
203
+ if (col == line_size) col = 0; // allow this case
204
+ }
205
+ }
206
+ }
207
+
208
+ Local<Object> ret = NEW_OBJECT;
209
+
210
+ if (arg_len == 0) {
211
+ SET_OBJ(ret, "written", Integer::New(ISOLATE 0));
212
+ // TODO: set 'output'?
213
+ SET_OBJ(ret, "col", Integer::New(ISOLATE col));
214
+ RETURN_VAL( ret );
215
+ }
216
+
217
+ if(allocResult) {
218
+ // allocate enough memory to handle worst case requirements
219
+ size_t dest_len = YENC_MAX_SIZE(arg_len, line_size);
220
+ result = (unsigned char*) malloc(dest_len);
221
+ }
222
+
223
+ size_t len = do_encode(line_size, &col, (const unsigned char*)node::Buffer::Data(args[0]), result, arg_len, false);
224
+
225
+ SET_OBJ(ret, "written", Integer::New(ISOLATE len));
226
+ if(allocResult) {
227
+ result = (unsigned char*)realloc(result, len);
228
+ SET_OBJ(ret, "output", NEW_BUFFER((char*)result, len, free_buffer, (void*)len));
229
+ MARK_EXT_MEM(len);
230
+ }
231
+ SET_OBJ(ret, "col", Integer::New(ISOLATE col));
232
+ RETURN_VAL( ret );
233
+ }
234
+
235
+ FUNC(Decode) {
236
+ FUNC_START;
237
+
238
+ if (args.Length() == 0 || !node::Buffer::HasInstance(args[0]))
239
+ RETURN_ERROR("You must supply a Buffer");
240
+
241
+ size_t arg_len = node::Buffer::Length(args[0]);
242
+ if (arg_len == 0)
243
+ RETURN_VAL( NEW_BUFFER(0) );
244
+
245
+ bool isRaw = false;
246
+ if (args.Length() > 1)
247
+ isRaw = ARG_TO_BOOL(args[1]);
248
+
249
+ unsigned char *result = (unsigned char*) malloc(arg_len);
250
+ size_t len = do_decode(isRaw, (const unsigned char*)node::Buffer::Data(args[0]), result, arg_len, NULL);
251
+ result = (unsigned char*)realloc(result, len);
252
+ MARK_EXT_MEM(len);
253
+ RETURN_VAL( NEW_BUFFER((char*)result, len, free_buffer, (void*)len) );
254
+ }
255
+
256
+ FUNC(DecodeTo) {
257
+ FUNC_START;
258
+
259
+ if (args.Length() < 2 || !node::Buffer::HasInstance(args[0]) || !node::Buffer::HasInstance(args[1]))
260
+ RETURN_ERROR("You must supply two Buffers");
261
+
262
+ size_t arg_len = node::Buffer::Length(args[0]);
263
+ if (arg_len == 0)
264
+ RETURN_VAL( Integer::New(ISOLATE 0) );
265
+
266
+ // check that destination buffer has enough space
267
+ if(node::Buffer::Length(args[1]) < arg_len)
268
+ RETURN_VAL( Integer::New(ISOLATE 0) );
269
+
270
+ bool isRaw = false;
271
+ if (args.Length() > 2)
272
+ isRaw = ARG_TO_BOOL(args[2]);
273
+
274
+ size_t len = do_decode(isRaw, (const unsigned char*)node::Buffer::Data(args[0]), (unsigned char*)node::Buffer::Data(args[1]), arg_len, NULL);
275
+ RETURN_VAL( Integer::New(ISOLATE len) );
276
+ }
277
+
278
+
279
+ FUNC(DecodeIncr) {
280
+ FUNC_START;
281
+
282
+ if (args.Length() == 0 || !node::Buffer::HasInstance(args[0]))
283
+ RETURN_ERROR("You must supply a Buffer");
284
+
285
+ size_t arg_len = node::Buffer::Length(args[0]);
286
+ if (arg_len == 0)
287
+ // handled properly in Javascript
288
+ RETURN_UNDEF;
289
+
290
+ YencDecoderState state = YDEC_STATE_CRLF;
291
+ unsigned char *result = NULL;
292
+ bool allocResult = true;
293
+ if (args.Length() > 1) {
294
+ state = (YencDecoderState)(ARG_TO_INT(args[1]));
295
+ if (args.Length() > 2 && node::Buffer::HasInstance(args[2])) {
296
+ if(node::Buffer::Length(args[2]) < arg_len)
297
+ RETURN_ERROR("Destination buffer does not have enough space");
298
+ result = (unsigned char*)node::Buffer::Data(args[2]);
299
+ allocResult = false;
300
+ }
301
+ }
302
+
303
+ const unsigned char* src = (const unsigned char*)node::Buffer::Data(args[0]);
304
+ const unsigned char* sp = src;
305
+ #ifdef DBG_ALIGN_SOURCE
306
+ void* newSrc = valloc(arg_len);
307
+ memcpy(newSrc, src, arg_len);
308
+ sp = (const unsigned char*)newSrc;
309
+ #endif
310
+
311
+ if(allocResult) result = (unsigned char*) malloc(arg_len);
312
+ unsigned char* dp = result;
313
+ YencDecoderEnd ended = do_decode_end(&sp, &dp, arg_len, &state);
314
+ size_t len = dp - result;
315
+ if(allocResult) result = (unsigned char*)realloc(result, len);
316
+
317
+ #ifdef DBG_ALIGN_SOURCE
318
+ free(newSrc);
319
+ #endif
320
+
321
+ Local<Object> ret = NEW_OBJECT;
322
+ SET_OBJ(ret, "read", Integer::New(ISOLATE sp - src));
323
+ SET_OBJ(ret, "written", Integer::New(ISOLATE len));
324
+ if(allocResult) {
325
+ SET_OBJ(ret, "output", NEW_BUFFER((char*)result, len, free_buffer, (void*)len));
326
+ MARK_EXT_MEM(len);
327
+ }
328
+ SET_OBJ(ret, "ended", Integer::New(ISOLATE (int)ended));
329
+ SET_OBJ(ret, "state", Integer::New(ISOLATE state));
330
+ RETURN_VAL( ret );
331
+ }
332
+
333
+
334
+ static inline uint32_t read_crc32(const Local<Value>& buf) {
335
+ const uint8_t* arr = (const uint8_t*)node::Buffer::Data(buf);
336
+ return (((uint_fast32_t)arr[0] << 24) | ((uint_fast32_t)arr[1] << 16) | ((uint_fast32_t)arr[2] << 8) | (uint_fast32_t)arr[3]);
337
+ }
338
+ static inline Local<Object> pack_crc32(
339
+ #if NODE_VERSION_AT_LEAST(0, 11, 0)
340
+ Isolate* isolate,
341
+ #endif
342
+ uint32_t crc) {
343
+ Local<Object> buff = NEW_BUFFER(4);
344
+ unsigned char* d = (unsigned char*)node::Buffer::Data(buff);
345
+ d[0] = (unsigned char)(crc >> 24) & 0xFF;
346
+ d[1] = (unsigned char)(crc >> 16) & 0xFF;
347
+ d[2] = (unsigned char)(crc >> 8) & 0xFF;
348
+ d[3] = (unsigned char)crc & 0xFF;
349
+ return buff;
350
+ }
351
+
352
+ // crc32(str, init)
353
+ FUNC(CRC32) {
354
+ FUNC_START;
355
+
356
+ if (args.Length() == 0 || !node::Buffer::HasInstance(args[0]))
357
+ RETURN_ERROR("You must supply a Buffer");
358
+ // TODO: support string args??
359
+
360
+ uint32_t crc = 0;
361
+ if (args.Length() >= 2) {
362
+ if (!node::Buffer::HasInstance(args[1]) || node::Buffer::Length(args[1]) != 4)
363
+ RETURN_ERROR("Second argument must be a 4 byte buffer");
364
+ crc = read_crc32(args[1]);
365
+ }
366
+ crc = do_crc32(
367
+ (const void*)node::Buffer::Data(args[0]),
368
+ node::Buffer::Length(args[0]),
369
+ crc
370
+ );
371
+ RETURN_VAL(pack_crc32(ISOLATE crc));
372
+ }
373
+
374
+ FUNC(CRC32Combine) {
375
+ FUNC_START;
376
+
377
+ if (args.Length() < 3)
378
+ RETURN_ERROR("At least 3 arguments required");
379
+ if (!node::Buffer::HasInstance(args[0]) || node::Buffer::Length(args[0]) != 4
380
+ || !node::Buffer::HasInstance(args[1]) || node::Buffer::Length(args[1]) != 4)
381
+ RETURN_ERROR("You must supply a 4 byte Buffer for the first two arguments");
382
+
383
+ uint32_t crc1 = read_crc32(args[0]), crc2 = read_crc32(args[1]);
384
+ size_t len = (size_t)ARG_TO_INT(args[2]);
385
+
386
+ crc1 = do_crc32_combine(crc1, crc2, len);
387
+ RETURN_VAL(pack_crc32(ISOLATE crc1));
388
+ }
389
+
390
+ FUNC(CRC32Zeroes) {
391
+ FUNC_START;
392
+
393
+ if (args.Length() < 1)
394
+ RETURN_ERROR("At least 1 argument required");
395
+
396
+ uint32_t crc1 = 0;
397
+ if (args.Length() >= 2) {
398
+ if (!node::Buffer::HasInstance(args[1]) || node::Buffer::Length(args[1]) != 4)
399
+ RETURN_ERROR("Second argument must be a 4 byte buffer");
400
+ crc1 = read_crc32(args[1]);
401
+ }
402
+ size_t len = (size_t)ARG_TO_INT(args[0]);
403
+ crc1 = do_crc32_zeros(crc1, len);
404
+ RETURN_VAL(pack_crc32(ISOLATE crc1));
405
+ }
406
+
407
+ static void init_all() {
408
+ encoder_init();
409
+ decoder_init();
410
+ crc_init();
411
+ }
412
+
413
+ #if NODE_VERSION_AT_LEAST(10, 7, 0)
414
+ // signal context aware module for node if it supports it
415
+ # include <uv.h>
416
+ static uv_once_t init_once = UV_ONCE_INIT;
417
+ NODE_MODULE_INIT(/* exports, module, context */)
418
+ #else
419
+ void yencode_init(
420
+ # if NODE_VERSION_AT_LEAST(4, 0, 0)
421
+ Local<Object> exports,
422
+ Local<Value> module,
423
+ void* priv
424
+ # else
425
+ Handle<Object> exports
426
+ # endif
427
+ )
428
+ #endif
429
+ {
430
+ NODE_SET_METHOD(exports, "encode", Encode);
431
+ NODE_SET_METHOD(exports, "encodeTo", EncodeTo);
432
+ NODE_SET_METHOD(exports, "encodeIncr", EncodeIncr);
433
+ NODE_SET_METHOD(exports, "decode", Decode);
434
+ NODE_SET_METHOD(exports, "decodeTo", DecodeTo);
435
+ NODE_SET_METHOD(exports, "decodeIncr", DecodeIncr);
436
+ NODE_SET_METHOD(exports, "crc32", CRC32);
437
+ NODE_SET_METHOD(exports, "crc32_combine", CRC32Combine);
438
+ NODE_SET_METHOD(exports, "crc32_zeroes", CRC32Zeroes);
439
+
440
+ #if NODE_VERSION_AT_LEAST(10, 7, 0)
441
+ uv_once(&init_once, init_all);
442
+ #else
443
+ init_all();
444
+ #endif
445
+ }
446
+
447
+ #if !NODE_VERSION_AT_LEAST(10, 7, 0)
448
+ NODE_MODULE(yencode, yencode_init);
449
+ #endif
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ module.exports = function(length, line_size) {
3
+ if(!length) return 0;
4
+ return Math.ceil(length*2) // all characters escaped
5
+ + 2 * Math.floor((length*2) / (line_size||128)) // newlines, considering the possibility of all chars escaped
6
+ + 2 // allocation for offset and that a newline may occur early
7
+ + 64 // extra space just in case things go awry... just kidding, it's just extra padding to make SIMD logic easier
8
+ ;
9
+ };