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,163 @@
1
+ // a basic script to test that raw yEnc works as expected
2
+
3
+ var assert = require('assert');
4
+ var y = (function() {
5
+ try {
6
+ return require('../build/Debug/yencode.node');
7
+ } catch(x) {}
8
+ return require('../build/Release/yencode.node');
9
+ })();
10
+ var maxSize = require('./_maxsize');
11
+
12
+ // slow reference yEnc implementation
13
+ var refYEnc = function(src, line_size, col) {
14
+ var ret = [];
15
+ for (var i = 0; i < src.length; i++) {
16
+ var c = (src[i] + 42) & 0xFF;
17
+ switch(String.fromCharCode(c)) {
18
+ case '.':
19
+ if(col > 0) break;
20
+ case '\t': case ' ':
21
+ if(col > 0 && col < line_size-1) break;
22
+ case '\0': case '\r': case '\n': case '=':
23
+ ret.push('='.charCodeAt(0));
24
+ c += 64;
25
+ col++;
26
+ }
27
+ ret.push(c);
28
+ col++;
29
+ if(col >= line_size) {
30
+ ret.push('\r'.charCodeAt(0));
31
+ ret.push('\n'.charCodeAt(0));
32
+ col = 0;
33
+ }
34
+ }
35
+
36
+ // if there's a trailing newline, trim it
37
+ if(ret[ret.length-2] == '\r'.charCodeAt(0) && ret[ret.length-1] == '\n'.charCodeAt(0)) {
38
+ ret.pop();
39
+ ret.pop();
40
+ }
41
+
42
+ // if the last character is tab/space, escape it
43
+ if(ret[ret.length-1] == '\t'.charCodeAt(0) || ret[ret.length-1] == ' '.charCodeAt(0)) {
44
+ var c = ret[ret.length-1];
45
+ ret.pop();
46
+ ret.push('='.charCodeAt(0));
47
+ ret.push((c+64) & 0xFF);
48
+ }
49
+
50
+ return new Buffer(ret);
51
+ };
52
+ var doTest = function(msg, test, expected) {
53
+ test[0] = new Buffer(test[0]);
54
+ if(!test[1]) test[1] = 128; // line size
55
+ if(!test[2]) test[2] = 0; // column offset
56
+
57
+ if(!expected && expected !== '') expected = refYEnc.apply(null, test).toString('hex');
58
+ else expected = expected.replace(/ /g, '');
59
+ var actual = y.encode.apply(null, test).toString('hex');
60
+ if(actual != expected) {
61
+ console.log('Actual:', actual);
62
+ console.log('Expect:', expected);
63
+ console.log('Source:', test[0].toString('hex'));
64
+ assert.equal(actual, expected, msg);
65
+ }
66
+
67
+ var buf = new Buffer(maxSize(test[0].length, test[1]));
68
+ var len = y.encodeTo.apply(null, [test[0], buf].concat(test.slice(1)));
69
+ assert.equal(buf.slice(0, len).toString('hex'), expected, msg);
70
+ };
71
+
72
+ var range = function(start, end) {
73
+ var ret = Array(end-start);
74
+ for(var i=start; i<end; i++)
75
+ ret[i-start] = i;
76
+ return ret;
77
+ }
78
+ var multiRange = function(list) {
79
+ var ret = [];
80
+ for(var i=0; i<list.length; i+=2) {
81
+ ret = ret.concat(range(list[i], list[i+1]));
82
+ }
83
+ return ret;
84
+ }
85
+
86
+ var lineSizes = // 48 sizes to test
87
+ range(1, 18).concat(range(23, 26)).concat(range(30, 35)).concat(range(46, 51)).concat(range(62, 67)).concat(range(126, 131)).concat([136, 145, 159]).concat(range(254, 259));
88
+ var runLineSizes = function(fn) {
89
+ lineSizes.forEach(function(ls) {
90
+ lineSizes.forEach(function(offs) {
91
+ if(offs >= ls) return;
92
+ fn(ls, offs);
93
+ });
94
+ });
95
+ };
96
+
97
+ // simple tests
98
+ runLineSizes(function(ls, offs) {
99
+ var infoStr = ' [ls='+ls+', offs='+offs+']';
100
+ var b = new Buffer(256);
101
+ b.fill(0);
102
+ doTest('Long no escaping' + infoStr, [b, ls]);
103
+ b.fill(227);
104
+ doTest('Long all escaping' + infoStr, [b, ls]);
105
+ b.fill(4);
106
+ doTest('Long all dots' + infoStr, [b, ls]);
107
+ b.fill(223);
108
+ doTest('Long all tabs' + infoStr, [b, ls]);
109
+ });
110
+
111
+ // case tests
112
+ var padLens = range(0, 35).concat(range(46, 51)).concat(range(62, 67));
113
+ var padding = new Buffer(128);
114
+ padding.fill(97); // 'a'
115
+ [ ['Empty test', [[]], ''],
116
+ ['Simple test', [[0,1,2,3,224,4]]],
117
+ ['Partial tab line', [[223, 223, 223]]],
118
+ ['Dot first should escape', [[4,3,224,2,1,0]]],
119
+ ['Short line', [[0,1,2,3,4], 2]],
120
+ ['Short line (2)', [[0,1,224,3,4], 2]],
121
+ ['Short line + offset', [[0,1,2,3,4], 2, 1]],
122
+ ['Short line (2) + offset', [[0,1,224,3,4], 2, 1]],
123
+ ['Tab & lf around line break', [[223,224], 128, 127], '3d 49 0d 0a 3d 4a'],
124
+ ].forEach(function(test) {
125
+ doTest.apply(null, test);
126
+ if(test.length == 2) {
127
+ // if no defined result, try padding the data to make it long enough to invoke SIMD behaviour
128
+ padLens.forEach(function(prepad) {
129
+ padLens.forEach(function(postpad) {
130
+ var newBuf = Buffer.concat([padding.slice(0, prepad), new Buffer(test[1][0]), padding.slice(0, postpad)]);
131
+ var newTest = test.slice();
132
+ newTest[1] = [newBuf].concat(newTest[1].slice(1));
133
+ doTest.apply(null, newTest);
134
+ });
135
+ });
136
+ }
137
+ });
138
+
139
+ // random tests
140
+ for(var i=0; i<32; i++) {
141
+ var rand = require('crypto').pseudoRandomBytes(4*1024);
142
+ runLineSizes(function(ls, offs) {
143
+ doTest('Random [ls='+ls+', offs='+offs+']', [rand, ls, offs]);
144
+ });
145
+ }
146
+
147
+ // targeted random tests
148
+ var charset = 'a\xd6\xdf\xe0\xe3\xf6\x04\x13';
149
+ var randStr = function(n) {
150
+ var ret = new Buffer(n);
151
+ for(var i=0; i<n; i++)
152
+ ret[i] = charset[(Math.random() * charset.length) | 0].charCodeAt(0);
153
+ return ret;
154
+ };
155
+ for(var i=0; i<32; i++) {
156
+ var rand = randStr(2048);
157
+ runLineSizes(function(ls, offs) {
158
+ doTest('Random2 [ls='+ls+', offs='+offs+']', [rand, ls, offs]);
159
+ });
160
+ }
161
+
162
+
163
+ console.log('All tests passed');
@@ -0,0 +1,126 @@
1
+
2
+ var assert = require('assert');
3
+ var y = require('../index.js');
4
+
5
+ var assertObjectHas = function(obj, required) {
6
+ for(var k in required) {
7
+ if(required[k] === undefined || required[k] === null)
8
+ assert(obj[k] === required[k]);
9
+ else if(typeof required[k] === 'object') // recurse to sub-objects
10
+ assertObjectHas(obj[k], required[k]);
11
+ else
12
+ assert.equal(obj[k], required[k], k);
13
+ }
14
+ };
15
+
16
+ var post, postData;
17
+
18
+ // test basic post
19
+ postData = [
20
+ '=ybegin part=5 line=128 size=500000 name=myBinary.dat',
21
+ '=ypart begin=499991 end=500000',
22
+ '..... data',
23
+ '=yend size=10 part=5 pcrc32=97f4bd52',
24
+ ''
25
+ ].join('\r\n');
26
+ post = y.from_post(new Buffer(postData));
27
+ assertObjectHas(post, {
28
+ yencStart: 0,
29
+ dataStart: postData.indexOf('...'),
30
+ dataEnd: postData.indexOf('\r\n=yend'),
31
+ yencEnd: postData.length,
32
+ props: {
33
+ begin: {
34
+ part: '5',
35
+ line: '128',
36
+ size: '500000',
37
+ name: 'myBinary.dat'
38
+ },
39
+ part: {
40
+ begin: '499991',
41
+ end: '500000'
42
+ },
43
+ end: {
44
+ size: '10',
45
+ part: '5',
46
+ pcrc32: '97f4bd52'
47
+ }
48
+ },
49
+ warnings: undefined
50
+ });
51
+ assert.equal(post.data.length, post.dataEnd - post.dataStart); // there's no escaped characters in this post, so length should equal input length
52
+ // won't bother testing actual encoding or CRC32 (leave this to other tests)
53
+
54
+
55
+ // test post with extra data
56
+ postData = [
57
+ 'ignored data',
58
+ '=ybegin part=5a some_prop=hello line=0 size=0 name=name with space and = chars',
59
+ '.... data',
60
+ '=yend size=2 pcrc32=invalid pcrc32=invalid invalid_prop',
61
+ ].join('\r\n');
62
+ post = y.from_post(new Buffer(postData));
63
+ assertObjectHas(post, {
64
+ yencStart: postData.indexOf('=ybegin'),
65
+ dataStart: postData.indexOf('...'),
66
+ dataEnd: postData.indexOf('\r\n=yend'),
67
+ yencEnd: postData.length,
68
+ props: {
69
+ begin: {
70
+ part: '5a',
71
+ line: '0',
72
+ some_prop: 'hello',
73
+ name: 'name with space and = chars'
74
+ },
75
+ end: {
76
+ pcrc32: 'invalid'
77
+ }
78
+ }
79
+ });
80
+ assert.equal(post.data.length, post.dataEnd - post.dataStart);
81
+ // check that expected warnings are there
82
+ var seenWarnings = {};
83
+ post.warnings.forEach(function(warn) {
84
+ seenWarnings[warn.code] = warn.message;
85
+ });
86
+ assert(seenWarnings['ignored_line_data']);
87
+ assert(seenWarnings['duplicate_property']);
88
+ assert(seenWarnings['missing_yend_newline']);
89
+ assert(seenWarnings['invalid_prop_part']);
90
+ assert(seenWarnings['zero_prop_line']);
91
+ assert(seenWarnings['invalid_prop_pcrc32']);
92
+ assert(seenWarnings['size_mismatch']);
93
+
94
+ // empty post
95
+ postData = [
96
+ '=ybegin size=0 line=1 name=',
97
+ '=yend size=0',
98
+ ''
99
+ ].join('\r\n');
100
+ post = y.from_post(new Buffer(postData));
101
+ assertObjectHas(post, {
102
+ yencStart: 0,
103
+ dataStart: undefined,
104
+ dataEnd: undefined,
105
+ yencEnd: postData.length,
106
+ data: undefined,
107
+ warnings: undefined,
108
+ props: {
109
+ begin: {
110
+ size: '0',
111
+ line: '1',
112
+ name: ''
113
+ },
114
+ end: { size: '0' }
115
+ }
116
+ });
117
+
118
+
119
+ // test parse errors
120
+ post = y.from_post(new Buffer('invalid post'));
121
+ assert.equal(post.code, 'no_start_found');
122
+ post = y.from_post(new Buffer('=ybegin abc=def'));
123
+ assert.equal(post.code, 'no_end_found');
124
+
125
+
126
+ console.log('All tests passed');
package/test.js DELETED
@@ -1,91 +0,0 @@
1
- // a basic script to test that raw yEnc works as expected
2
-
3
- var assert = require('assert');
4
- var y = require('./build/Release/yencode.node');
5
-
6
- // slow reference yEnc implementation
7
- var refYEnc = function(src, line_size, col) {
8
- var ret = [];
9
- for (var i = 0; i < src.length; i++) {
10
- var c = (src[i] + 42) & 0xFF;
11
- switch(String.fromCharCode(c)) {
12
- case '.':
13
- if(col > 0) break;
14
- case '\t': case ' ':
15
- if(col > 0 && col < line_size-1) break;
16
- case '\0': case '\r': case '\n': case '=':
17
- ret.push('='.charCodeAt(0));
18
- c += 64;
19
- col++;
20
- }
21
- ret.push(c);
22
- col++;
23
- if(col >= line_size) {
24
- ret.push('\r'.charCodeAt(0));
25
- ret.push('\n'.charCodeAt(0));
26
- col = 0;
27
- }
28
- }
29
-
30
- // if there's a trailing newline, trim it
31
- if(ret[ret.length-2] == '\r'.charCodeAt(0) && ret[ret.length-1] == '\n'.charCodeAt(0)) {
32
- ret.pop();
33
- ret.pop();
34
- }
35
-
36
- // if the last character is tab/space, escape it
37
- if(ret[ret.length-1] == '\t'.charCodeAt(0) || ret[ret.length-1] == ' '.charCodeAt(0)) {
38
- var c = ret[ret.length-1];
39
- ret.pop();
40
- ret.push('='.charCodeAt(0));
41
- ret.push((c+64) & 0xFF);
42
- }
43
-
44
- return new Buffer(ret);
45
- };
46
- var doTest = function(msg, test, expected) {
47
- test[0] = new Buffer(test[0]);
48
- if(!test[1]) test[1] = 128; // line size
49
- if(!test[2]) test[2] = 0; // column offset
50
-
51
- if(!expected) expected = refYEnc.apply(null, test).toString('hex');
52
- else expected = expected.replace(/ /g, '');
53
- assert.equal(y.encode.apply(null, test).toString('hex'), expected, msg);
54
- var buf = new Buffer(require('./').maxSize(test[0].length, test[1]));
55
- var len = y.encodeTo.apply(null, [test[0], buf].concat(test.slice(1)));
56
- assert.equal(buf.slice(0, len).toString('hex'), expected, msg);
57
- };
58
-
59
-
60
- doTest('Empty test', [[]], '');
61
- doTest('Simple test', [[0,1,2,3,224,4]]);
62
- doTest('Partial tab line', [[223, 223, 223]]);
63
- doTest('Dot first should escape', [[4,3,224,2,1,0]]);
64
- doTest('Short line', [[0,1,2,3,4], 2]);
65
- doTest('Short line (2)', [[0,1,224,3,4], 2]);
66
- doTest('Short line + offset', [[0,1,2,3,4], 2, 1]);
67
- doTest('Short line (2) + offset', [[0,1,224,3,4], 2, 1]);
68
- doTest('Tab & lf around line break', [[223,224], 128, 127], '3d 49 0d 0a 3d 4a');
69
-
70
- // longer tests
71
- var b = new Buffer(256);
72
- b.fill(0);
73
- doTest('Long no escaping', [b]);
74
- b.fill(227);
75
- doTest('Long all escaping', [b]);
76
- b.fill(4);
77
- doTest('Long all dots', [b]);
78
- b.fill(223);
79
- doTest('Long all tabs', [b]);
80
-
81
-
82
- // random tests
83
- for(var i=0; i<32; i++) {
84
- var rand = require('crypto').pseudoRandomBytes(128*1024);
85
- doTest('Random', [rand]);
86
- doTest('Random + short line', [rand, 3]);
87
- doTest('Random + offset', [rand, 128, 1]);
88
- doTest('Random + offset (end)', [rand, 128, 127]);
89
- }
90
-
91
- console.log('All tests passed');