yencode 1.1.4 → 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 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
- - fast raw yEnc encoding with the ability to specify line length. A single
9
- thread can achieve \>450MB/s on a Raspberry Pi 3, or \>5GB/s on a Core-i
10
- series CPU.
11
- - fast yEnc decoding, with and without NNTP layer dot unstuffing.
12
- A single thread can achieve \>300MB/s on a Raspberry Pi 3, or \>4.5GB/s on a Core-i series CPU.
13
- - SIMD optimised encoding and decoding routines, which can use ARMv7 NEON, ARMv8 ASIMD or the
14
- following x86 CPU features when available (with dynamic dispatch): SSE2,
15
- SSSE3, AVX, AVX2, AVX512-BW (128/256-bit), AVX512-VBMI2
16
- - full yEnc encoding for single and multi-part posts, according to the
17
- [version 1.3 specifications](http://www.yenc.org/yenc-draft.1.3.txt)
18
- - full yEnc decoding of posts
19
- - fast compiled CRC32 implementation via
20
- [crcutil](https://code.google.com/p/crcutil/) or [PCLMULQDQ
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. Returns the length of the encoded data.
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
- ## int minSize(int length, int line_size=128)
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. If *stripDots* is true,
121
- will perform NNTP's "dot unstuffing" during decode. If *data* was sourced from an
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. Returns the length of the decoded data.
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\(Buffer data \[, string state=null\]\[, Buffer output\]\)
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
- - *int read*: number of bytes read from the *data*. Will be equal to the length of
151
- the input unless the end was reached (*ended* set to *true*).
152
- - *int written*: number of bytes written to the output
153
- - *Buffer output*: the output data. If the *output* parameter was supplied to this
154
- function, this will just be a reference to it.
155
- - *bool ended*: whether the end of the yEnc data was reached. The *state* value will indicate the type of end which was reached
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
- another way, it calculates `crc32(a+b)` given `crc32(a)`, `crc32(b)` and
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
- CRC32 as a 4 byte Buffer.
201
- You can supply a starting CRC32 value by passing it in the second parameter.
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 post(string filename, data, int line_size=128)
217
- -----------------------------------------------------
159
+ ### Buffer(4) crc32_multiply(Buffer(4) x, Buffer(4) y)
218
160
 
219
- Returns a single yEnc encoded post, suitable for posting to newsgroups.
220
- Note that *data* can be a Buffer or string or anything that `Buffer.from` or `new Buffer` accepts
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
- **Example**
164
+ ### Buffer(4) crc32_shift(int n, Buffer(4) crc=[128,0,0,0])
224
165
 
225
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
226
- y.post('bytes.bin', [0, 1, 2, 3, 4]).toString()
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
- YEncoder multi_post(string filename, int size, int parts, int line_size=128)
231
- ----------------------------------------------------------------------------
169
+ **Example**
232
170
 
233
- Returns a *YEncoder* instance for generating multi-part yEnc posts. This
234
- implementation will only generate multi-part posts sequentially.
235
- You need to supply the *size* of the file, and the number of *parts* that it
236
- will be broken into (typically this will be `Math.ceil(file_size/article_size)`)
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
- The *YEncoder* instance has the following method and read-only properties:
182
+ ### Buffer post(string filename, data, int line_size=128)
239
183
 
240
- - **Buffer encode(data)** : Encode the next part (*data*) and returns the
241
- result.
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
- - **int size** : The file's size
187
+ **Example**
244
188
 
245
- - **int parts** : Number of parts to post
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
- - **int line_size** : Size of each line
194
+ ### YEncoder multi_post(string filename, int size, int parts, int line_size=128)
248
195
 
249
- - **int part** : Current part
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
- - **int pos** : Current position in file
199
+ The *YEncoder* instance has the following method and read-only properties:
252
200
 
253
- - **int crc** : CRC32 of data already fed through *encode()*
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
- ## {Object|DecoderError} from_post\(Buffer data, bool stripDots=false\)
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
- - *int yencStart*: location of the `=ybegin` sequence (is usually `0` for most posts)
282
- - *int dataStart*: location of where the yEnc raw data begins
283
- - *int dataEnd*: location of where the yEnc raw data ends
284
- - *int yencEnd*: location of the end of the `=yend` line (after the trailing newline)
285
- - *Buffer data*: decoded data
286
- - *Buffer(4) crc32*: 4 byte CRC32 of decoded data
287
- - *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"}}`
288
- - *Array\<DecoderWarning\> warnings*: a list of non-fatal issues encountered when decoding the post. Each *DecoderWarning* is an object with two properties:
289
- - *string code*: type of issue
290
- - *string message*: description of issue
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": ["crcutil", "yencode_sse2", "yencode_ssse3", "yencode_clmul", "yencode_clmul256", "yencode_avx", "yencode_avx2", "yencode_vbmi2", "yencode_neon", "yencode_armcrc", "yencode_rvv"],
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
- "include_dirs": ["crcutil-1.0/code","crcutil-1.0/examples"]
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": "crcutil",
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;