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
package/README.md CHANGED
@@ -1,231 +1,339 @@
1
- This module provides a very fast (non-JS) compiled implementation of [yEnc
2
- encoding](<http://www.yenc.org/yenc-draft.1.3.txt>) and CRC32 hash calculation
3
- for node.js. It's mainly optimised for x86 processors, and will use SIMD
4
- operations if available.
5
-
6
- This module should be *significantly* faster than pure Javascript versions.
7
-
8
- Supports:
9
- ---------
10
-
11
- - fast raw yEnc encoding with incremental support and the ability to specify
12
- line length. Optimised to use SSE2 and SSSE3/SSE4.1 if available - a single
13
- thread can achieve \>500MB/s on a low power Atom CPU, or \>3GB/s on a Core-i
14
- series CPU.
15
-
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
-
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) with incremental support (\>1GB/s on a low power Atom CPU)
23
-
24
- - ability to combine two CRC32 hashes into one (useful for amalgamating
25
- pcrc32s into a crc32 for yEnc)
26
-
27
- - (may eventually support) yEnc decoding
28
-
29
- Should work on nodejs 0.10.x and later.
30
-
31
- Installing
32
- ==========
33
-
34
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
35
- npm install yencode
36
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37
-
38
- Or you can download the package and run
39
-
40
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
41
- npm install -g node-gyp # if you don't have it already
42
- node-gyp rebuild
43
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44
-
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.
48
-
49
- Some versions of GCC/Clang don't like the `-march=native` switch. If you're
50
- having build issues with these compilers, try removing all instances of
51
- `"-march=native",` from *binding.gyp* and recompiling. Note that some CPU
52
- specific optimisations may not be enabled if the flag is removed.
53
-
54
- API
55
- ===
56
-
57
- Note that for the *encode*, *crc32* and *crc32\_combine* functions, the *data*
58
- parameter must be a Buffer and not a string. Also, on node v0.10, these
59
- functions actually return a *SlowBuffer* object, similar to how node’s crypto
60
- functions work.
61
-
62
- Buffer encode(Buffer data, int line\_size=128, int column\_offset=0)
63
- --------------------------------------------------------------------
64
-
65
- Performs raw yEnc encoding on *data* returning the result.
66
- *line\_size* controls how often to insert newlines (note, as per yEnc
67
- specifications, it's possible to have lines longer than this length)
68
- *column\_offset* is the column of the first character
69
-
70
- int encodeTo(Buffer data, Buffer output, int line\_size=128, int column\_offset=0)
71
- ----------------------------------------------------------------------------------
72
-
73
- Same as above, but instead of returning a Buffer, writes it to the supplied
74
- *output* Buffer. Returns the length of the encoded data.
75
- Note that the *output* Buffer must be at least large enough to hold the largest
76
- possible output size (use the *maxSize* function to determine this), otherwise
77
- the function returns 0 and does not encode anything. Whilst this amount of space
78
- is usually not required, for performance reasons this is not checked during
79
- encoding, so the space is needed to prevent possible overflow conditions.
80
-
81
- int maxSize(int length, int line\_size=128)
82
- -------------------------------------------
83
-
84
- Returns the maximum possible size for a raw yEnc encoded message of *length*
85
- bytes. Note that this does include some provision for dealing with alignment
86
- issues specific to *yencode*‘s implementation; in other words, the returned
87
- value is actually an over-estimate for the maximum size.
88
-
89
- Buffer(4) crc32(Buffer data, Buffer(4) initial=false)
90
- -----------------------------------------------------
91
-
92
- Calculate CRC32 hash of data, returning the hash as a 4 byte Buffer.
93
- You can perform incremental CRC32 calculation by specifying a 4 byte Buffer in
94
- the second argument.
95
-
96
- **Example**
97
-
98
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99
- y.crc32(new Buffer('the fox jumped'))
100
- // <Buffer f8 7b 6f 30>
101
- y.crc32(new Buffer(' into the fence'), new Buffer([0xf8, 0x7b, 0x6f, 0x30]))
102
- // <Buffer 70 4f 00 7e>
103
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104
-
105
- Buffer(4) crc32\_combine(Buffer(4) crc1, Buffer(4) crc2, int len2)
106
- ------------------------------------------------------------------
107
-
108
- Combines two CRC32s, returning the resulting CRC32 as a 4 byte Buffer. To put it
109
- another way, it calculates `crc32(a+b)` given `crc32(a)`, `crc32(b)` and
110
- `b.length`.
111
- *crc1* is the first CRC, *crc2* is the CRC to append onto the end, where *len2*
112
- represents then length of the data being appended.
113
-
114
- **Example**
115
-
116
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117
- y.crc32_combine(
118
- y.crc32(new Buffer('the fox jumped')),
119
- y.crc32(new Buffer(' into the fence')),
120
- ' into the fence'.length
121
- )
122
- // <Buffer 70 4f 00 7e>
123
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124
-
125
- Buffer(4) crc32\_zeroes(int len)
126
- --------------------------------
127
-
128
- Calculates the CRC32 of a sequence of *len* null bytes, returning the resulting
129
- CRC32 as a 4 byte Buffer.
130
-
131
- **Example**
132
-
133
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
134
- y.crc32_zeroes(2)
135
- // <Buffer 41 d9 12 ff>
136
- y.crc32(new Buffer([0, 0]))
137
- // <Buffer 41 d9 12 ff>
138
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
139
-
140
- Buffer post(string filename, data, int line\_size=128)
141
- ------------------------------------------------------
142
-
143
- Returns a single yEnc encoded post, suitable for posting to newsgroups.
144
- Note that *data* can be a Buffer or string or anything that `new Buffer` accepts
145
- (this differs from the above functions).
146
-
147
- **Example**
148
-
149
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
150
- y.post('bytes.bin', [0, 1, 2, 3, 4]).toString()
151
- // '=ybegin line=128 size=5 name=bytes.bin\r\n*+,-.\r\n=yend size=5 crc32=515ad3cc'
152
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
153
-
154
- YEncoder multi\_post(string filename, int size, int parts, int line\_size=128)
155
- ------------------------------------------------------------------------------
156
-
157
- Returns a *YEncoder* instance for generating multi-part yEnc posts. This
158
- implementation will only generate multi-part posts sequentially.
159
- You need to supply the *size* of the file, and the number of *parts* that it
160
- will be broken into (typically this will be `Math.ceil(file_size/article_size)`)
161
-
162
- The *YEncoder* instance has the following method and read-only properties:
163
-
164
- - **Buffer encode(data)** : Encode the next part (*data*) and returns the
165
- result.
166
-
167
- - **int size** : The file's size
168
-
169
- - **int parts** : Number of parts to post
170
-
171
- - **int line\_size** : Size of each line
172
-
173
- - **int part** : Current part
174
-
175
- - **int pos** : Current position in file
176
-
177
- - **int crc** : CRC32 of data already fed through *encode()*
178
-
179
- **Example**
180
-
181
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
182
- enc = y.multi_post('bytes.bin', 5, 1)
183
- enc.encode([0, 1, 2, 3, 4]).toString()
184
- // '=ybegin line=128 size=5 name=bytes.bin\r\n*+,-.\r\n=yend size=5 crc32=515ad3cc'
185
- enc.crc
186
- <Buffer 51 5a d3 cc>
187
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
188
-
189
- **Example 2**
190
-
191
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192
- enc = y.multi_post('bytes.bin', 5, 2)
193
- enc.encode([0, 1, 2, 3]).toString()
194
- // '=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'
195
- enc.encode([4]).toString()
196
- // '=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'
197
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
198
-
199
- string encoding='utf8'
200
- ----------------------
201
-
202
- The default character set used for encoding filenames.
203
-
204
- Example
205
- =======
206
-
207
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
208
- var y = require('yencode');
209
- var data = new Buffer(768000);
210
- var post = Buffer.concat([
211
- // yEnc header
212
- new Buffer('=ybegin line=128 size=768000 name=rubbish.bin\r\n'),
213
- // encode the data
214
- y.encode(data),
215
- // yEnc footer
216
- new Buffer('\r\n=yend size=768000 crc32=' + y.crc32(data).toString('hex'))
217
- ]);
218
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
219
-
220
- License
221
- =======
222
-
223
- This module is Public Domain.
224
-
225
- [crcutil](<https://code.google.com/p/crcutil/>), used for CRC32 calculation, is
226
- licensed under the [Apache License
227
- 2.0](<http://www.apache.org/licenses/LICENSE-2.0>)
228
-
229
- [zlib-ng](<https://github.com/Dead2/zlib-ng>), from where the CRC32 calculation
230
- using folding approach was stolen, is under a [zlib
231
- license](<https://github.com/Dead2/zlib-ng/blob/develop/LICENSE.md>)
1
+ This module provides a very fast (as in gigabytes per second), compiled implementation of [yEnc](http://www.yenc.org/yenc-draft.1.3.txt) and CRC32 (IEEE) hash calculation for node.js. The implementations are optimised for speed, and uses x86/ARM SIMD optimised routines if such CPU features are available.
2
+
3
+ This module should be 1-2 orders of magnitude faster than pure Javascript versions.
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
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
35
+ npm install yencode
36
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37
+
38
+ Or you can download the package and run
39
+
40
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
41
+ npm install -g node-gyp # if you don't have it already
42
+ node-gyp rebuild
43
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44
+
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.
48
+
49
+ Redistributable Builds
50
+ ----------------------
51
+
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.
57
+
58
+ Windows builds are redistributable by default as MSVC doesn’t support native CPU targeting.
59
+
60
+ Older Compilers
61
+ ---------------
62
+
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"`
68
+
69
+ ## GCC 9 on ARMv7
70
+
71
+ 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
+
73
+ API
74
+ ===
75
+
76
+ Note, on node v0.10, functions returning a Buffer actually return a *SlowBuffer*
77
+ object, similar to how node’s crypto functions work.
78
+
79
+ Buffer encode(Buffer data, int line_size=128, int column_offset=0)
80
+ ------------------------------------------------------------------
81
+
82
+ 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)
85
+ *column_offset* is the column of the first character
86
+
87
+ int encodeTo(Buffer data, Buffer output, int line_size=128, int column_offset=0)
88
+ --------------------------------------------------------------------------------
89
+
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.
97
+
98
+ int maxSize(int length, int line_size=128, float escape_ratio=1)
99
+ ----------------------------------------------------------------
100
+
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.
105
+
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).
107
+ 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
+
109
+ For usage with *encodeTo*, the *escape_ratio* must be 1.
110
+
111
+ ## int minSize(int length, int line_size=128)
112
+
113
+ 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
+
115
+ 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
+
117
+ Buffer decode(Buffer data, bool stripDots=false)
118
+ ------------------------------------------------
119
+
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.
125
+
126
+ int decodeTo(Buffer data, Buffer output, bool stripDots=false)
127
+ --------------------------------------------------------------
128
+
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.
133
+
134
+ Object decodeChunk\(Buffer data \[, string state=null\]\[, Buffer output\]\)
135
+ -----------------------------------------------------------------------------
136
+
137
+ Perform raw yEnc decoding on a chunk of data sourced from NNTP. This function is
138
+ designed to incrementally process a stream from the network, and will perform NNTP
139
+ "dot unstuffing" as well as stop when the end of the data is reached.
140
+
141
+ *data* is the data to be decoded
142
+ *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*
143
+ If *output* is supplied, the output will be written here \(see *decodeTo* for notes
144
+ on required size\), otherwise a new buffer will be created where the output will be
145
+ written to.
146
+
147
+ Returns an object with the following keys:
148
+
149
+ - *int read*: number of bytes read from the *data*. Will be equal to the length of
150
+ the input unless the end was reached (*ended* set to *true*).
151
+ - *int written*: number of bytes written to the output
152
+ - *Buffer output*: the output data. If the *output* parameter was supplied to this
153
+ function, this will just be a reference to it.
154
+ - *bool ended*: whether the end of the yEnc data was reached. The *state* value will indicate the type of end which was reached
155
+ - *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*
156
+ Note that this value is after NNTP “dot unstuffing”, where applicable (`\r\n.=` sequences are replaced with `\r\n=`)
157
+ 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)
158
+
159
+ Buffer(4) crc32(Buffer data, Buffer(4) initial=false)
160
+ -----------------------------------------------------
161
+
162
+ Calculate CRC32 hash of data, returning the hash as a 4 byte Buffer.
163
+ You can perform incremental CRC32 calculation by specifying a 4 byte Buffer in
164
+ the second argument.
165
+
166
+ **Example**
167
+
168
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169
+ y.crc32(new Buffer('the fox jumped'))
170
+ // <Buffer f8 7b 6f 30>
171
+ y.crc32(new Buffer(' into the fence'), new Buffer([0xf8, 0x7b, 0x6f, 0x30]))
172
+ // <Buffer 70 4f 00 7e>
173
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174
+
175
+ Buffer(4) crc32_combine(Buffer(4) crc1, Buffer(4) crc2, int len2)
176
+ -----------------------------------------------------------------
177
+
178
+ Combines two CRC32s, returning the resulting CRC32 as a 4 byte Buffer. To put it
179
+ another way, it calculates `crc32(a+b)` given `crc32(a)`, `crc32(b)` and
180
+ `b.length`.
181
+ *crc1* is the first CRC, *crc2* is the CRC to append onto the end, where *len2*
182
+ represents then length of the data being appended.
183
+
184
+ **Example**
185
+
186
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
187
+ y.crc32_combine(
188
+ y.crc32(new Buffer('the fox jumped')),
189
+ y.crc32(new Buffer(' into the fence')),
190
+ ' into the fence'.length
191
+ )
192
+ // <Buffer 70 4f 00 7e>
193
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
194
+
195
+ Buffer(4) crc32_zeroes(int len, Buffer(4) initial=false)
196
+ --------------------------------------------------------
197
+
198
+ Calculates the CRC32 of a sequence of *len* null bytes, returning the resulting
199
+ CRC32 as a 4 byte Buffer.
200
+ You can supply a starting CRC32 value by passing it in the second parameter.
201
+
202
+ **Example**
203
+
204
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
205
+ y.crc32_zeroes(2)
206
+ // <Buffer 41 d9 12 ff>
207
+ y.crc32(new Buffer([0, 0]))
208
+ // <Buffer 41 d9 12 ff>
209
+ y.crc32_zeroes(2, y.crc32(new Buffer([1, 2])))
210
+ // <Buffer 9a 7c 6c 17>
211
+ y.crc32(new Buffer([1, 2, 0, 0]))
212
+ // <Buffer 9a 7c 6c 17>
213
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
214
+
215
+ Buffer post(string filename, data, int line_size=128)
216
+ -----------------------------------------------------
217
+
218
+ Returns a single yEnc encoded post, suitable for posting to newsgroups.
219
+ Note that *data* can be a Buffer or string or anything that `Buffer.from` or `new Buffer` accepts
220
+ (this differs from the above functions).
221
+
222
+ **Example**
223
+
224
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225
+ y.post('bytes.bin', [0, 1, 2, 3, 4]).toString()
226
+ // '=ybegin line=128 size=5 name=bytes.bin\r\n*+,-.\r\n=yend size=5 crc32=515ad3cc'
227
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228
+
229
+ YEncoder multi_post(string filename, int size, int parts, int line_size=128)
230
+ ----------------------------------------------------------------------------
231
+
232
+ Returns a *YEncoder* instance for generating multi-part yEnc posts. This
233
+ implementation will only generate multi-part posts sequentially.
234
+ You need to supply the *size* of the file, and the number of *parts* that it
235
+ will be broken into (typically this will be `Math.ceil(file_size/article_size)`)
236
+
237
+ The *YEncoder* instance has the following method and read-only properties:
238
+
239
+ - **Buffer encode(data)** : Encode the next part (*data*) and returns the
240
+ result.
241
+
242
+ - **int size** : The file's size
243
+
244
+ - **int parts** : Number of parts to post
245
+
246
+ - **int line_size** : Size of each line
247
+
248
+ - **int part** : Current part
249
+
250
+ - **int pos** : Current position in file
251
+
252
+ - **int crc** : CRC32 of data already fed through *encode()*
253
+
254
+ **Example**
255
+
256
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
257
+ enc = y.multi_post('bytes.bin', 5, 1)
258
+ enc.encode([0, 1, 2, 3, 4]).toString()
259
+ // '=ybegin line=128 size=5 name=bytes.bin\r\n*+,-.\r\n=yend size=5 crc32=515ad3cc'
260
+ enc.crc
261
+ <Buffer 51 5a d3 cc>
262
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
263
+
264
+ **Example 2**
265
+
266
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
267
+ enc = y.multi_post('bytes.bin', 5, 2)
268
+ enc.encode([0, 1, 2, 3]).toString()
269
+ // '=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'
270
+ enc.encode([4]).toString()
271
+ // '=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'
272
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
273
+
274
+ ## {Object|DecoderError} from_post\(Buffer data, bool stripDots=false\)
275
+
276
+ Decode post specified in *data*. Set *stripDots* to true if NNTP “dot unstuffing” has not yet been performed.
277
+
278
+ Returns an object detailing the info parsed from the post, where the keys are:
279
+
280
+ - *int yencStart*: location of the `=ybegin` sequence (is usually `0` for most posts)
281
+ - *int dataStart*: location of where the yEnc raw data begins
282
+ - *int dataEnd*: location of where the yEnc raw data ends
283
+ - *int yencEnd*: location of the end of the `=yend` line (after the trailing newline)
284
+ - *Buffer data*: decoded data
285
+ - *Buffer(4) crc32*: 4 byte CRC32 of decoded data
286
+ - *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"}}`
287
+ - *Array\<DecoderWarning\> warnings*: a list of non-fatal issues encountered when decoding the post. Each *DecoderWarning* is an object with two properties:
288
+ - *string code*: type of issue
289
+ - *string message*: description of issue
290
+
291
+ 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:
292
+
293
+ - *no_start_found*: the `=ybegin` sequence could not be found
294
+ - *no_end_found*: the `=yend` sequence could not be found
295
+ - *missing_required_properties*: required properties could not be found
296
+
297
+ string encoding='utf8'
298
+ ----------------------
299
+
300
+ The default character set used for encoding filenames.
301
+
302
+ Example
303
+ =======
304
+
305
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
306
+ var y = require('yencode');
307
+ var data = new Buffer(768000);
308
+ var post = Buffer.concat([
309
+ // yEnc header
310
+ new Buffer('=ybegin line=128 size=768000 name=rubbish.bin\r\n'),
311
+ // encode the data
312
+ y.encode(data),
313
+ // yEnc footer
314
+ new Buffer('\r\n=yend size=768000 crc32=' + y.crc32(data).toString('hex'))
315
+ ]);
316
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
317
+
318
+ Algorithm
319
+ =========
320
+
321
+ A brief description of how the SIMD yEnc encoding algorithm works [can be found
322
+ here](https://github.com/animetosho/node-yencode/issues/4#issuecomment-330025192).
323
+ I may eventually write up something more detailed, regarding optimizations and
324
+ such used.
325
+
326
+ License
327
+ =======
328
+
329
+ This module is Public Domain or
330
+ [CC0](https://creativecommons.org/publicdomain/zero/1.0/legalcode) (or
331
+ equivalent) if PD isn’t recognised.
332
+
333
+ [crcutil](https://code.google.com/p/crcutil/), used for CRC32 calculation, is
334
+ licensed under the [Apache License
335
+ 2.0](http://www.apache.org/licenses/LICENSE-2.0)
336
+
337
+ [zlib-ng](https://github.com/Dead2/zlib-ng), from where the CRC32 calculation
338
+ using folding approach was stolen, is under a [zlib
339
+ license](https://github.com/Dead2/zlib-ng/blob/develop/LICENSE.md)