yencode 1.1.5 → 1.2.0
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 +130 -189
- package/binding.gyp +79 -6
- package/index.js +2 -0
- package/package.json +1 -1
- package/src/common.h +19 -1
- package/src/crc.cc +84 -19
- package/src/crc.h +66 -4
- package/src/crc_arm.cc +50 -32
- package/src/crc_common.h +11 -0
- package/src/crc_folding.cc +152 -14
- package/src/crc_folding_256.cc +7 -12
- package/src/crc_riscv.cc +251 -0
- package/src/decoder.cc +33 -3
- package/src/decoder_avx.cc +2 -2
- package/src/decoder_avx2.cc +1 -1
- package/src/decoder_avx2_base.h +2 -10
- package/src/decoder_common.h +38 -51
- package/src/decoder_neon.cc +4 -14
- package/src/decoder_neon64.cc +4 -11
- package/src/decoder_rvv.cc +274 -0
- package/src/decoder_sse2.cc +23 -2
- package/src/decoder_sse_base.h +6 -34
- package/src/decoder_ssse3.cc +2 -2
- package/src/decoder_vbmi2.cc +0 -5
- package/src/encoder.cc +25 -0
- package/src/encoder_common.h +2 -20
- package/src/encoder_rvv.cc +4 -19
- package/src/platform.cc +4 -4
- package/src/yencode.cc +45 -3
- package/test/testcrc.js +17 -1
- package/test/testcrcfuncs.c +53 -0
- package/test/testdec.js +1 -0
package/README.md
CHANGED
|
@@ -2,292 +2,246 @@ This module provides a very fast (as in gigabytes per second), compiled implemen
|
|
|
2
2
|
|
|
3
3
|
This module should be 1-2 orders of magnitude faster than pure Javascript versions.
|
|
4
4
|
|
|
5
|
-
Features:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
instruction](http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf)
|
|
22
|
-
(if available) or ARMv8’s CRC instructions, with incremental support
|
|
23
|
-
(\>1GB/s on a low power Atom/ARM CPU, \>15GB/s on a modern Intel CPU)
|
|
24
|
-
- ability to combine two CRC32 hashes into one (useful for amalgamating
|
|
25
|
-
*pcrc32s* into a *crc32* for yEnc), as well as quickly compute the CRC32 of a sequence of null bytes
|
|
26
|
-
- eventually may support incremental processing (algorithms internally support
|
|
27
|
-
it, they’re just not exposed to the Javascript interface)
|
|
28
|
-
- [context awareness](https://nodejs.org/api/addons.html#addons_context_aware_addons) (NodeJS 10.7.0 or later), enabling use within [worker threads](https://nodejs.org/api/worker_threads.html)
|
|
29
|
-
- supports NodeJS 0.10.x to 12.x.x and beyond
|
|
30
|
-
|
|
31
|
-
Installing
|
|
32
|
-
==========
|
|
33
|
-
|
|
34
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
5
|
+
## Features:
|
|
6
|
+
|
|
7
|
+
- fast raw yEnc encoding with the ability to specify line length. A single thread can achieve \>450MB/s on a Raspberry Pi 3, or \>5GB/s on a Core-i series CPU.
|
|
8
|
+
- fast yEnc decoding, with and without NNTP layer dot unstuffing. A single thread can achieve \>300MB/s on a Raspberry Pi 3, or \>4.5GB/s on a Core-i series CPU.
|
|
9
|
+
- SIMD optimised encoding and decoding routines, which can use ARMv7 NEON, ARMv8 ASIMD, RISC-V Vector or the following x86 CPU features when available (with dynamic dispatch): SSE2, SSSE3, AVX, AVX2, AVX512-BW (128/256-bit), AVX512-VBMI2 (or AVX10.1/256)
|
|
10
|
+
- full yEnc encoding for single and multi-part posts, according to the [version 1.3 specifications](http://www.yenc.org/yenc-draft.1.3.txt)
|
|
11
|
+
- full yEnc decoding of posts
|
|
12
|
+
- fast compiled CRC32 implementation via [crcutil](https://code.google.com/p/crcutil/) or [PCLMULQDQ instruction](http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf) (if available), ARMv8’s CRC instructions, or RISC-V’s Zb(k)c extension, with incremental support (\>1GB/s on a low power Atom/ARM CPU, \>15GB/s on a modern Intel CPU)
|
|
13
|
+
- ability to combine two CRC32 hashes into one (useful for amalgamating *pcrc32s* into a *crc32* for yEnc), as well as quickly compute the CRC32 of a sequence of null bytes
|
|
14
|
+
- eventually may support incremental processing (algorithms internally support it, they’re just not exposed to the Javascript interface)
|
|
15
|
+
- [context awareness](https://nodejs.org/api/addons.html#addons_context_aware_addons) (NodeJS 10.7.0 or later), enabling use within [worker threads](https://nodejs.org/api/worker_threads.html)
|
|
16
|
+
- supports NodeJS 0.10.x to 12.x.x and beyond
|
|
17
|
+
|
|
18
|
+
# Installing
|
|
19
|
+
|
|
20
|
+
```bash
|
|
35
21
|
npm install yencode
|
|
36
|
-
|
|
22
|
+
```
|
|
37
23
|
|
|
38
24
|
Or you can download the package and run
|
|
39
25
|
|
|
40
|
-
|
|
26
|
+
```bash
|
|
41
27
|
npm install -g node-gyp # if you don't have it already
|
|
42
28
|
node-gyp rebuild
|
|
43
|
-
|
|
29
|
+
```
|
|
44
30
|
|
|
45
|
-
Note, Windows builds are always compiled with SSE2 support. If you can’t have
|
|
46
|
-
this, delete all instances of `"msvs_settings": {"VCCLCompilerTool":
|
|
47
|
-
{"EnableEnhancedInstructionSet": "2"}},` in *binding.gyp* before compiling.
|
|
31
|
+
Note, Windows builds are always compiled with SSE2 support. If you can’t have this, delete all instances of `"msvs_settings": {"VCCLCompilerTool": {"EnableEnhancedInstructionSet": "2"}},` in *binding.gyp* before compiling.
|
|
48
32
|
|
|
49
|
-
Redistributable Builds
|
|
50
|
-
----------------------
|
|
33
|
+
## Redistributable Builds
|
|
51
34
|
|
|
52
|
-
By default, non-Windows builds are built with `-march=native` flag, which means
|
|
53
|
-
that the compiler will optimise the build for the CPU of the build machine. If
|
|
54
|
-
you’re looking to run built binaries elsewhere, this may be undesirable. To make
|
|
55
|
-
builds redistributable, replace `"enable_native_tuning%": 1,` from
|
|
56
|
-
*binding.gyp* with `"enable_native_tuning%": 0,` and (re)compile.
|
|
35
|
+
By default, non-Windows builds are built with `-march=native` flag, which means that the compiler will optimise the build for the CPU of the build machine. If you’re looking to run built binaries elsewhere, this may be undesirable. To make builds redistributable, replace `"enable_native_tuning%": 1,` from *binding.gyp* with `"enable_native_tuning%": 0,` and (re)compile.
|
|
57
36
|
|
|
58
37
|
Windows builds are redistributable by default as MSVC doesn’t support native CPU targeting.
|
|
59
38
|
|
|
60
|
-
Older Compilers
|
|
61
|
-
---------------
|
|
39
|
+
## Older Compilers
|
|
62
40
|
|
|
63
|
-
Unfortunately node-gyp doesn’t provide much in the way of compiler version
|
|
64
|
-
detection. As such, the build script assumes the compiler isn’t too old and
|
|
65
|
-
supports AVX. If you are trying to build using an older compiler (such as Visual
|
|
66
|
-
Studio 2008), you may need to edit *binding.gyp* to remove AVX related options,
|
|
67
|
-
such as `-mavx`, `-mpopcnt` and `"EnableEnhancedInstructionSet": "3"`
|
|
41
|
+
Unfortunately node-gyp doesn’t provide much in the way of compiler version detection. As such, the build script assumes the compiler isn’t too old and supports AVX. If you are trying to build using an older compiler (such as Visual Studio 2008), you may need to edit *binding.gyp* to remove AVX related options, such as `-mavx`, `-mpopcnt` and `"EnableEnhancedInstructionSet": "3"`
|
|
68
42
|
|
|
69
43
|
## GCC 9 on ARMv7
|
|
70
44
|
|
|
71
45
|
I’ve noticed that GCC 9.2.1 (which may include GCC 9.x.x), with ARMv7 targets, seems to generate code which crashes. I‘m not yet sure on the reason, but have not seen the issue with GCC 8.3.0 or Clang, or GCC 9 with ARMv8 targets.
|
|
72
46
|
|
|
73
|
-
API
|
|
74
|
-
===
|
|
47
|
+
# API
|
|
75
48
|
|
|
76
|
-
Note, on node v0.10, functions returning a Buffer actually return a *SlowBuffer*
|
|
77
|
-
object, similar to how node’s crypto functions work.
|
|
49
|
+
Note, on node v0.10, functions returning a Buffer actually return a *SlowBuffer* object, similar to how node’s crypto functions work.
|
|
78
50
|
|
|
79
|
-
Buffer encode(Buffer data, int line_size=128, int column_offset=0)
|
|
80
|
-
------------------------------------------------------------------
|
|
51
|
+
### Buffer encode(Buffer data, int line_size=128, int column_offset=0)
|
|
81
52
|
|
|
82
53
|
Performs raw yEnc encoding on *data* returning the result.
|
|
83
|
-
*line_size* controls how often to insert newlines (note, as per yEnc
|
|
84
|
-
specifications, it's possible to have lines longer than this length)
|
|
54
|
+
*line_size* controls how often to insert newlines (note, as per yEnc specifications, it's possible to have lines longer than this length)
|
|
85
55
|
*column_offset* is the column of the first character
|
|
86
56
|
|
|
87
|
-
int encodeTo(Buffer data, Buffer output, int line_size=128, int column_offset=0)
|
|
88
|
-
--------------------------------------------------------------------------------
|
|
57
|
+
### int encodeTo(Buffer data, Buffer output, int line_size=128, int column_offset=0)
|
|
89
58
|
|
|
90
|
-
Same as above, but instead of returning a Buffer, writes it to the supplied
|
|
91
|
-
*output* Buffer
|
|
92
|
-
Note that the *output* Buffer must be at least large enough to hold the largest
|
|
93
|
-
possible output size (use the *maxSize* function to determine this), otherwise
|
|
94
|
-
an error will be thrown. Whilst this amount of space
|
|
95
|
-
is usually not required, for performance reasons this is not checked during
|
|
96
|
-
encoding, so the space is needed to prevent possible overflow conditions.
|
|
59
|
+
Same as above, but instead of returning a Buffer, writes it to the supplied *output* Buffer. Returns the length of the encoded data.
|
|
60
|
+
Note that the *output* Buffer must be at least large enough to hold the largest possible output size (use the *maxSize* function to determine this), otherwise an error will be thrown. Whilst this amount of space is usually not required, for performance reasons this is not checked during encoding, so the space is needed to prevent possible overflow conditions.
|
|
97
61
|
|
|
98
|
-
int maxSize(int length, int line_size=128, float escape_ratio=1)
|
|
99
|
-
----------------------------------------------------------------
|
|
62
|
+
### int maxSize(int length, int line_size=128, float escape_ratio=1)
|
|
100
63
|
|
|
101
|
-
Returns the maximum possible size for a raw yEnc encoded message of *length*
|
|
102
|
-
bytes. Note that this does include some provision for dealing with alignment
|
|
103
|
-
issues specific to *yencode*‘s implementation; in other words, the returned
|
|
104
|
-
value is actually an over-estimate for the maximum size.
|
|
64
|
+
Returns the maximum possible size for a raw yEnc encoded message of *length* bytes. Note that this does include some provision for dealing with alignment issues specific to *yencode*‘s implementation; in other words, the returned value is actually an over-estimate for the maximum size.
|
|
105
65
|
|
|
106
|
-
You can manually specify expected yEnc character escaping ratio with the *escape_ratio* parameter if you wish to calculate an “expected size” rather than the maximum. The ratio must be between 0 (no characters ever escaped) and 1 (all characters escaped, i.e. calculates maximum possible size, the default behavior).
|
|
66
|
+
You can manually specify expected yEnc character escaping ratio with the *escape_ratio* parameter if you wish to calculate an “expected size” rather than the maximum. The ratio must be between 0 (no characters ever escaped) and 1 (all characters escaped, i.e. calculates maximum possible size, the default behavior).
|
|
107
67
|
For random data, and a line size of 128, the expected escape ratio for yEnc is roughly 0.0158. For 1KB of random data, the probability that the escape ratio exceeds 5% would be about 2.188\*10^-12^ (or 1 in 4.571\*10^11^). For 128KB of random data, exceeding a 1.85% ratio has a likelihood of 1.174\*10^-14^ (or 1 in 8.517\*10^13^).
|
|
108
68
|
|
|
109
69
|
For usage with *encodeTo*, the *escape_ratio* must be 1.
|
|
110
70
|
|
|
111
|
-
|
|
71
|
+
### int minSize(int length, int line_size=128)
|
|
112
72
|
|
|
113
73
|
Returns the minimum possible size for a raw yEnc encoded message of *length* bytes. Unlike `maxSize`, this does not include alignment provisions for *yencode*‘s implementation of yEnc.
|
|
114
74
|
|
|
115
75
|
This is equivalent to `maxSize(length, line_size, 0) - 2` (`maxSize` adds a 2 to provision for an early end-of-line due to a line offset being used).
|
|
116
76
|
|
|
117
|
-
Buffer decode(Buffer data, bool stripDots=false)
|
|
118
|
-
------------------------------------------------
|
|
77
|
+
### Buffer decode(Buffer data, bool stripDots=false)
|
|
119
78
|
|
|
120
|
-
Performs raw yEnc decoding on *data* returning the result.
|
|
121
|
-
will perform NNTP's "dot unstuffing" during decode.
|
|
122
|
-
NNTP abstraction layer which already performs unstuffing, *stripDots* should be
|
|
123
|
-
false, otherwise, if you're processing data from the socket yourself and haven't
|
|
124
|
-
othewise performed unstuffing, *stripDots* should be set to true.
|
|
79
|
+
Performs raw yEnc decoding on *data* returning the result.
|
|
80
|
+
If *stripDots* is true, will perform NNTP's "dot unstuffing" during decode.
|
|
81
|
+
If *data* was sourced from an NNTP abstraction layer which already performs unstuffing, *stripDots* should be false, otherwise, if you're processing data from the socket yourself and haven't othewise performed unstuffing, *stripDots* should be set to true.
|
|
125
82
|
|
|
126
|
-
int decodeTo(Buffer data, Buffer output, bool stripDots=false)
|
|
127
|
-
--------------------------------------------------------------
|
|
83
|
+
### int decodeTo(Buffer data, Buffer output, bool stripDots=false)
|
|
128
84
|
|
|
129
|
-
Same as above, but instead of returning a Buffer, writes it to the supplied
|
|
130
|
-
*output* Buffer
|
|
131
|
-
Note that the *output* Buffer must be at least large enough to hold the largest
|
|
132
|
-
possible output size (i.e. length of the input), otherwise an error is thrown.
|
|
85
|
+
Same as above, but instead of returning a Buffer, writes it to the supplied *output* Buffer. Returns the length of the decoded data.
|
|
86
|
+
Note that the *output* Buffer must be at least large enough to hold the largest possible output size (i.e. length of the input), otherwise an error is thrown.
|
|
133
87
|
The *data* and *output* Buffers can be the same, for in-situ decoding.
|
|
134
88
|
|
|
135
|
-
Object decodeChunk
|
|
136
|
-
-----------------------------------------------------------------------------
|
|
89
|
+
### Object decodeChunk(Buffer data \[, string state=null\]\[, Buffer output\])
|
|
137
90
|
|
|
138
|
-
Perform raw yEnc decoding on a chunk of data sourced from NNTP. This function is
|
|
139
|
-
designed to incrementally process a stream from the network, and will perform NNTP
|
|
140
|
-
"dot unstuffing" as well as stop when the end of the data is reached.
|
|
91
|
+
Perform raw yEnc decoding on a chunk of data sourced from NNTP. This function is designed to incrementally process a stream from the network, and will perform NNTP "dot unstuffing" as well as stop when the end of the data is reached.
|
|
141
92
|
|
|
142
93
|
*data* is the data to be decoded
|
|
143
94
|
*state* is the current state of the incremental decode. Set to *null* if this is starting the decode of a new article, otherwise this should be set to the value of *state* given from the previous invocation of *decodeChunk*
|
|
144
|
-
If *output* is supplied, the output will be written here \(see *decodeTo* for notes
|
|
145
|
-
on required size\), otherwise a new buffer will be created where the output will be
|
|
146
|
-
written to. The *data* and *output* Buffers can be the same, for in-situ decoding.
|
|
95
|
+
If *output* is supplied, the output will be written here \(see *decodeTo* for notes on required size\), otherwise a new buffer will be created where the output will be written to. The *data* and *output* Buffers can be the same, for in-situ decoding.
|
|
147
96
|
|
|
148
97
|
Returns an object with the following keys:
|
|
149
98
|
|
|
150
|
-
-
|
|
151
|
-
|
|
152
|
-
- *
|
|
153
|
-
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
- *string state*: the state after decoding. This indicates the last few (up to 4) characters encountered, if they affect the decoding of subsequent characters. For example, a state of `"="` suggests that the first byte of the next call to *decodeChunk* needs to be unescaped. Feed this into the next invocation of *decodeChunk*
|
|
157
|
-
Note that this value is after NNTP “dot unstuffing”, where applicable (`\r\n.=` sequences are replaced with `\r\n=`)
|
|
99
|
+
- **int read**: number of bytes read from the *data*. Will be equal to the length of the input unless the end was reached (*ended* set to *true*).
|
|
100
|
+
- **int written**: number of bytes written to the output
|
|
101
|
+
- **Buffer output**: the output data. If the *output* parameter was supplied to this function, this will just be a reference to it.
|
|
102
|
+
- **bool ended**: whether the end of the yEnc data was reached. The *state* value will indicate the type of end which was reached
|
|
103
|
+
- **string state**: the state after decoding. This indicates the last few (up to 4) characters encountered, if they affect the decoding of subsequent characters. For example, a state of `"="` suggests that the first byte of the next call to *decodeChunk* needs to be unescaped. Feed this into the next invocation of *decodeChunk*
|
|
104
|
+
Note that this value is after NNTP “dot unstuffing”, where applicable (`\r\n.=` sequences are replaced with `\r\n=`)
|
|
158
105
|
If the end was reached (*ended* set to true), this will indicate the type of end which was reached, which can be either `\r\n=y` (yEnc control line encountered) or `\r\n.\r\n` (end of article marker encountered)
|
|
159
106
|
|
|
160
|
-
Buffer(4) crc32(Buffer data, Buffer(4) initial=false)
|
|
161
|
-
-----------------------------------------------------
|
|
107
|
+
### Buffer(4) crc32(Buffer data, Buffer(4) initial=false)
|
|
162
108
|
|
|
163
109
|
Calculate CRC32 hash of data, returning the hash as a 4 byte Buffer.
|
|
164
|
-
You can perform incremental CRC32 calculation by specifying a 4 byte Buffer in
|
|
165
|
-
the second argument.
|
|
110
|
+
You can perform incremental CRC32 calculation by specifying a 4 byte Buffer in the second argument.
|
|
166
111
|
|
|
167
112
|
**Example**
|
|
168
113
|
|
|
169
|
-
|
|
114
|
+
```javascript
|
|
170
115
|
y.crc32(new Buffer('the fox jumped'))
|
|
171
116
|
// <Buffer f8 7b 6f 30>
|
|
172
117
|
y.crc32(new Buffer(' into the fence'), new Buffer([0xf8, 0x7b, 0x6f, 0x30]))
|
|
173
118
|
// <Buffer 70 4f 00 7e>
|
|
174
|
-
|
|
119
|
+
```
|
|
175
120
|
|
|
176
|
-
Buffer(4) crc32_combine(Buffer(4) crc1, Buffer(4) crc2, int len2)
|
|
177
|
-
-----------------------------------------------------------------
|
|
121
|
+
### Buffer(4) crc32_combine(Buffer(4) crc1, Buffer(4) crc2, int len2)
|
|
178
122
|
|
|
179
|
-
Combines two CRC32s, returning the resulting CRC32 as a 4 byte Buffer. To put it
|
|
180
|
-
|
|
181
|
-
`b.length`.
|
|
182
|
-
*crc1* is the first CRC, *crc2* is the CRC to append onto the end, where *len2*
|
|
183
|
-
represents then length of the data being appended.
|
|
123
|
+
Combines two CRC32s, returning the resulting CRC32 as a 4 byte Buffer. To put it another way, it calculates `crc32(a+b)` given `crc32(a)`, `crc32(b)` and `b.length`.
|
|
124
|
+
*crc1* is the first CRC, *crc2* is the CRC to append onto the end, where *len2* represents then length of the data being appended.
|
|
184
125
|
|
|
185
126
|
**Example**
|
|
186
127
|
|
|
187
|
-
|
|
128
|
+
```javascript
|
|
188
129
|
y.crc32_combine(
|
|
189
130
|
y.crc32(new Buffer('the fox jumped')),
|
|
190
131
|
y.crc32(new Buffer(' into the fence')),
|
|
191
132
|
' into the fence'.length
|
|
192
133
|
)
|
|
193
134
|
// <Buffer 70 4f 00 7e>
|
|
194
|
-
|
|
135
|
+
```
|
|
195
136
|
|
|
196
|
-
Buffer(4) crc32_zeroes(int len, Buffer(4) initial=false)
|
|
197
|
-
--------------------------------------------------------
|
|
137
|
+
### Buffer(4) crc32_zeroes(int len, Buffer(4) initial=false)
|
|
198
138
|
|
|
199
|
-
Calculates the CRC32 of a sequence of *len* null bytes, returning the resulting
|
|
200
|
-
|
|
201
|
-
|
|
139
|
+
Calculates the CRC32 of a sequence of *len* null bytes, returning the resulting CRC32 as a 4 byte Buffer.
|
|
140
|
+
You can supply a starting CRC32 value by passing it in the second parameter.
|
|
141
|
+
If *len* is negative, it will remove that many null bytes instead.
|
|
202
142
|
|
|
203
143
|
**Example**
|
|
204
144
|
|
|
205
|
-
|
|
145
|
+
```javascript
|
|
206
146
|
y.crc32_zeroes(2)
|
|
207
147
|
// <Buffer 41 d9 12 ff>
|
|
208
148
|
y.crc32(new Buffer([0, 0]))
|
|
209
149
|
// <Buffer 41 d9 12 ff>
|
|
150
|
+
y.crc32_zeroes(-3, y.crc32_zeroes(5))
|
|
151
|
+
// <Buffer 41 d9 12 ff>
|
|
152
|
+
|
|
210
153
|
y.crc32_zeroes(2, y.crc32(new Buffer([1, 2])))
|
|
211
154
|
// <Buffer 9a 7c 6c 17>
|
|
212
155
|
y.crc32(new Buffer([1, 2, 0, 0]))
|
|
213
156
|
// <Buffer 9a 7c 6c 17>
|
|
214
|
-
|
|
157
|
+
```
|
|
215
158
|
|
|
216
|
-
Buffer
|
|
217
|
-
-----------------------------------------------------
|
|
159
|
+
### Buffer(4) crc32_multiply(Buffer(4) x, Buffer(4) y)
|
|
218
160
|
|
|
219
|
-
Returns
|
|
220
|
-
|
|
221
|
-
(this differs from the above functions).
|
|
161
|
+
Returns the product of *x* and *y* in the CRC32 field.
|
|
162
|
+
This is a low-level CRC32 operation should you find the need to use it.
|
|
222
163
|
|
|
223
|
-
|
|
164
|
+
### Buffer(4) crc32_shift(int n, Buffer(4) crc=[128,0,0,0])
|
|
224
165
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
// '=ybegin line=128 size=5 name=bytes.bin\r\n*+,-.\r\n=yend size=5 crc32=515ad3cc'
|
|
228
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
166
|
+
Returns 2<sup>*n*</sup> in the CRC32 field if *crc* is not supplied. If *crc* is supplied, shifts it forward by *n* bits. *n* can be negative.
|
|
167
|
+
This is a low-level CRC32 operation should you find the need to use it.
|
|
229
168
|
|
|
230
|
-
|
|
231
|
-
----------------------------------------------------------------------------
|
|
169
|
+
**Example**
|
|
232
170
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
171
|
+
```javascript
|
|
172
|
+
function crc32_combine(crc1, crc2, len2) {
|
|
173
|
+
var shifted = y.crc32_shift(len2*8, crc1);
|
|
174
|
+
shifted[0] ^= crc2[0];
|
|
175
|
+
shifted[1] ^= crc2[1];
|
|
176
|
+
shifted[2] ^= crc2[2];
|
|
177
|
+
shifted[3] ^= crc2[3];
|
|
178
|
+
return shifted;
|
|
179
|
+
}
|
|
180
|
+
```
|
|
237
181
|
|
|
238
|
-
|
|
182
|
+
### Buffer post(string filename, data, int line_size=128)
|
|
239
183
|
|
|
240
|
-
|
|
241
|
-
|
|
184
|
+
Returns a single yEnc encoded post, suitable for posting to newsgroups.
|
|
185
|
+
Note that *data* can be a Buffer or string or anything that `Buffer.from` or `new Buffer` accepts (this differs from the above functions).
|
|
242
186
|
|
|
243
|
-
|
|
187
|
+
**Example**
|
|
244
188
|
|
|
245
|
-
|
|
189
|
+
```javascript
|
|
190
|
+
y.post('bytes.bin', [0, 1, 2, 3, 4]).toString()
|
|
191
|
+
// '=ybegin line=128 size=5 name=bytes.bin\r\n*+,-.\r\n=yend size=5 crc32=515ad3cc'
|
|
192
|
+
```
|
|
246
193
|
|
|
247
|
-
|
|
194
|
+
### YEncoder multi_post(string filename, int size, int parts, int line_size=128)
|
|
248
195
|
|
|
249
|
-
-
|
|
196
|
+
Returns a *YEncoder* instance for generating multi-part yEnc posts. This implementation will only generate multi-part posts sequentially.
|
|
197
|
+
You need to supply the *size* of the file, and the number of *parts* that it will be broken into (typically this will be `Math.ceil(file_size/article_size)`)
|
|
250
198
|
|
|
251
|
-
|
|
199
|
+
The *YEncoder* instance has the following method and read-only properties:
|
|
252
200
|
|
|
253
|
-
-
|
|
201
|
+
- **Buffer encode(data)** : Encode the next part (*data*) and returns the result.
|
|
202
|
+
- **int size** : The file's size
|
|
203
|
+
- **int parts** : Number of parts to post
|
|
204
|
+
- **int line_size** : Size of each line
|
|
205
|
+
- **int part** : Current part
|
|
206
|
+
- **int pos** : Current position in file
|
|
207
|
+
- **int crc** : CRC32 of data already fed through *encode()*
|
|
254
208
|
|
|
255
209
|
**Example**
|
|
256
210
|
|
|
257
|
-
|
|
211
|
+
```javascript
|
|
258
212
|
enc = y.multi_post('bytes.bin', 5, 1)
|
|
259
213
|
enc.encode([0, 1, 2, 3, 4]).toString()
|
|
260
214
|
// '=ybegin line=128 size=5 name=bytes.bin\r\n*+,-.\r\n=yend size=5 crc32=515ad3cc'
|
|
261
215
|
enc.crc
|
|
262
216
|
<Buffer 51 5a d3 cc>
|
|
263
|
-
|
|
217
|
+
```
|
|
264
218
|
|
|
265
219
|
**Example 2**
|
|
266
220
|
|
|
267
|
-
|
|
221
|
+
```javascript
|
|
268
222
|
enc = y.multi_post('bytes.bin', 5, 2)
|
|
269
223
|
enc.encode([0, 1, 2, 3]).toString()
|
|
270
224
|
// '=ybegin part=1 total=2 line=128 size=5 name=bytes.bin\r\n=ypart begin=1 end=4\r\n*+,-\r\n=yend size=4 part=1 pcrc32=8bb98613'
|
|
271
225
|
enc.encode([4]).toString()
|
|
272
226
|
// '=ybegin part=2 total=2 line=128 size=5 name=bytes.bin\r\n=ypart begin=5 end=5\r\n=n\r\n=yend size=1 part=2 pcrc32=d56f2b94 crc32=515ad3cc'
|
|
273
|
-
|
|
227
|
+
```
|
|
274
228
|
|
|
275
|
-
|
|
229
|
+
### {Object|DecoderError} from_post(Buffer data, bool stripDots=false)
|
|
276
230
|
|
|
277
231
|
Decode post specified in *data*. Set *stripDots* to true if NNTP “dot unstuffing” has not yet been performed.
|
|
278
232
|
|
|
279
233
|
Returns an object detailing the info parsed from the post, where the keys are:
|
|
280
234
|
|
|
281
|
-
-
|
|
282
|
-
-
|
|
283
|
-
-
|
|
284
|
-
-
|
|
285
|
-
-
|
|
286
|
-
-
|
|
287
|
-
-
|
|
288
|
-
-
|
|
289
|
-
-
|
|
290
|
-
-
|
|
235
|
+
- **int yencStart**: location of the `=ybegin` sequence (is usually `0` for most posts)
|
|
236
|
+
- **int dataStart**: location of where the yEnc raw data begins
|
|
237
|
+
- **int dataEnd**: location of where the yEnc raw data ends
|
|
238
|
+
- **int yencEnd**: location of the end of the `=yend` line (after the trailing newline)
|
|
239
|
+
- **Buffer data**: decoded data
|
|
240
|
+
- **Buffer(4) crc32**: 4 byte CRC32 of decoded data
|
|
241
|
+
- **Object\<Object\<string\>\> props**: two-level structure listing the properties given in the yEnc metadata. First level represents the line type (e.g. `=ybegin` line is keyed as `begin`), and the second level maps keys to values within that line. For example, the line `=ybegin line=128 name=my-file.dat` would be decoded as `{begin: {line: "128", name: "my-file.dat"}}`
|
|
242
|
+
- **Array\<DecoderWarning\> warnings**: a list of non-fatal issues encountered when decoding the post. Each *DecoderWarning* is an object with two properties:
|
|
243
|
+
- **string code**: type of issue
|
|
244
|
+
- **string message**: description of issue
|
|
291
245
|
|
|
292
246
|
If the post failed to decode, a *DecoderError* is returned, which is an *Error* object where the *code* property indicates the type of error. There are 3 possible error codes which could be returned:
|
|
293
247
|
|
|
@@ -295,15 +249,13 @@ If the post failed to decode, a *DecoderError* is returned, which is an *Error*
|
|
|
295
249
|
- *no_end_found*: the `=yend` sequence could not be found
|
|
296
250
|
- *missing_required_properties*: required properties could not be found
|
|
297
251
|
|
|
298
|
-
string encoding='utf8'
|
|
299
|
-
----------------------
|
|
252
|
+
### string encoding='utf8'
|
|
300
253
|
|
|
301
254
|
The default character set used for encoding filenames.
|
|
302
255
|
|
|
303
|
-
Example
|
|
304
|
-
=======
|
|
256
|
+
# Example
|
|
305
257
|
|
|
306
|
-
|
|
258
|
+
```javascript
|
|
307
259
|
var y = require('yencode');
|
|
308
260
|
var data = new Buffer(768000);
|
|
309
261
|
var post = Buffer.concat([
|
|
@@ -314,27 +266,16 @@ var post = Buffer.concat([
|
|
|
314
266
|
// yEnc footer
|
|
315
267
|
new Buffer('\r\n=yend size=768000 crc32=' + y.crc32(data).toString('hex'))
|
|
316
268
|
]);
|
|
317
|
-
|
|
269
|
+
```
|
|
318
270
|
|
|
319
|
-
Algorithm
|
|
320
|
-
=========
|
|
271
|
+
# Algorithm
|
|
321
272
|
|
|
322
|
-
A brief description of how the SIMD yEnc encoding algorithm works [can be found
|
|
323
|
-
here](https://github.com/animetosho/node-yencode/issues/4#issuecomment-330025192).
|
|
324
|
-
I may eventually write up something more detailed, regarding optimizations and
|
|
325
|
-
such used.
|
|
273
|
+
A brief description of how the SIMD yEnc encoding algorithm works [can be found here](https://github.com/animetosho/node-yencode/issues/4#issuecomment-330025192). I may eventually write up something more detailed, regarding optimizations and such used.
|
|
326
274
|
|
|
327
|
-
License
|
|
328
|
-
=======
|
|
275
|
+
# License
|
|
329
276
|
|
|
330
|
-
This module is Public Domain or
|
|
331
|
-
[CC0](https://creativecommons.org/publicdomain/zero/1.0/legalcode) (or
|
|
332
|
-
equivalent) if PD isn’t recognised.
|
|
277
|
+
This module is Public Domain or [CC0](https://creativecommons.org/publicdomain/zero/1.0/legalcode) (or equivalent) if PD isn’t recognised.
|
|
333
278
|
|
|
334
|
-
[crcutil](https://code.google.com/p/crcutil/), used for CRC32 calculation, is
|
|
335
|
-
licensed under the [Apache License
|
|
336
|
-
2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
|
279
|
+
[crcutil](https://code.google.com/p/crcutil/), used for CRC32 calculation, is licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
|
337
280
|
|
|
338
|
-
[zlib-ng](https://github.com/Dead2/zlib-ng), from where the CRC32 calculation
|
|
339
|
-
using folding approach was stolen, is under a [zlib
|
|
340
|
-
license](https://github.com/Dead2/zlib-ng/blob/develop/LICENSE.md)
|
|
281
|
+
[zlib-ng](https://github.com/Dead2/zlib-ng), from where the CRC32 calculation using folding approach was stolen, is under a [zlib license](https://github.com/Dead2/zlib-ng/blob/develop/LICENSE.md)
|
package/binding.gyp
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"variables": {
|
|
3
3
|
"enable_native_tuning%": 1,
|
|
4
|
-
"disable_avx256%": 0
|
|
4
|
+
"disable_avx256%": 0,
|
|
5
|
+
"disable_crcutil%": 0
|
|
5
6
|
},
|
|
6
7
|
"target_defaults": {
|
|
7
8
|
"conditions": [
|
|
@@ -41,6 +42,9 @@
|
|
|
41
42
|
['disable_avx256!=0', {
|
|
42
43
|
"defines": ["YENC_DISABLE_AVX256=1"]
|
|
43
44
|
}],
|
|
45
|
+
['disable_crcutil!=0', {
|
|
46
|
+
"defines": ["YENC_DISABLE_CRCUTIL=1"]
|
|
47
|
+
}],
|
|
44
48
|
['OS!="win" and enable_native_tuning!=0', {
|
|
45
49
|
"defines": ["YENC_BUILD_NATIVE=1"]
|
|
46
50
|
}],
|
|
@@ -74,7 +78,7 @@
|
|
|
74
78
|
"targets": [
|
|
75
79
|
{
|
|
76
80
|
"target_name": "yencode",
|
|
77
|
-
"dependencies": ["
|
|
81
|
+
"dependencies": ["yencode_sse2", "yencode_ssse3", "yencode_clmul", "yencode_clmul256", "yencode_avx", "yencode_avx2", "yencode_vbmi2", "yencode_neon", "yencode_armcrc", "yencode_rvv", "yencode_zbkc"],
|
|
78
82
|
"sources": [
|
|
79
83
|
"src/yencode.cc",
|
|
80
84
|
"src/platform.cc",
|
|
@@ -82,7 +86,12 @@
|
|
|
82
86
|
"src/decoder.cc",
|
|
83
87
|
"src/crc.cc"
|
|
84
88
|
],
|
|
85
|
-
"
|
|
89
|
+
"conditions": [
|
|
90
|
+
['target_arch in "ia32 x64" and disable_crcutil==0', {
|
|
91
|
+
"dependencies": ["crcutil"],
|
|
92
|
+
"include_dirs": ["crcutil-1.0/code","crcutil-1.0/examples"]
|
|
93
|
+
}]
|
|
94
|
+
]
|
|
86
95
|
},
|
|
87
96
|
{
|
|
88
97
|
"target_name": "yencode_sse2",
|
|
@@ -324,7 +333,8 @@
|
|
|
324
333
|
"target_name": "yencode_rvv",
|
|
325
334
|
"type": "static_library",
|
|
326
335
|
"sources": [
|
|
327
|
-
"src/encoder_rvv.cc"
|
|
336
|
+
"src/encoder_rvv.cc",
|
|
337
|
+
"src/decoder_rvv.cc"
|
|
328
338
|
],
|
|
329
339
|
"cflags!": ["-fno-omit-frame-pointer", "-fno-tree-vrp", "-fno-strict-aliasing"],
|
|
330
340
|
"cxxflags!": ["-fno-omit-frame-pointer", "-fno-tree-vrp", "-fno-strict-aliasing"],
|
|
@@ -338,9 +348,13 @@
|
|
|
338
348
|
"variables": {"supports_rvv%": "<!(<!(echo ${CXX_target:-${CXX:-c++}}) -MM -E src/encoder_rvv.cc -march=rv64gcv 2>/dev/null || true)"},
|
|
339
349
|
"conditions": [
|
|
340
350
|
['supports_rvv!=""', {
|
|
351
|
+
"cflags!": ["-march=native"],
|
|
352
|
+
"cxxflags!": ["-march=native"],
|
|
341
353
|
"cflags": ["-march=rv64gcv"],
|
|
342
354
|
"cxxflags": ["-march=rv64gcv"],
|
|
343
355
|
"xcode_settings": {
|
|
356
|
+
"OTHER_CFLAGS!": ["-march=native"],
|
|
357
|
+
"OTHER_CXXFLAGS!": ["-march=native"],
|
|
344
358
|
"OTHER_CFLAGS": ["-march=rv64gcv"],
|
|
345
359
|
"OTHER_CXXFLAGS": ["-march=rv64gcv"],
|
|
346
360
|
}
|
|
@@ -351,9 +365,13 @@
|
|
|
351
365
|
"variables": {"supports_rvv%": "<!(<!(echo ${CXX_target:-${CXX:-c++}}) -MM -E src/encoder_rvv.cc -march=rv32gcv 2>/dev/null || true)"},
|
|
352
366
|
"conditions": [
|
|
353
367
|
['supports_rvv!=""', {
|
|
368
|
+
"cflags!": ["-march=native"],
|
|
369
|
+
"cxxflags!": ["-march=native"],
|
|
354
370
|
"cflags": ["-march=rv32gcv"],
|
|
355
371
|
"cxxflags": ["-march=rv32gcv"],
|
|
356
372
|
"xcode_settings": {
|
|
373
|
+
"OTHER_CFLAGS!": ["-march=native"],
|
|
374
|
+
"OTHER_CXXFLAGS!": ["-march=native"],
|
|
357
375
|
"OTHER_CFLAGS": ["-march=rv32gcv"],
|
|
358
376
|
"OTHER_CXXFLAGS": ["-march=rv32gcv"],
|
|
359
377
|
}
|
|
@@ -399,8 +417,58 @@
|
|
|
399
417
|
]
|
|
400
418
|
},
|
|
401
419
|
{
|
|
402
|
-
"target_name": "
|
|
420
|
+
"target_name": "yencode_zbkc",
|
|
403
421
|
"type": "static_library",
|
|
422
|
+
"sources": [
|
|
423
|
+
"src/crc_riscv.cc"
|
|
424
|
+
],
|
|
425
|
+
"cflags!": ["-fno-omit-frame-pointer", "-fno-tree-vrp", "-fno-strict-aliasing"],
|
|
426
|
+
"cxxflags!": ["-fno-omit-frame-pointer", "-fno-tree-vrp", "-fno-strict-aliasing"],
|
|
427
|
+
"xcode_settings": {
|
|
428
|
+
"OTHER_CFLAGS!": ["-fno-omit-frame-pointer", "-fno-tree-vrp", "-fno-strict-aliasing"],
|
|
429
|
+
"OTHER_CXXFLAGS!": ["-fno-omit-frame-pointer", "-fno-tree-vrp", "-fno-strict-aliasing"]
|
|
430
|
+
},
|
|
431
|
+
"msvs_settings": {"VCCLCompilerTool": {"BufferSecurityCheck": "false"}},
|
|
432
|
+
"conditions": [
|
|
433
|
+
['target_arch=="riscv64" and OS!="win"', {
|
|
434
|
+
"variables": {"supports_zbkc%": "<!(<!(echo ${CXX_target:-${CXX:-c++}}) -MM -E src/crc_riscv.cc -march=rv64gc_zbkc 2>/dev/null || true)"},
|
|
435
|
+
"conditions": [
|
|
436
|
+
['supports_zbkc!=""', {
|
|
437
|
+
"cflags!": ["-march=native"],
|
|
438
|
+
"cxxflags!": ["-march=native"],
|
|
439
|
+
"cflags": ["-march=rv64gc_zbkc"],
|
|
440
|
+
"cxxflags": ["-march=rv64gc_zbkc"],
|
|
441
|
+
"xcode_settings": {
|
|
442
|
+
"OTHER_CFLAGS!": ["-march=native"],
|
|
443
|
+
"OTHER_CXXFLAGS!": ["-march=native"],
|
|
444
|
+
"OTHER_CFLAGS": ["-march=rv64gc_zbkc"],
|
|
445
|
+
"OTHER_CXXFLAGS": ["-march=rv64gc_zbkc"],
|
|
446
|
+
}
|
|
447
|
+
}]
|
|
448
|
+
]
|
|
449
|
+
}],
|
|
450
|
+
['target_arch=="riscv32" and OS!="win"', {
|
|
451
|
+
"variables": {"supports_zbkc%": "<!(<!(echo ${CXX_target:-${CXX:-c++}}) -MM -E src/crc_riscv.cc -march=rv32gc_zbkc 2>/dev/null || true)"},
|
|
452
|
+
"conditions": [
|
|
453
|
+
['supports_zbkc!=""', {
|
|
454
|
+
"cflags!": ["-march=native"],
|
|
455
|
+
"cxxflags!": ["-march=native"],
|
|
456
|
+
"cflags": ["-march=rv32gc_zbkc"],
|
|
457
|
+
"cxxflags": ["-march=rv32gc_zbkc"],
|
|
458
|
+
"xcode_settings": {
|
|
459
|
+
"OTHER_CFLAGS!": ["-march=native"],
|
|
460
|
+
"OTHER_CXXFLAGS!": ["-march=native"],
|
|
461
|
+
"OTHER_CFLAGS": ["-march=rv32gc_zbkc"],
|
|
462
|
+
"OTHER_CXXFLAGS": ["-march=rv32gc_zbkc"],
|
|
463
|
+
}
|
|
464
|
+
}]
|
|
465
|
+
]
|
|
466
|
+
}]
|
|
467
|
+
]
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
"target_name": "crcutil",
|
|
471
|
+
"type": "none",
|
|
404
472
|
"sources": [
|
|
405
473
|
"crcutil-1.0/code/crc32c_sse4.cc",
|
|
406
474
|
"crcutil-1.0/code/multiword_64_64_cl_i386_mmx.cc",
|
|
@@ -422,7 +490,12 @@
|
|
|
422
490
|
},
|
|
423
491
|
"msvs_settings": {"VCCLCompilerTool": {"BufferSecurityCheck": "false"}},
|
|
424
492
|
"include_dirs": ["crcutil-1.0/code", "crcutil-1.0/tests"],
|
|
425
|
-
"defines": ["CRCUTIL_USE_MM_CRC32=0"]
|
|
493
|
+
"defines": ["CRCUTIL_USE_MM_CRC32=0"],
|
|
494
|
+
"conditions": [
|
|
495
|
+
['target_arch in "ia32 x64" and disable_crcutil==0', {
|
|
496
|
+
"type": "static_library",
|
|
497
|
+
}]
|
|
498
|
+
]
|
|
426
499
|
}
|
|
427
500
|
]
|
|
428
501
|
}
|
package/index.js
CHANGED
|
@@ -190,6 +190,8 @@ module.exports = {
|
|
|
190
190
|
crc32: y.crc32,
|
|
191
191
|
crc32_combine: y.crc32_combine,
|
|
192
192
|
crc32_zeroes: y.crc32_zeroes,
|
|
193
|
+
crc32_multiply: y.crc32_multiply,
|
|
194
|
+
crc32_shift: y.crc32_shift,
|
|
193
195
|
|
|
194
196
|
post: function(filename, data, line_size) {
|
|
195
197
|
if(!line_size) line_size = 128;
|