├── .gitignore ├── .gitmodules ├── .npmignore ├── History.md ├── LICENSE ├── README.md ├── TODO.md ├── benchmark └── bench.js ├── bin └── lz4c ├── binding.gyp ├── bower.json ├── build.sh ├── build ├── lz4.js └── lz4.min.js ├── data ├── lorem_1mb.txt ├── sphere.dae ├── sphere.lz4.dat ├── test ├── test.lz4 ├── testHC.lz4 ├── test_1.txt ├── test_medium ├── test_medium.lz4 └── test_smallchunk.lz4 ├── doc └── format.txt ├── examples ├── compress.html ├── cu.html ├── file_compress.js ├── file_compressBlock.js ├── file_compressHC.js ├── file_compressHCSync.js ├── file_compressJS.js ├── file_compressSync.js ├── file_uncompress.js ├── file_uncompressBlock.js ├── file_uncompressJS.js ├── file_uncompressSync.js └── uncompress.html ├── karma.conf.js ├── lib ├── binding.js ├── binding │ ├── lz4_binding.cc │ └── xxhash_binding.cc ├── decoder.js ├── decoder_stream.js ├── encoder.js ├── encoder_stream.js ├── lz4.js ├── lz4l.js ├── static.js ├── utils-js.js └── utils.js ├── package.json └── test ├── block-test.js ├── browser ├── block.js ├── checksum.js ├── decoder.js ├── encoder.js └── helpers │ ├── download_data_file.js │ └── spec_helper.js ├── checksum-test.js ├── decode-test.js ├── encode-test.js └── jsencode_decode-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | tmp/ 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/lz4"] 2 | path = deps/lz4 3 | url = https://github.com/Cyan4973/lz4.git 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | node_modules/ 3 | data/ 4 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 0.5.3 / 2016-09-01 2 | ================== 3 | 4 | * Issue #44: Fix compressing a zero-sized stream. Thanks @ChALkeR. 5 | 6 | 0.5.2 / 2016-03-21 7 | ================== 8 | 9 | * Issue #36: Deprecated declarations. Thanks @ee99ee. 10 | * Updated LZ4 C code base with r131. 11 | 12 | 0.5.1 / 2015-12-10 13 | ================== 14 | 15 | * Issue #37: reverted commit breaking encodeBlock. Thanks @jamievicary. 16 | 17 | 0.5.0 / 2015-09-10 18 | ================== 19 | 20 | * Merged pull request #32 (thanks go to mog422) 21 | * Updated encoding tests to not depend on pre-encoded data 22 | 23 | 0.4.1 / 2015-08-14 24 | ================== 25 | 26 | * Issue #31: LZ4 Javascript compress function corrupts data 27 | 28 | 0.4.0 / 2015-04-08 29 | ================== 30 | 31 | * Support for node 0.12 and iojs 1.6. Thanks to EricMCornelius (github.com/EricMCornelius) for his merge request. 32 | 33 | 0.3.15 / 2015-03-07 34 | =================== 35 | 36 | * Fixed build 37 | 38 | 0.3.14 / 2014-11-03 39 | =================== 40 | 41 | * Issue #22: pos variable is not in read_DataBlockChecksum 42 | 43 | 0.3.13 / 2014-09-11 44 | =================== 45 | 46 | * Issue #19: fixed regression in Node wrt invalid checksums 47 | (nodejs and browserify Buffer.readInt32LE() are incompatible) 48 | 49 | 0.3.12 / 2014-09-03 50 | =================== 51 | 52 | * Issue #7: removed checks in writeInt32LE() 53 | 54 | 0.3.11 / 2014-07-09 55 | =================== 56 | 57 | * Updated LZ4 source to r119 58 | 59 | 0.3.10 / 2014-07-09 60 | =================== 61 | 62 | * Removed garbage in build/lz4.min.js by updating minify to latest version 63 | 64 | 0.3.9 / 2014-07-06 65 | ================== 66 | 67 | * Fixed checksum errors in the decoder (browser implementation) (issue #14) 68 | * Added start and end indexes to decodeBlock() and encodeBlock() (issue #15) 69 | 70 | 0.3.8 / 2014-05-21 71 | ================== 72 | 73 | * Fixed issue where the browser implementation of Buffer checks sign in writeUInt32LE() 74 | 75 | 0.3.7 / 2014-05-20 76 | ================== 77 | 78 | * Fixed assert() when writing uncompressible data 79 | 80 | 0.3.6 / 2014-04-11 81 | ================== 82 | 83 | * Added useJS option to encoder and decoder streams 84 | 85 | 0.3.5 / 2014-04-11 86 | ================== 87 | 88 | * Fixed stream encoder typo 89 | 90 | 0.3.4 / 2014-04-07 91 | ================== 92 | 93 | * Updated lz4 source to r116 94 | * Fixed stream encoder on large inputs 95 | 96 | 0.3.3 / 2014-03-28 97 | ================== 98 | 99 | * Updated build/lz4.js and build/lz4.min.js 100 | 101 | 0.3.2 / 2014-03-27 102 | ================== 103 | 104 | * Fixed Javascript compressBlock() not writing last batch of literals under some circumstances 105 | 106 | 0.3.1 / 2014-03-18 107 | ================== 108 | 109 | * Improved Javascript encoder speed 110 | 111 | 0.3.0 / 2014-03-11 112 | ================== 113 | 114 | * First release of the pure Javascript encoder 115 | 116 | 0.2.4 / 2014-03-05 117 | ================== 118 | 119 | * Updated lz4 source to r113 120 | * Split xxHash and LZ4 bindings 121 | * Added browser support via ./build/lz4.js and ./build/lz4.min.js 122 | * Exposed block level compression/decompression functions 123 | 124 | 0.2.3 / 2013-12-15 125 | ================== 126 | 127 | * Fixed handling of uncompressed data 128 | * Sync and async encoders share the same code 129 | 130 | 0.2.2 / 2013-10-04 131 | ================== 132 | 133 | * Sync and async decoders share the same code 134 | * Async decoder emits an error on missing data 135 | 136 | 0.2.1 / 2013-10-03 137 | ================== 138 | 139 | * Fixed encoder reversed logic 140 | 141 | 0.2.0 / 2013-10-01 142 | ================== 143 | 144 | * Updated lz4 source to r104 145 | * Support for LZ4Stream format v1.4, legacy format is deprecated, use v0.1 for its support 146 | 147 | 0.1.2 / 2013-09-09 148 | ================== 149 | 150 | * Updated lz4 source to r102 151 | 152 | 0.1.1 / 2013-06-09 153 | ================== 154 | 155 | * Updated lz4 source to r96 156 | * Fixed an issue with small chunkSize parameters 157 | 158 | 0.1.0 / 2013-03-13 159 | ================== 160 | 161 | * Updated streams to use streams2 162 | 163 | 0.0.5 / 2013-03-12 164 | ================== 165 | 166 | * Updated lz4 source to r90 167 | * Fixed node binding compilation errors for node v0.10 168 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Pierre Curto 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LZ4 2 | 3 | [LZ4](http://fastcompression.blogspot.fr/) is a very fast compression and decompression algorithm. This nodejs module provides a Javascript implementation of the decoder as well as native bindings to the LZ4 functions. Nodejs Streams are also supported for compression and decompression. 4 | 5 | NB. 6 | Version 0.2 does not support the legacy format, only the one as of "LZ4 Streaming Format 1.4". Use version 0.1 if required. 7 | 8 | ## Build 9 | 10 | With NodeJS: 11 | 12 | ```shell 13 | git clone https://github.com/pierrec/node-lz4.git 14 | cd node-lz4 15 | git submodule update --init --recursive 16 | npm install 17 | ``` 18 | 19 | ## Install 20 | 21 | With NodeJS: 22 | 23 | ```shell 24 | npm install lz4 25 | ``` 26 | 27 | Within the browser, using `build/lz4.js`: 28 | 29 | ```html 30 | 31 | 58 | ``` 59 | 60 | 61 | From github cloning, after having made sure that node and node-gyp are properly installed: 62 | 63 | ```shell 64 | npm i 65 | node-gyp rebuild 66 | ``` 67 | 68 | See below for more LZ4 functions. 69 | 70 | 71 | ## Usage 72 | 73 | ### Encoding 74 | 75 | There are 2 ways to encode: 76 | 77 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations). 78 | * __synchronous__ by feeding the whole set of data - faster but is limited by the amount of memory 79 | 80 | 81 | #### Asynchronous encoding 82 | 83 | First, create an LZ4 encoding NodeJS stream with `LZ4#createEncoderStream(options)`. 84 | 85 | * `options` (_Object_): LZ4 stream options (optional) 86 | * `options.blockMaxSize` (_Number_): chunk size to use (default=4Mb) 87 | * `options.highCompression` (_Boolean_): use high compression (default=false) 88 | * `options.blockIndependence` (_Boolean_): (default=true) 89 | * `options.blockChecksum` (_Boolean_): add compressed blocks checksum (default=false) 90 | * `options.streamSize` (_Boolean_): add full LZ4 stream size (default=false) 91 | * `options.streamChecksum` (_Boolean_): add full LZ4 stream checksum (default=true) 92 | * `options.dict` (_Boolean_): use dictionary (default=false) 93 | * `options.dictId` (_Integer_): dictionary id (default=0) 94 | 95 | 96 | The stream can then encode any data piped to it. It will emit a `data` event on each encoded chunk, which can be saved into an output stream. 97 | 98 | The following example shows how to encode a file `test` into `test.lz4`. 99 | 100 | 101 | ```javascript 102 | var fs = require('fs') 103 | var lz4 = require('lz4') 104 | 105 | var encoder = lz4.createEncoderStream() 106 | 107 | var input = fs.createReadStream('test') 108 | var output = fs.createWriteStream('test.lz4') 109 | 110 | input.pipe(encoder).pipe(output) 111 | ``` 112 | 113 | #### Synchronous encoding 114 | 115 | Read the data into memory and feed it to `LZ4#encode(input[, options])` to decode an LZ4 stream. 116 | 117 | * `input` (_Buffer_): data to encode 118 | * `options` (_Object_): LZ4 stream options (optional) 119 | * `options.blockMaxSize` (_Number_): chunk size to use (default=4Mb) 120 | * `options.highCompression` (_Boolean_): use high compression (default=false) 121 | * `options.blockIndependence` (_Boolean_): (default=true) 122 | * `options.blockChecksum` (_Boolean_): add compressed blocks checksum (default=false) 123 | * `options.streamSize` (_Boolean_): add full LZ4 stream size (default=false) 124 | * `options.streamChecksum` (_Boolean_): add full LZ4 stream checksum (default=true) 125 | * `options.dict` (_Boolean_): use dictionary (default=false) 126 | * `options.dictId` (_Integer_): dictionary id (default=0) 127 | 128 | 129 | ```javascript 130 | var fs = require('fs') 131 | var lz4 = require('lz4') 132 | 133 | var input = fs.readFileSync('test') 134 | var output = lz4.encode(input) 135 | 136 | fs.writeFileSync('test.lz4', output) 137 | ``` 138 | 139 | 140 | ### Decoding 141 | 142 | There are 2 ways to decode: 143 | 144 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations) 145 | * __synchronous__ by feeding the whole LZ4 data - faster but is limited by the amount of memory 146 | 147 | 148 | #### Asynchronous decoding 149 | 150 | First, create an LZ4 decoding NodeJS stream with `LZ4#createDecoderStream()`. 151 | 152 | 153 | The stream can then decode any data piped to it. It will emit a `data` event on each decoded sequence, which can be saved into an output stream. 154 | 155 | The following example shows how to decode an LZ4 compressed file `test.lz4` into `test`. 156 | 157 | 158 | ```javascript 159 | var fs = require('fs') 160 | var lz4 = require('lz4') 161 | 162 | var decoder = lz4.createDecoderStream() 163 | 164 | var input = fs.createReadStream('test.lz4') 165 | var output = fs.createWriteStream('test') 166 | 167 | input.pipe(decoder).pipe(output) 168 | ``` 169 | 170 | #### Synchronous decoding 171 | 172 | Read the data into memory and feed it to `LZ4#decode(input)` to produce an LZ4 stream. 173 | 174 | * `input` (_Buffer_): data to decode 175 | 176 | 177 | ```javascript 178 | var fs = require('fs') 179 | var lz4 = require('lz4') 180 | 181 | var input = fs.readFileSync('test.lz4') 182 | var output = lz4.decode(input) 183 | 184 | fs.writeFileSync('test', output) 185 | ``` 186 | 187 | ## Block level encoding/decoding 188 | 189 | In some cases, it is useful to be able to manipulate an LZ4 block instead of an LZ4 stream. The functions to decode and encode are therefore exposed as: 190 | 191 | * `LZ4#decodeBlock(input, output[, startIdx, endIdx])` (_Number_) >=0: uncompressed size, <0: error at offset 192 | * `input` (_Buffer_): data block to decode 193 | * `output` (_Buffer_): decoded data block 194 | * `startIdx` (_Number_): input buffer start index (optional, default=0) 195 | * `endIdx` (_Number_): input buffer end index (optional, default=startIdx + input.length) 196 | * `LZ4#encodeBound(inputSize)` (_Number_): maximum size for a compressed block 197 | * `inputSize` (_Number_) size of the input, 0 if too large 198 | This is required to size the buffer for a block encoded data 199 | * `LZ4#encodeBlock(input, output[, startIdx, endIdx])` (_Number_) >0: compressed size, =0: not compressible 200 | * `input` (_Buffer_): data block to encode 201 | * `output` (_Buffer_): encoded data block 202 | * `startIdx` (_Number_): output buffer start index (optional, default=0) 203 | * `endIdx` (_Number_): output buffer end index (optional, default=startIdx + output.length) 204 | * `LZ4#encodeBlockHC(input, output[, compressionLevel])` (_Number_) >0: compressed size, =0: not compressible 205 | * `input` (_Buffer_): data block to encode with high compression 206 | * `output` (_Buffer_): encoded data block 207 | * `compressionLevel` (_Number_): compression level between 3 and 12 (optional, default=9) 208 | 209 | 210 | Blocks do not have any magic number and are provided as is. It is useful to store somewhere the size of the original input for decoding. 211 | LZ4#encodeBlockHC() is not available as pure Javascript. 212 | 213 | 214 | ## How it works 215 | 216 | * [LZ4 stream format](http://fastcompression.blogspot.fr/2011/05/lz4-explained.html) 217 | 218 | ## Restrictions / Issues 219 | 220 | * `blockIndependence` property only supported for `true` 221 | 222 | 223 | ## License 224 | 225 | MIT 226 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | * LZ4 stream dictionary 2 | * NodeJS streams updates 3 | * dependent blocks compression -------------------------------------------------------------------------------- /benchmark/bench.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var Benchmark = require('benchmark') 4 | var lz4 = require('..') 5 | var lz4js = require('../lib/binding') 6 | 7 | var inputFileName = path.normalize( process.argv[2] || __dirname + '/../data/lorem_1mb.txt' ) 8 | console.log('Input file:', inputFileName) 9 | 10 | var input = fs.readFileSync(inputFileName) 11 | var outputMaxSize = lz4.encodeBound(input.length) 12 | var output = Buffer.alloc(outputMaxSize) 13 | 14 | var decoded = Buffer.alloc(input.length) 15 | var encoded = Buffer.alloc(outputMaxSize) 16 | var n = lz4.encodeBlock(input, encoded) 17 | encoded = encoded.slice(0, n) 18 | 19 | console.log('Input size:', input.length) 20 | console.log('Output size:', encoded.length) 21 | 22 | var suite = new Benchmark.Suite 23 | suite 24 | .add('lz4.encodeBlock native', function() { 25 | lz4.encodeBlock(input, output) 26 | }) 27 | .add('lz4.decodeBlock native', function() { 28 | lz4.decodeBlock(encoded, decoded) 29 | }) 30 | .add('lz4.encodeBlock JS', function() { 31 | lz4js.compress(input, output) 32 | }) 33 | .add('lz4.decodeBlock JS', function() { 34 | lz4js.uncompress(encoded, decoded) 35 | }) 36 | // add listeners 37 | .on('cycle', function(event) { 38 | console.log( String(event.target) ) 39 | }) 40 | .run() -------------------------------------------------------------------------------- /bin/lz4c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierrec/node-lz4/943e768691a9fb29e2d9a88f9942463765a45468/bin/lz4c -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'xxhash', 5 | 'cflags!': [ '-fno-exceptions' ], 6 | 'cflags_cc!': [ '-fno-exceptions' ], 7 | 'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', 8 | 'CLANG_CXX_LIBRARY': 'libc++', 9 | 'MACOSX_DEPLOYMENT_TARGET': '10.7', 10 | }, 11 | 'msvs_settings': { 12 | 'VCCLCompilerTool': { 'ExceptionHandling': 1 }, 13 | }, 14 | 'sources': [ 15 | 'lib/binding/xxhash_binding.cc', 16 | 'deps/lz4/lib/xxhash.h', 17 | 'deps/lz4/lib/xxhash.c', 18 | ], 19 | 'include_dirs': [ 20 | '" 7 | ], 8 | "description": "LZ4 streaming compression and decompression", 9 | "main": "build/lz4.js", 10 | "moduleType": [ 11 | "node" 12 | ], 13 | "keywords": [ 14 | "lz4", 15 | "compression", 16 | "decompression", 17 | "stream" 18 | ], 19 | "license": "MIT", 20 | "ignore": [ 21 | "**/.*", 22 | "node_modules", 23 | "bower_components", 24 | "test", 25 | "tests" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | browserify -r ./lib/utils-js.js:./utils -r buffer -r xxhashjs -r ./lib/lz4l.js:lz4 -o build/lz4.js lib/lz4l.js && \ 4 | minify build/lz4.js > build/lz4.min.js 5 | 6 | -------------------------------------------------------------------------------- /data/sphere.dae: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | alorino 6 | Maya 7.0 | ColladaMaya v2.01 Jun 9 2006 at 16:08:19 | FCollada v1.11 7 | Collada Maya Export Options: bakeTransforms=0;exportPolygonMeshes=1;bakeLighting=0;isSampling=0; 8 | curveConstrainSampling=0;exportCameraAsLookat=0; 9 | exportLights=1;exportCameras=1;exportJointsAndSkin=1; 10 | exportAnimations=1;exportTriangles=0;exportInvisibleNodes=0; 11 | exportNormals=1;exportTexCoords=1;exportVertexColors=1;exportTangents=0; 12 | exportTexTangents=0;exportConstraints=0;exportPhysics=0;exportXRefs=1; 13 | dereferenceXRefs=0;cameraXFov=0;cameraYFov=1 14 | 15 | Copyright 2006 Sony Computer Entertainment Inc. 16 | Licensed under the SCEA Shared Source License, Version 1.0 (the 17 | "License"); you may not use this file except in compliance with the 18 | License. You may obtain a copy of the License at: 19 | http://research.scea.com/scea_shared_source_license.html 20 | Unless required by applicable law or agreed to in writing, software 21 | distributed under the License is distributed on an "AS IS" BASIS, 22 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 | See the License for the specific language governing permissions and 24 | limitations under the License. 25 | 26 | 27 | 2006-06-23T18:26:06Z 28 | 2006-06-23T18:26:06Z 29 | 30 | Y_UP 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 0 0 0 1 44 | 45 | 46 | 0 0 0 1 47 | 48 | 49 | 0.5 0.5 0.5 1 50 | 51 | 52 | 1 1 1 1 53 | 54 | 55 | 1 56 | 57 | 58 | 0 0 0 1 59 | 60 | 61 | 1 62 | 63 | 64 | 0 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 0.148778 -0.987688 -0.048341 0.126558 -0.987688 -0.09195 0.09195 -0.987688 -0.126558 0.048341 -0.987688 -0.148778 0 -0.987688 -0.156435 -0.048341 -0.987688 -0.148778 -0.09195 -0.987688 -0.126558 -0.126558 -0.987688 -0.09195 -0.148778 -0.987688 -0.048341 -0.156435 -0.987688 0 -0.148778 -0.987688 0.048341 -0.126558 -0.987688 0.09195 -0.09195 -0.987688 0.126558 -0.048341 -0.987688 0.148778 0 -0.987688 0.156434 0.048341 -0.987688 0.148778 0.09195 -0.987688 0.126558 0.126558 -0.987688 0.09195 0.148778 -0.987688 0.048341 0.156434 -0.987688 0 0.293893 -0.951057 -0.095492 0.25 -0.951057 -0.181636 0.181636 -0.951057 -0.25 0.095492 -0.951057 -0.293893 0 -0.951057 -0.309017 -0.095492 -0.951057 -0.293893 -0.181636 -0.951057 -0.25 -0.25 -0.951057 -0.181636 -0.293893 -0.951057 -0.095492 -0.309017 -0.951057 0 -0.293893 -0.951057 0.095492 -0.25 -0.951057 0.181636 -0.181636 -0.951057 0.25 -0.095492 -0.951057 0.293893 0 -0.951057 0.309017 0.095492 -0.951057 0.293893 0.181636 -0.951057 0.25 0.25 -0.951057 0.181636 0.293893 -0.951057 0.095492 0.309017 -0.951057 0 0.431771 -0.891007 -0.140291 0.367286 -0.891007 -0.266849 0.266849 -0.891007 -0.367286 0.140291 -0.891007 -0.431771 0 -0.891007 -0.453991 -0.140291 -0.891007 -0.431771 -0.266849 -0.891007 -0.367286 -0.367286 -0.891007 -0.266849 -0.431771 -0.891007 -0.140291 -0.453991 -0.891007 0 -0.431771 -0.891007 0.140291 -0.367286 -0.891007 0.266849 -0.266849 -0.891007 0.367286 -0.140291 -0.891007 0.431771 0 -0.891007 0.453991 0.140291 -0.891007 0.431771 0.266849 -0.891007 0.367286 0.367286 -0.891007 0.266849 0.431771 -0.891007 0.140291 0.453991 -0.891007 0 0.559017 -0.809017 -0.181636 0.475528 -0.809017 -0.345492 0.345492 -0.809017 -0.475528 0.181636 -0.809017 -0.559017 0 -0.809017 -0.587785 -0.181636 -0.809017 -0.559017 -0.345492 -0.809017 -0.475528 -0.475528 -0.809017 -0.345492 -0.559017 -0.809017 -0.181636 -0.587785 -0.809017 0 -0.559017 -0.809017 0.181636 -0.475528 -0.809017 0.345492 -0.345492 -0.809017 0.475528 -0.181636 -0.809017 0.559017 0 -0.809017 0.587785 0.181636 -0.809017 0.559017 0.345492 -0.809017 0.475528 0.475528 -0.809017 0.345492 0.559017 -0.809017 0.181636 0.587785 -0.809017 0 0.672499 -0.707107 -0.218508 0.572062 -0.707107 -0.415627 0.415627 -0.707107 -0.572062 0.218508 -0.707107 -0.672499 0 -0.707107 -0.707107 -0.218508 -0.707107 -0.672499 -0.415627 -0.707107 -0.572062 -0.572062 -0.707107 -0.415627 -0.672499 -0.707107 -0.218508 -0.707107 -0.707107 0 -0.672499 -0.707107 0.218508 -0.572062 -0.707107 0.415627 -0.415627 -0.707107 0.572061 -0.218508 -0.707107 0.672499 0 -0.707107 0.707107 0.218508 -0.707107 0.672499 0.415627 -0.707107 0.572061 0.572061 -0.707107 0.415627 0.672499 -0.707107 0.218508 0.707107 -0.707107 0 0.769421 -0.587785 -0.25 0.654509 -0.587785 -0.475529 0.475528 -0.587785 -0.654509 0.25 -0.587785 -0.769421 0 -0.587785 -0.809017 -0.25 -0.587785 -0.769421 -0.475528 -0.587785 -0.654509 -0.654509 -0.587785 -0.475528 -0.769421 -0.587785 -0.25 -0.809017 -0.587785 0 -0.769421 -0.587785 0.25 -0.654509 -0.587785 0.475528 -0.475528 -0.587785 0.654509 -0.25 -0.587785 0.769421 0 -0.587785 0.809017 0.25 -0.587785 0.769421 0.475528 -0.587785 0.654509 0.654509 -0.587785 0.475528 0.769421 -0.587785 0.25 0.809017 -0.587785 0 0.847398 -0.453991 -0.275336 0.72084 -0.453991 -0.523721 0.523721 -0.453991 -0.72084 0.275336 -0.453991 -0.847398 0 -0.453991 -0.891007 -0.275336 -0.453991 -0.847398 -0.523721 -0.453991 -0.72084 -0.72084 -0.453991 -0.523721 -0.847398 -0.453991 -0.275336 -0.891007 -0.453991 0 -0.847398 -0.453991 0.275336 -0.72084 -0.453991 0.523721 -0.523721 -0.453991 0.72084 -0.275336 -0.453991 0.847398 0 -0.453991 0.891007 0.275336 -0.453991 0.847398 0.523721 -0.453991 0.72084 0.72084 -0.453991 0.523721 0.847398 -0.453991 0.275336 0.891007 -0.453991 0 0.904509 -0.309017 -0.293893 0.769421 -0.309017 -0.559017 0.559017 -0.309017 -0.769421 0.293893 -0.309017 -0.904509 0 -0.309017 -0.951057 -0.293893 -0.309017 -0.904509 -0.559017 -0.309017 -0.769421 -0.769421 -0.309017 -0.559017 -0.904509 -0.309017 -0.293893 -0.951057 -0.309017 0 -0.904509 -0.309017 0.293893 -0.769421 -0.309017 0.559017 -0.559017 -0.309017 0.769421 -0.293893 -0.309017 0.904509 0 -0.309017 0.951057 0.293893 -0.309017 0.904509 0.559017 -0.309017 0.769421 0.769421 -0.309017 0.559017 0.904509 -0.309017 0.293893 0.951057 -0.309017 0 0.939348 -0.156434 -0.305213 0.799057 -0.156434 -0.580549 0.580549 -0.156434 -0.799057 0.305213 -0.156434 -0.939348 0 -0.156434 -0.987689 -0.305213 -0.156434 -0.939348 -0.580549 -0.156434 -0.799057 -0.799057 -0.156434 -0.580549 -0.939348 -0.156434 -0.305213 -0.987689 -0.156434 0 -0.939348 -0.156434 0.305213 -0.799057 -0.156434 0.580549 -0.580549 -0.156434 0.799057 -0.305213 -0.156434 0.939348 0 -0.156434 0.987688 0.305213 -0.156434 0.939348 0.580549 -0.156434 0.799057 0.799057 -0.156434 0.580549 0.939348 -0.156434 0.305212 0.987688 -0.156434 0 0.951057 0 -0.309017 0.809017 0 -0.587786 0.587785 0 -0.809017 0.309017 0 -0.951057 0 0 -1 -0.309017 0 -0.951057 -0.587785 0 -0.809017 -0.809017 0 -0.587785 -0.951057 0 -0.309017 -1 0 0 -0.951057 0 0.309017 -0.809017 0 0.587785 -0.587785 0 0.809017 -0.309017 0 0.951057 0 0 1 0.309017 0 0.951057 0.587785 0 0.809017 0.809017 0 0.587785 0.951057 0 0.309017 1 0 0 0.939348 0.156434 -0.305213 0.799057 0.156434 -0.580549 0.580549 0.156434 -0.799057 0.305213 0.156434 -0.939348 0 0.156434 -0.987689 -0.305213 0.156434 -0.939348 -0.580549 0.156434 -0.799057 -0.799057 0.156434 -0.580549 -0.939348 0.156434 -0.305213 -0.987689 0.156434 0 -0.939348 0.156434 0.305213 -0.799057 0.156434 0.580549 -0.580549 0.156434 0.799057 -0.305213 0.156434 0.939348 0 0.156434 0.987688 0.305213 0.156434 0.939348 0.580549 0.156434 0.799057 0.799057 0.156434 0.580549 0.939348 0.156434 0.305212 0.987688 0.156434 0 0.904509 0.309017 -0.293893 0.769421 0.309017 -0.559017 0.559017 0.309017 -0.769421 0.293893 0.309017 -0.904509 0 0.309017 -0.951057 -0.293893 0.309017 -0.904509 -0.559017 0.309017 -0.769421 -0.769421 0.309017 -0.559017 -0.904509 0.309017 -0.293893 -0.951057 0.309017 0 -0.904509 0.309017 0.293893 -0.769421 0.309017 0.559017 -0.559017 0.309017 0.769421 -0.293893 0.309017 0.904509 0 0.309017 0.951057 0.293893 0.309017 0.904509 0.559017 0.309017 0.769421 0.769421 0.309017 0.559017 0.904509 0.309017 0.293893 0.951057 0.309017 0 0.847398 0.453991 -0.275336 0.72084 0.453991 -0.523721 0.523721 0.453991 -0.72084 0.275336 0.453991 -0.847398 0 0.453991 -0.891007 -0.275336 0.453991 -0.847398 -0.523721 0.453991 -0.72084 -0.72084 0.453991 -0.523721 -0.847398 0.453991 -0.275336 -0.891007 0.453991 0 -0.847398 0.453991 0.275336 -0.72084 0.453991 0.523721 -0.523721 0.453991 0.72084 -0.275336 0.453991 0.847398 0 0.453991 0.891007 0.275336 0.453991 0.847398 0.523721 0.453991 0.72084 0.72084 0.453991 0.523721 0.847398 0.453991 0.275336 0.891007 0.453991 0 0.769421 0.587785 -0.25 0.654509 0.587785 -0.475529 0.475528 0.587785 -0.654509 0.25 0.587785 -0.769421 0 0.587785 -0.809017 -0.25 0.587785 -0.769421 -0.475528 0.587785 -0.654509 -0.654509 0.587785 -0.475528 -0.769421 0.587785 -0.25 -0.809017 0.587785 0 -0.769421 0.587785 0.25 -0.654509 0.587785 0.475528 -0.475528 0.587785 0.654509 -0.25 0.587785 0.769421 0 0.587785 0.809017 0.25 0.587785 0.769421 0.475528 0.587785 0.654509 0.654509 0.587785 0.475528 0.769421 0.587785 0.25 0.809017 0.587785 0 0.672499 0.707107 -0.218508 0.572062 0.707107 -0.415627 0.415627 0.707107 -0.572062 0.218508 0.707107 -0.672499 0 0.707107 -0.707107 -0.218508 0.707107 -0.672499 -0.415627 0.707107 -0.572062 -0.572062 0.707107 -0.415627 -0.672499 0.707107 -0.218508 -0.707107 0.707107 0 -0.672499 0.707107 0.218508 -0.572062 0.707107 0.415627 -0.415627 0.707107 0.572061 -0.218508 0.707107 0.672499 0 0.707107 0.707107 0.218508 0.707107 0.672499 0.415627 0.707107 0.572061 0.572061 0.707107 0.415627 0.672499 0.707107 0.218508 0.707107 0.707107 0 0.559017 0.809017 -0.181636 0.475528 0.809017 -0.345492 0.345492 0.809017 -0.475528 0.181636 0.809017 -0.559017 0 0.809017 -0.587785 -0.181636 0.809017 -0.559017 -0.345492 0.809017 -0.475528 -0.475528 0.809017 -0.345492 -0.559017 0.809017 -0.181636 -0.587785 0.809017 0 -0.559017 0.809017 0.181636 -0.475528 0.809017 0.345492 -0.345492 0.809017 0.475528 -0.181636 0.809017 0.559017 0 0.809017 0.587785 0.181636 0.809017 0.559017 0.345492 0.809017 0.475528 0.475528 0.809017 0.345492 0.559017 0.809017 0.181636 0.587785 0.809017 0 0.431771 0.891007 -0.140291 0.367286 0.891007 -0.266849 0.266849 0.891007 -0.367286 0.140291 0.891007 -0.431771 0 0.891007 -0.453991 -0.140291 0.891007 -0.431771 -0.266849 0.891007 -0.367286 -0.367286 0.891007 -0.266849 -0.431771 0.891007 -0.140291 -0.453991 0.891007 0 -0.431771 0.891007 0.140291 -0.367286 0.891007 0.266849 -0.266849 0.891007 0.367286 -0.140291 0.891007 0.431771 0 0.891007 0.453991 0.140291 0.891007 0.431771 0.266849 0.891007 0.367286 0.367286 0.891007 0.266849 0.431771 0.891007 0.140291 0.453991 0.891007 0 0.293893 0.951057 -0.095492 0.25 0.951057 -0.181636 0.181636 0.951057 -0.25 0.095492 0.951057 -0.293893 0 0.951057 -0.309017 -0.095492 0.951057 -0.293893 -0.181636 0.951057 -0.25 -0.25 0.951057 -0.181636 -0.293893 0.951057 -0.095492 -0.309017 0.951057 0 -0.293893 0.951057 0.095492 -0.25 0.951057 0.181636 -0.181636 0.951057 0.25 -0.095492 0.951057 0.293893 0 0.951057 0.309017 0.095492 0.951057 0.293893 0.181636 0.951057 0.25 0.25 0.951057 0.181636 0.293893 0.951057 0.095492 0.309017 0.951057 0 0.148778 0.987688 -0.048341 0.126558 0.987688 -0.09195 0.09195 0.987688 -0.126558 0.048341 0.987688 -0.148778 0 0.987688 -0.156435 -0.048341 0.987688 -0.148778 -0.09195 0.987688 -0.126558 -0.126558 0.987688 -0.09195 -0.148778 0.987688 -0.048341 -0.156435 0.987688 0 -0.148778 0.987688 0.048341 -0.126558 0.987688 0.09195 -0.09195 0.987688 0.126558 -0.048341 0.987688 0.148778 0 0.987688 0.156434 0.048341 0.987688 0.148778 0.09195 0.987688 0.126558 0.126558 0.987688 0.09195 0.148778 0.987688 0.048341 0.156434 0.987688 0 0 -1 0 0 1 0 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 0.148756 -0.987692 -0.048334 0.126539 -0.987692 -0.091936 0.091936 -0.987692 -0.126539 0.048334 -0.987692 -0.148755 0 -0.987692 -0.156411 -0.048334 -0.987692 -0.148755 -0.091936 -0.987692 -0.126538 -0.126539 -0.987692 -0.091935 -0.148756 -0.987692 -0.048334 -0.156411 -0.987692 -1e-006 -0.148755 -0.987692 0.048334 -0.126539 -0.987692 0.091936 -0.091936 -0.987692 0.126539 -0.048334 -0.987692 0.148755 0 -0.987692 0.156411 0.048334 -0.987692 0.148755 0.091936 -0.987692 0.126538 0.126539 -0.987692 0.091936 0.148756 -0.987692 0.048334 0.156411 -0.987692 1e-006 0.293852 -0.951071 -0.095478 0.249965 -0.95107 -0.18161 0.18161 -0.95107 -0.249965 0.095478 -0.95107 -0.293852 0 -0.95107 -0.308974 -0.095478 -0.951071 -0.293852 -0.18161 -0.951071 -0.249965 -0.249965 -0.951071 -0.18161 -0.293852 -0.951071 -0.095478 -0.308974 -0.951071 0 -0.293852 -0.95107 0.095479 -0.249965 -0.95107 0.181611 -0.18161 -0.95107 0.249965 -0.095478 -0.951071 0.293852 0 -0.95107 0.308974 0.095478 -0.951071 0.293852 0.18161 -0.95107 0.249965 0.249965 -0.95107 0.181611 0.293852 -0.95107 0.095479 0.308974 -0.95107 0 0.431718 -0.891035 -0.140273 0.367241 -0.891035 -0.266816 0.266816 -0.891035 -0.367241 0.140274 -0.891035 -0.431718 0 -0.891035 -0.453935 -0.140274 -0.891035 -0.431718 -0.266816 -0.891035 -0.367241 -0.367241 -0.891035 -0.266816 -0.431718 -0.891035 -0.140274 -0.453935 -0.891035 0 -0.431718 -0.891035 0.140274 -0.367241 -0.891035 0.266817 -0.266816 -0.891035 0.367241 -0.140274 -0.891035 0.431718 0 -0.891035 0.453935 0.140274 -0.891035 0.431718 0.266816 -0.891035 0.367241 0.367241 -0.891035 0.266816 0.431718 -0.891035 0.140274 0.453935 -0.891035 0 0.558961 -0.80906 -0.181617 0.475481 -0.80906 -0.345457 0.345457 -0.80906 -0.47548 0.181617 -0.80906 -0.558961 0 -0.80906 -0.587726 -0.181617 -0.80906 -0.558961 -0.345457 -0.80906 -0.475481 -0.475481 -0.80906 -0.345457 -0.558961 -0.80906 -0.181617 -0.587726 -0.80906 0 -0.558961 -0.80906 0.181617 -0.47548 -0.80906 0.345457 -0.345457 -0.80906 0.475481 -0.181617 -0.80906 0.558961 0 -0.80906 0.587726 0.181617 -0.80906 0.558961 0.345457 -0.80906 0.475481 0.475481 -0.80906 0.345457 0.558961 -0.80906 0.181617 0.587726 -0.80906 0 0.672447 -0.707161 -0.218491 0.572018 -0.707161 -0.415595 0.415595 -0.707161 -0.572018 0.218491 -0.707161 -0.672447 0 -0.707161 -0.707053 -0.218491 -0.707161 -0.672447 -0.415595 -0.707161 -0.572018 -0.572018 -0.707161 -0.415595 -0.672447 -0.707161 -0.218491 -0.707053 -0.707161 0 -0.672447 -0.707161 0.218491 -0.572018 -0.707161 0.415595 -0.415595 -0.707161 0.572018 -0.218491 -0.707161 0.672447 0 -0.707161 0.707053 0.218491 -0.707161 0.672447 0.415595 -0.707161 0.572018 0.572018 -0.707161 0.415595 0.672447 -0.707161 0.218491 0.707053 -0.707161 1e-006 0.76938 -0.587844 -0.249986 0.654474 -0.587844 -0.475503 0.475503 -0.587844 -0.654474 0.249987 -0.587844 -0.76938 0 -0.587844 -0.808974 -0.249987 -0.587844 -0.76938 -0.475503 -0.587844 -0.654474 -0.654474 -0.587844 -0.475503 -0.76938 -0.587844 -0.249987 -0.808974 -0.587844 0 -0.76938 -0.587844 0.249987 -0.654474 -0.587844 0.475503 -0.475503 -0.587844 0.654474 -0.249987 -0.587844 0.76938 0 -0.587844 0.808974 0.249987 -0.587844 0.76938 0.475503 -0.587844 0.654474 0.654474 -0.587844 0.475503 0.76938 -0.587844 0.249987 0.808974 -0.587844 1e-006 0.847371 -0.454045 -0.275327 0.720817 -0.454045 -0.523704 0.523704 -0.454045 -0.720817 0.275327 -0.454045 -0.847371 0 -0.454045 -0.890979 -0.275328 -0.454045 -0.847371 -0.523704 -0.454045 -0.720817 -0.720817 -0.454045 -0.523704 -0.847371 -0.454045 -0.275327 -0.890979 -0.454045 0 -0.847371 -0.454045 0.275328 -0.720817 -0.454045 0.523704 -0.523704 -0.454045 0.720817 -0.275327 -0.454045 0.847371 0 -0.454045 0.890979 0.275328 -0.454045 0.847371 0.523704 -0.454045 0.720817 0.720817 -0.454045 0.523704 0.847371 -0.454045 0.275327 0.890979 -0.454045 1e-006 0.904496 -0.309059 -0.293888 0.76941 -0.309059 -0.559009 0.559009 -0.309059 -0.76941 0.293888 -0.309059 -0.904496 0 -0.309059 -0.951043 -0.293889 -0.309059 -0.904495 -0.559009 -0.309059 -0.76941 -0.76941 -0.309059 -0.559009 -0.904495 -0.309059 -0.293888 -0.951043 -0.309059 0 -0.904495 -0.309059 0.293888 -0.76941 -0.309059 0.559009 -0.559009 -0.309059 0.76941 -0.293888 -0.309059 0.904495 0 -0.309059 0.951043 0.293888 -0.309059 0.904495 0.559009 -0.309059 0.76941 0.76941 -0.309059 0.559009 0.904495 -0.309059 0.293888 0.951043 -0.309059 1e-006 0.939344 -0.156457 -0.305211 0.799054 -0.156457 -0.580547 0.580546 -0.156457 -0.799054 0.305211 -0.156457 -0.939344 0 -0.156457 -0.987685 -0.305212 -0.156457 -0.939344 -0.580547 -0.156457 -0.799054 -0.799054 -0.156457 -0.580546 -0.939344 -0.156457 -0.305211 -0.987685 -0.156457 0 -0.939344 -0.156457 0.305211 -0.799054 -0.156457 0.580547 -0.580546 -0.156457 0.799054 -0.305211 -0.156457 0.939344 0 -0.156457 0.987685 0.305211 -0.156457 0.939344 0.580547 -0.156457 0.799054 0.799054 -0.156457 0.580546 0.939344 -0.156457 0.305211 0.987685 -0.156457 1e-006 0.951057 0 -0.309016 0.809017 0 -0.587785 0.587785 0 -0.809017 0.309017 0 -0.951057 0 0 -1 -0.309017 0 -0.951056 -0.587785 0 -0.809017 -0.809017 0 -0.587785 -0.951057 0 -0.309017 -1 0 0 -0.951056 0 0.309017 -0.809017 0 0.587785 -0.587785 0 0.809017 -0.309017 0 0.951057 0 0 1 0.309017 0 0.951056 0.587785 0 0.809017 0.809017 0 0.587785 0.951057 0 0.309017 1 0 1e-006 0.939344 0.156457 -0.305211 0.799054 0.156457 -0.580547 0.580546 0.156457 -0.799054 0.305211 0.156457 -0.939344 0 0.156457 -0.987685 -0.305212 0.156457 -0.939344 -0.580547 0.156457 -0.799054 -0.799054 0.156457 -0.580546 -0.939344 0.156457 -0.305211 -0.987685 0.156457 0 -0.939344 0.156457 0.305211 -0.799054 0.156457 0.580547 -0.580546 0.156457 0.799054 -0.305211 0.156457 0.939344 0 0.156457 0.987685 0.305211 0.156457 0.939344 0.580547 0.156457 0.799054 0.799054 0.156457 0.580546 0.939344 0.156457 0.305211 0.987685 0.156457 1e-006 0.904496 0.309059 -0.293888 0.76941 0.309059 -0.559009 0.559009 0.309059 -0.76941 0.293888 0.309059 -0.904496 0 0.309059 -0.951043 -0.293889 0.309059 -0.904495 -0.559009 0.309059 -0.76941 -0.76941 0.309059 -0.559009 -0.904495 0.309059 -0.293888 -0.951043 0.309059 0 -0.904495 0.309059 0.293888 -0.76941 0.309059 0.559009 -0.559009 0.309059 0.76941 -0.293888 0.309059 0.904495 0 0.309059 0.951043 0.293888 0.309059 0.904495 0.559009 0.309059 0.76941 0.76941 0.309059 0.559009 0.904495 0.309059 0.293888 0.951043 0.309059 1e-006 0.847371 0.454045 -0.275327 0.720817 0.454045 -0.523704 0.523704 0.454045 -0.720817 0.275327 0.454045 -0.847371 0 0.454045 -0.890979 -0.275328 0.454045 -0.847371 -0.523704 0.454045 -0.720817 -0.720817 0.454045 -0.523704 -0.847371 0.454045 -0.275327 -0.890979 0.454045 0 -0.847371 0.454045 0.275328 -0.720817 0.454045 0.523704 -0.523704 0.454045 0.720817 -0.275327 0.454045 0.847371 0 0.454045 0.890979 0.275328 0.454045 0.847371 0.523704 0.454045 0.720817 0.720817 0.454045 0.523704 0.847371 0.454045 0.275327 0.890979 0.454045 1e-006 0.76938 0.587844 -0.249986 0.654474 0.587844 -0.475503 0.475503 0.587844 -0.654474 0.249987 0.587844 -0.76938 0 0.587844 -0.808974 -0.249987 0.587844 -0.76938 -0.475503 0.587844 -0.654474 -0.654474 0.587844 -0.475503 -0.76938 0.587844 -0.249987 -0.808974 0.587844 0 -0.76938 0.587844 0.249987 -0.654474 0.587844 0.475503 -0.475503 0.587844 0.654474 -0.249987 0.587844 0.76938 0 0.587844 0.808974 0.249987 0.587844 0.76938 0.475503 0.587844 0.654474 0.654474 0.587844 0.475503 0.76938 0.587844 0.249987 0.808974 0.587844 1e-006 0.672447 0.707161 -0.218491 0.572018 0.707161 -0.415595 0.415595 0.707161 -0.572018 0.218491 0.707161 -0.672447 0 0.707161 -0.707053 -0.218491 0.707161 -0.672447 -0.415595 0.707161 -0.572018 -0.572018 0.707161 -0.415595 -0.672447 0.707161 -0.218491 -0.707053 0.707161 0 -0.672447 0.707161 0.218491 -0.572018 0.707161 0.415595 -0.415595 0.707161 0.572018 -0.218491 0.707161 0.672447 0 0.707161 0.707053 0.218491 0.707161 0.672447 0.415595 0.707161 0.572018 0.572018 0.707161 0.415595 0.672447 0.707161 0.218491 0.707053 0.707161 0 0.558961 0.80906 -0.181617 0.475481 0.80906 -0.345457 0.345457 0.80906 -0.475481 0.181617 0.80906 -0.558961 0 0.80906 -0.587726 -0.181617 0.80906 -0.558961 -0.345457 0.80906 -0.475481 -0.475481 0.80906 -0.345457 -0.558961 0.80906 -0.181617 -0.587726 0.80906 0 -0.558961 0.80906 0.181617 -0.475481 0.80906 0.345457 -0.345457 0.80906 0.475481 -0.181617 0.80906 0.558961 0 0.80906 0.587726 0.181617 0.80906 0.558961 0.345457 0.80906 0.475481 0.475481 0.80906 0.345457 0.558961 0.80906 0.181617 0.587726 0.80906 1e-006 0.431718 0.891035 -0.140273 0.367241 0.891035 -0.266816 0.266816 0.891035 -0.367241 0.140274 0.891035 -0.431718 0 0.891035 -0.453935 -0.140274 0.891035 -0.431718 -0.266816 0.891035 -0.367241 -0.367241 0.891035 -0.266816 -0.431718 0.891035 -0.140274 -0.453935 0.891035 0 -0.431718 0.891035 0.140274 -0.367241 0.891035 0.266817 -0.266816 0.891035 0.367241 -0.140274 0.891035 0.431718 0 0.891035 0.453935 0.140274 0.891035 0.431718 0.266816 0.891035 0.367241 0.367241 0.891035 0.266816 0.431718 0.891035 0.140274 0.453935 0.891035 0 0.293852 0.951071 -0.095478 0.249965 0.951071 -0.18161 0.18161 0.951071 -0.249965 0.095478 0.951071 -0.293852 0 0.951071 -0.308974 -0.095478 0.951071 -0.293852 -0.18161 0.951071 -0.249965 -0.249965 0.95107 -0.18161 -0.293852 0.951071 -0.095478 -0.308974 0.951071 0 -0.293852 0.951071 0.095478 -0.249965 0.951071 0.18161 -0.18161 0.95107 0.249965 -0.095478 0.951071 0.293852 0 0.951071 0.308974 0.095478 0.95107 0.293852 0.18161 0.95107 0.249965 0.249965 0.95107 0.18161 0.293852 0.951071 0.095478 0.308974 0.95107 0 0.148756 0.987692 -0.048334 0.126539 0.987692 -0.091935 0.091936 0.987692 -0.126538 0.048334 0.987692 -0.148755 0 0.987692 -0.156411 -0.048334 0.987692 -0.148755 -0.091936 0.987692 -0.126539 -0.126539 0.987692 -0.091936 -0.148756 0.987692 -0.048333 -0.156411 0.987692 1e-006 -0.148756 0.987692 0.048334 -0.126539 0.987692 0.091935 -0.091936 0.987692 0.126538 -0.048334 0.987692 0.148755 0 0.987692 0.156411 0.048334 0.987692 0.148755 0.091936 0.987692 0.126539 0.126539 0.987692 0.091936 0.148756 0.987692 0.048333 0.156411 0.987692 -1e-006 0 -1 0 0 1 0 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 0 0.05 0.05 0.05 0.1 0.05 0.15 0.05 0.2 0.05 0.25 0.05 0.3 0.05 0.35 0.05 0.4 0.05 0.45 0.05 0.5 0.05 0.55 0.05 0.6 0.05 0.65 0.05 0.7 0.05 0.75 0.05 0.8 0.05 0.85 0.05 0.9 0.05 0.95 0.05 1 0.05 0 0.1 0.05 0.1 0.1 0.1 0.15 0.1 0.2 0.1 0.25 0.1 0.3 0.1 0.35 0.1 0.4 0.1 0.45 0.1 0.5 0.1 0.55 0.1 0.6 0.1 0.65 0.1 0.7 0.1 0.75 0.1 0.8 0.1 0.85 0.1 0.9 0.1 0.95 0.1 1 0.1 0 0.15 0.05 0.15 0.1 0.15 0.15 0.15 0.2 0.15 0.25 0.15 0.3 0.15 0.35 0.15 0.4 0.15 0.45 0.15 0.5 0.15 0.55 0.15 0.6 0.15 0.65 0.15 0.7 0.15 0.75 0.15 0.8 0.15 0.85 0.15 0.9 0.15 0.95 0.15 1 0.15 0 0.2 0.05 0.2 0.1 0.2 0.15 0.2 0.2 0.2 0.25 0.2 0.3 0.2 0.35 0.2 0.4 0.2 0.45 0.2 0.5 0.2 0.55 0.2 0.6 0.2 0.65 0.2 0.7 0.2 0.75 0.2 0.8 0.2 0.85 0.2 0.9 0.2 0.95 0.2 1 0.2 0 0.25 0.05 0.25 0.1 0.25 0.15 0.25 0.2 0.25 0.25 0.25 0.3 0.25 0.35 0.25 0.4 0.25 0.45 0.25 0.5 0.25 0.55 0.25 0.6 0.25 0.65 0.25 0.7 0.25 0.75 0.25 0.8 0.25 0.85 0.25 0.9 0.25 0.95 0.25 1 0.25 0 0.3 0.05 0.3 0.1 0.3 0.15 0.3 0.2 0.3 0.25 0.3 0.3 0.3 0.35 0.3 0.4 0.3 0.45 0.3 0.5 0.3 0.55 0.3 0.6 0.3 0.65 0.3 0.7 0.3 0.75 0.3 0.8 0.3 0.85 0.3 0.9 0.3 0.95 0.3 1 0.3 0 0.35 0.05 0.35 0.1 0.35 0.15 0.35 0.2 0.35 0.25 0.35 0.3 0.35 0.35 0.35 0.4 0.35 0.45 0.35 0.5 0.35 0.55 0.35 0.6 0.35 0.65 0.35 0.7 0.35 0.75 0.35 0.8 0.35 0.85 0.35 0.9 0.35 0.95 0.35 1 0.35 0 0.4 0.05 0.4 0.1 0.4 0.15 0.4 0.2 0.4 0.25 0.4 0.3 0.4 0.35 0.4 0.4 0.4 0.45 0.4 0.5 0.4 0.55 0.4 0.6 0.4 0.65 0.4 0.7 0.4 0.75 0.4 0.8 0.4 0.85 0.4 0.9 0.4 0.95 0.4 1 0.4 0 0.45 0.05 0.45 0.1 0.45 0.15 0.45 0.2 0.45 0.25 0.45 0.3 0.45 0.35 0.45 0.4 0.45 0.45 0.45 0.5 0.45 0.55 0.45 0.6 0.45 0.65 0.45 0.7 0.45 0.75 0.45 0.8 0.45 0.85 0.45 0.9 0.45 0.95 0.45 1 0.45 0 0.5 0.05 0.5 0.1 0.5 0.15 0.5 0.2 0.5 0.25 0.5 0.3 0.5 0.35 0.5 0.4 0.5 0.45 0.5 0.5 0.5 0.55 0.5 0.6 0.5 0.65 0.5 0.7 0.5 0.75 0.5 0.8 0.5 0.85 0.5 0.9 0.5 0.95 0.5 1 0.5 0 0.55 0.05 0.55 0.1 0.55 0.15 0.55 0.2 0.55 0.25 0.55 0.3 0.55 0.35 0.55 0.4 0.55 0.45 0.55 0.5 0.55 0.55 0.55 0.6 0.55 0.65 0.55 0.7 0.55 0.75 0.55 0.8 0.55 0.85 0.55 0.9 0.55 0.95 0.55 1 0.55 0 0.6 0.05 0.6 0.1 0.6 0.15 0.6 0.2 0.6 0.25 0.6 0.3 0.6 0.35 0.6 0.4 0.6 0.45 0.6 0.5 0.6 0.55 0.6 0.6 0.6 0.65 0.6 0.7 0.6 0.75 0.6 0.8 0.6 0.85 0.6 0.9 0.6 0.95 0.6 1 0.6 0 0.65 0.05 0.65 0.1 0.65 0.15 0.65 0.2 0.65 0.25 0.65 0.3 0.65 0.35 0.65 0.4 0.65 0.45 0.65 0.5 0.65 0.55 0.65 0.6 0.65 0.65 0.65 0.7 0.65 0.75 0.65 0.8 0.65 0.85 0.65 0.9 0.65 0.95 0.65 1 0.65 0 0.7 0.05 0.7 0.1 0.7 0.15 0.7 0.2 0.7 0.25 0.7 0.3 0.7 0.35 0.7 0.4 0.7 0.45 0.7 0.5 0.7 0.55 0.7 0.6 0.7 0.65 0.7 0.7 0.7 0.75 0.7 0.8 0.7 0.85 0.7 0.9 0.7 0.95 0.7 1 0.7 0 0.75 0.05 0.75 0.1 0.75 0.15 0.75 0.2 0.75 0.25 0.75 0.3 0.75 0.35 0.75 0.4 0.75 0.45 0.75 0.5 0.75 0.55 0.75 0.6 0.75 0.65 0.75 0.7 0.75 0.75 0.75 0.8 0.75 0.85 0.75 0.9 0.75 0.95 0.75 1 0.75 0 0.8 0.05 0.8 0.1 0.8 0.15 0.8 0.2 0.8 0.25 0.8 0.3 0.8 0.35 0.8 0.4 0.8 0.45 0.8 0.5 0.8 0.55 0.8 0.6 0.8 0.65 0.8 0.7 0.8 0.75 0.8 0.8 0.8 0.85 0.8 0.9 0.8 0.95 0.8 1 0.8 0 0.85 0.05 0.85 0.1 0.85 0.15 0.85 0.2 0.85 0.25 0.85 0.3 0.85 0.35 0.85 0.4 0.85 0.45 0.85 0.5 0.85 0.55 0.85 0.6 0.85 0.65 0.85 0.7 0.85 0.75 0.85 0.8 0.85 0.85 0.85 0.9 0.85 0.95 0.85 1 0.85 0 0.9 0.05 0.9 0.1 0.9 0.15 0.9 0.2 0.9 0.25 0.9 0.3 0.9 0.35 0.9 0.4 0.9 0.45 0.9 0.5 0.9 0.55 0.9 0.6 0.9 0.65 0.9 0.7 0.9 0.75 0.9 0.8 0.9 0.85 0.9 0.9 0.9 0.95 0.9 1 0.9 0 0.95 0.05 0.95 0.1 0.95 0.15 0.95 0.2 0.95 0.25 0.95 0.3 0.95 0.35 0.95 0.4 0.95 0.45 0.95 0.5 0.95 0.55 0.95 0.6 0.95 0.65 0.95 0.7 0.95 0.75 0.95 0.8 0.95 0.85 0.95 0.9 0.95 0.95 0.95 1 0.95 0.5 0 0.5 1 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 111 |

0 0 1 1 21 22 20 21 1 1 2 2 22 23 21 22 2 2 3 3 23 24 22 23 3 3 4 4 24 25 23 24 4 4 5 5 25 26 24 25 5 5 6 6 26 27 25 26 6 6 7 7 27 28 26 27 7 7 8 8 28 29 27 28 8 8 9 9 29 30 28 29 9 9 10 10 30 31 29 30 10 10 11 11 31 32 30 31 11 11 12 12 32 33 31 32 12 12 13 13 33 34 32 33 13 13 14 14 34 35 33 34 14 14 15 15 35 36 34 35 15 15 16 16 36 37 35 36 16 16 17 17 37 38 36 37 17 17 18 18 38 39 37 38 18 18 19 19 39 40 38 39 19 19 0 20 20 41 39 40 20 21 21 22 41 43 40 42 21 22 22 23 42 44 41 43 22 23 23 24 43 45 42 44 23 24 24 25 44 46 43 45 24 25 25 26 45 47 44 46 25 26 26 27 46 48 45 47 26 27 27 28 47 49 46 48 27 28 28 29 48 50 47 49 28 29 29 30 49 51 48 50 29 30 30 31 50 52 49 51 30 31 31 32 51 53 50 52 31 32 32 33 52 54 51 53 32 33 33 34 53 55 52 54 33 34 34 35 54 56 53 55 34 35 35 36 55 57 54 56 35 36 36 37 56 58 55 57 36 37 37 38 57 59 56 58 37 38 38 39 58 60 57 59 38 39 39 40 59 61 58 60 39 40 20 41 40 62 59 61 40 42 41 43 61 64 60 63 41 43 42 44 62 65 61 64 42 44 43 45 63 66 62 65 43 45 44 46 64 67 63 66 44 46 45 47 65 68 64 67 45 47 46 48 66 69 65 68 46 48 47 49 67 70 66 69 47 49 48 50 68 71 67 70 48 50 49 51 69 72 68 71 49 51 50 52 70 73 69 72 50 52 51 53 71 74 70 73 51 53 52 54 72 75 71 74 52 54 53 55 73 76 72 75 53 55 54 56 74 77 73 76 54 56 55 57 75 78 74 77 55 57 56 58 76 79 75 78 56 58 57 59 77 80 76 79 57 59 58 60 78 81 77 80 58 60 59 61 79 82 78 81 59 61 40 62 60 83 79 82 60 63 61 64 81 85 80 84 61 64 62 65 82 86 81 85 62 65 63 66 83 87 82 86 63 66 64 67 84 88 83 87 64 67 65 68 85 89 84 88 65 68 66 69 86 90 85 89 66 69 67 70 87 91 86 90 67 70 68 71 88 92 87 91 68 71 69 72 89 93 88 92 69 72 70 73 90 94 89 93 70 73 71 74 91 95 90 94 71 74 72 75 92 96 91 95 72 75 73 76 93 97 92 96 73 76 74 77 94 98 93 97 74 77 75 78 95 99 94 98 75 78 76 79 96 100 95 99 76 79 77 80 97 101 96 100 77 80 78 81 98 102 97 101 78 81 79 82 99 103 98 102 79 82 60 83 80 104 99 103 80 84 81 85 101 106 100 105 81 85 82 86 102 107 101 106 82 86 83 87 103 108 102 107 83 87 84 88 104 109 103 108 84 88 85 89 105 110 104 109 85 89 86 90 106 111 105 110 86 90 87 91 107 112 106 111 87 91 88 92 108 113 107 112 88 92 89 93 109 114 108 113 89 93 90 94 110 115 109 114 90 94 91 95 111 116 110 115 91 95 92 96 112 117 111 116 92 96 93 97 113 118 112 117 93 97 94 98 114 119 113 118 94 98 95 99 115 120 114 119 95 99 96 100 116 121 115 120 96 100 97 101 117 122 116 121 97 101 98 102 118 123 117 122 98 102 99 103 119 124 118 123 99 103 80 104 100 125 119 124 100 105 101 106 121 127 120 126 101 106 102 107 122 128 121 127 102 107 103 108 123 129 122 128 103 108 104 109 124 130 123 129 104 109 105 110 125 131 124 130 105 110 106 111 126 132 125 131 106 111 107 112 127 133 126 132 107 112 108 113 128 134 127 133 108 113 109 114 129 135 128 134 109 114 110 115 130 136 129 135 110 115 111 116 131 137 130 136 111 116 112 117 132 138 131 137 112 117 113 118 133 139 132 138 113 118 114 119 134 140 133 139 114 119 115 120 135 141 134 140 115 120 116 121 136 142 135 141 116 121 117 122 137 143 136 142 117 122 118 123 138 144 137 143 118 123 119 124 139 145 138 144 119 124 100 125 120 146 139 145 120 126 121 127 141 148 140 147 121 127 122 128 142 149 141 148 122 128 123 129 143 150 142 149 123 129 124 130 144 151 143 150 124 130 125 131 145 152 144 151 125 131 126 132 146 153 145 152 126 132 127 133 147 154 146 153 127 133 128 134 148 155 147 154 128 134 129 135 149 156 148 155 129 135 130 136 150 157 149 156 130 136 131 137 151 158 150 157 131 137 132 138 152 159 151 158 132 138 133 139 153 160 152 159 133 139 134 140 154 161 153 160 134 140 135 141 155 162 154 161 135 141 136 142 156 163 155 162 136 142 137 143 157 164 156 163 137 143 138 144 158 165 157 164 138 144 139 145 159 166 158 165 139 145 120 146 140 167 159 166 140 147 141 148 161 169 160 168 141 148 142 149 162 170 161 169 142 149 143 150 163 171 162 170 143 150 144 151 164 172 163 171 144 151 145 152 165 173 164 172 145 152 146 153 166 174 165 173 146 153 147 154 167 175 166 174 147 154 148 155 168 176 167 175 148 155 149 156 169 177 168 176 149 156 150 157 170 178 169 177 150 157 151 158 171 179 170 178 151 158 152 159 172 180 171 179 152 159 153 160 173 181 172 180 153 160 154 161 174 182 173 181 154 161 155 162 175 183 174 182 155 162 156 163 176 184 175 183 156 163 157 164 177 185 176 184 157 164 158 165 178 186 177 185 158 165 159 166 179 187 178 186 159 166 140 167 160 188 179 187 160 168 161 169 181 190 180 189 161 169 162 170 182 191 181 190 162 170 163 171 183 192 182 191 163 171 164 172 184 193 183 192 164 172 165 173 185 194 184 193 165 173 166 174 186 195 185 194 166 174 167 175 187 196 186 195 167 175 168 176 188 197 187 196 168 176 169 177 189 198 188 197 169 177 170 178 190 199 189 198 170 178 171 179 191 200 190 199 171 179 172 180 192 201 191 200 172 180 173 181 193 202 192 201 173 181 174 182 194 203 193 202 174 182 175 183 195 204 194 203 175 183 176 184 196 205 195 204 176 184 177 185 197 206 196 205 177 185 178 186 198 207 197 206 178 186 179 187 199 208 198 207 179 187 160 188 180 209 199 208 180 189 181 190 201 211 200 210 181 190 182 191 202 212 201 211 182 191 183 192 203 213 202 212 183 192 184 193 204 214 203 213 184 193 185 194 205 215 204 214 185 194 186 195 206 216 205 215 186 195 187 196 207 217 206 216 187 196 188 197 208 218 207 217 188 197 189 198 209 219 208 218 189 198 190 199 210 220 209 219 190 199 191 200 211 221 210 220 191 200 192 201 212 222 211 221 192 201 193 202 213 223 212 222 193 202 194 203 214 224 213 223 194 203 195 204 215 225 214 224 195 204 196 205 216 226 215 225 196 205 197 206 217 227 216 226 197 206 198 207 218 228 217 227 198 207 199 208 219 229 218 228 199 208 180 209 200 230 219 229 200 210 201 211 221 232 220 231 201 211 202 212 222 233 221 232 202 212 203 213 223 234 222 233 203 213 204 214 224 235 223 234 204 214 205 215 225 236 224 235 205 215 206 216 226 237 225 236 206 216 207 217 227 238 226 237 207 217 208 218 228 239 227 238 208 218 209 219 229 240 228 239 209 219 210 220 230 241 229 240 210 220 211 221 231 242 230 241 211 221 212 222 232 243 231 242 212 222 213 223 233 244 232 243 213 223 214 224 234 245 233 244 214 224 215 225 235 246 234 245 215 225 216 226 236 247 235 246 216 226 217 227 237 248 236 247 217 227 218 228 238 249 237 248 218 228 219 229 239 250 238 249 219 229 200 230 220 251 239 250 220 231 221 232 241 253 240 252 221 232 222 233 242 254 241 253 222 233 223 234 243 255 242 254 223 234 224 235 244 256 243 255 224 235 225 236 245 257 244 256 225 236 226 237 246 258 245 257 226 237 227 238 247 259 246 258 227 238 228 239 248 260 247 259 228 239 229 240 249 261 248 260 229 240 230 241 250 262 249 261 230 241 231 242 251 263 250 262 231 242 232 243 252 264 251 263 232 243 233 244 253 265 252 264 233 244 234 245 254 266 253 265 234 245 235 246 255 267 254 266 235 246 236 247 256 268 255 267 236 247 237 248 257 269 256 268 237 248 238 249 258 270 257 269 238 249 239 250 259 271 258 270 239 250 220 251 240 272 259 271 240 252 241 253 261 274 260 273 241 253 242 254 262 275 261 274 242 254 243 255 263 276 262 275 243 255 244 256 264 277 263 276 244 256 245 257 265 278 264 277 245 257 246 258 266 279 265 278 246 258 247 259 267 280 266 279 247 259 248 260 268 281 267 280 248 260 249 261 269 282 268 281 249 261 250 262 270 283 269 282 250 262 251 263 271 284 270 283 251 263 252 264 272 285 271 284 252 264 253 265 273 286 272 285 253 265 254 266 274 287 273 286 254 266 255 267 275 288 274 287 255 267 256 268 276 289 275 288 256 268 257 269 277 290 276 289 257 269 258 270 278 291 277 290 258 270 259 271 279 292 278 291 259 271 240 272 260 293 279 292 260 273 261 274 281 295 280 294 261 274 262 275 282 296 281 295 262 275 263 276 283 297 282 296 263 276 264 277 284 298 283 297 264 277 265 278 285 299 284 298 265 278 266 279 286 300 285 299 266 279 267 280 287 301 286 300 267 280 268 281 288 302 287 301 268 281 269 282 289 303 288 302 269 282 270 283 290 304 289 303 270 283 271 284 291 305 290 304 271 284 272 285 292 306 291 305 272 285 273 286 293 307 292 306 273 286 274 287 294 308 293 307 274 287 275 288 295 309 294 308 275 288 276 289 296 310 295 309 276 289 277 290 297 311 296 310 277 290 278 291 298 312 297 311 278 291 279 292 299 313 298 312 279 292 260 293 280 314 299 313 280 294 281 295 301 316 300 315 281 295 282 296 302 317 301 316 282 296 283 297 303 318 302 317 283 297 284 298 304 319 303 318 284 298 285 299 305 320 304 319 285 299 286 300 306 321 305 320 286 300 287 301 307 322 306 321 287 301 288 302 308 323 307 322 288 302 289 303 309 324 308 323 289 303 290 304 310 325 309 324 290 304 291 305 311 326 310 325 291 305 292 306 312 327 311 326 292 306 293 307 313 328 312 327 293 307 294 308 314 329 313 328 294 308 295 309 315 330 314 329 295 309 296 310 316 331 315 330 296 310 297 311 317 332 316 331 297 311 298 312 318 333 317 332 298 312 299 313 319 334 318 333 299 313 280 314 300 335 319 334 300 315 301 316 321 337 320 336 301 316 302 317 322 338 321 337 302 317 303 318 323 339 322 338 303 318 304 319 324 340 323 339 304 319 305 320 325 341 324 340 305 320 306 321 326 342 325 341 306 321 307 322 327 343 326 342 307 322 308 323 328 344 327 343 308 323 309 324 329 345 328 344 309 324 310 325 330 346 329 345 310 325 311 326 331 347 330 346 311 326 312 327 332 348 331 347 312 327 313 328 333 349 332 348 313 328 314 329 334 350 333 349 314 329 315 330 335 351 334 350 315 330 316 331 336 352 335 351 316 331 317 332 337 353 336 352 317 332 318 333 338 354 337 353 318 333 319 334 339 355 338 354 319 334 300 335 320 356 339 355 320 336 321 337 341 358 340 357 321 337 322 338 342 359 341 358 322 338 323 339 343 360 342 359 323 339 324 340 344 361 343 360 324 340 325 341 345 362 344 361 325 341 326 342 346 363 345 362 326 342 327 343 347 364 346 363 327 343 328 344 348 365 347 364 328 344 329 345 349 366 348 365 329 345 330 346 350 367 349 366 330 346 331 347 351 368 350 367 331 347 332 348 352 369 351 368 332 348 333 349 353 370 352 369 333 349 334 350 354 371 353 370 334 350 335 351 355 372 354 371 335 351 336 352 356 373 355 372 336 352 337 353 357 374 356 373 337 353 338 354 358 375 357 374 338 354 339 355 359 376 358 375 339 355 320 356 340 377 359 376 340 357 341 358 361 379 360 378 341 358 342 359 362 380 361 379 342 359 343 360 363 381 362 380 343 360 344 361 364 382 363 381 344 361 345 362 365 383 364 382 345 362 346 363 366 384 365 383 346 363 347 364 367 385 366 384 347 364 348 365 368 386 367 385 348 365 349 366 369 387 368 386 349 366 350 367 370 388 369 387 350 367 351 368 371 389 370 388 351 368 352 369 372 390 371 389 352 369 353 370 373 391 372 390 353 370 354 371 374 392 373 391 354 371 355 372 375 393 374 392 355 372 356 373 376 394 375 393 356 373 357 374 377 395 376 394 357 374 358 375 378 396 377 395 358 375 359 376 379 397 378 396 359 376 340 377 360 398 379 397 1 1 0 0 380 399 2 2 1 1 380 399 3 3 2 2 380 399 4 4 3 3 380 399 5 5 4 4 380 399 6 6 5 5 380 399 7 7 6 6 380 399 8 8 7 7 380 399 9 9 8 8 380 399 10 10 9 9 380 399 11 11 10 10 380 399 12 12 11 11 380 399 13 13 12 12 380 399 14 14 13 13 380 399 15 15 14 14 380 399 16 16 15 15 380 399 17 17 16 16 380 399 18 18 17 17 380 399 19 19 18 18 380 399 0 20 19 19 380 399 360 378 361 379 381 400 361 379 362 380 381 400 362 380 363 381 381 400 363 381 364 382 381 400 364 382 365 383 381 400 365 383 366 384 381 400 366 384 367 385 381 400 367 385 368 386 381 400 368 386 369 387 381 400 369 387 370 388 381 400 370 388 371 389 381 400 371 389 372 390 381 400 372 390 373 391 381 400 373 391 374 392 381 400 374 392 375 393 381 400 375 393 376 394 381 400 376 394 377 395 381 400 377 395 378 396 381 400 378 396 379 397 381 400 379 397 360 398 381 400

112 |
113 |
114 |
115 |
116 | 117 | 118 | 119 | 0 0 1 0 120 | 0 1 0 0 121 | 1 0 0 0 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 |
-------------------------------------------------------------------------------- /data/sphere.lz4.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierrec/node-lz4/943e768691a9fb29e2d9a88f9942463765a45468/data/sphere.lz4.dat -------------------------------------------------------------------------------- /data/test: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Pierre Curto" 3 | , "name": "lz4-js" 4 | , "description": "LZ4 streaming compression and decompression" 5 | , "keywords": ["lz4","compression","decompression","stream"] 6 | , "version": "0.0.1" 7 | , "homepage": "http://github.com/pierrec/node-lz4-js" 8 | , "repository": { 9 | "type": "git" 10 | , "url": "git://github.com/pierrec/node-lz4-js.git" 11 | } 12 | , "main": "./lib/lz4.js" 13 | , "bugs": { "url" : "http://github.com/pierrec/node-lz4-js/issues" } 14 | , "licenses": 15 | [ { 16 | "type": "MIT" 17 | , "url": "http://github.com/pierrec/node-lz4-js/raw/master/LICENSE" 18 | } 19 | ] 20 | , "engines": { 21 | "node": ">= 0.8" 22 | } 23 | , "dependencies": { 24 | "inherits": ">= 1.0" 25 | } 26 | , "devDependencies": { 27 | "mocha": ">= 0.10" 28 | } 29 | , "scripts": { 30 | "test": "mocha test/*-test.js" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /data/test.lz4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierrec/node-lz4/943e768691a9fb29e2d9a88f9942463765a45468/data/test.lz4 -------------------------------------------------------------------------------- /data/testHC.lz4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierrec/node-lz4/943e768691a9fb29e2d9a88f9942463765a45468/data/testHC.lz4 -------------------------------------------------------------------------------- /data/test_medium: -------------------------------------------------------------------------------- 1 | # LZ4 2 | 3 | [LZ4](http://fastcompression.blogspot.fr/) is a very fast compression and decompression algorithm. This nodejs module provides a Javascript implementation of the decoder as well as native bindings to the LZ4 functions. Nodejs Streams are also supported for compression and decompression. 4 | 5 | 6 | ## Install 7 | 8 | npm install lz4 9 | 10 | 11 | ## Usage 12 | 13 | ### Encoding 14 | 15 | There are 2 ways to encode: 16 | 17 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations). 18 | * __synchronous__ by feeding the whole set of data - faster but is limited by the amount of memory 19 | 20 | 21 | #### Asynchronous encoding 22 | 23 | First, create an LZ4 encoding NodeJS stream with `LZ4#createEncoderStream(options)`. 24 | 25 | * `options.chunkSize` (_Number_): chunk size to use (default=8Mb) (optional) 26 | * `options.hc` (_Boolean_): use high compression (default=false) (optional) 27 | 28 | 29 | The stream can then encode any data piped to it. It will emit a `data` event on each encoded chunk, which can be saved into an output stream. 30 | 31 | The following example shows how to encode a file `test` into `test.lz4`. 32 | 33 | 34 | ```javascript 35 | var fs = require('fs') 36 | var lz4 = require('lz4') 37 | 38 | var encoder = lz4.createEncoderStream() 39 | 40 | var input = fs.createReadStream('test') 41 | var output = fs.createWriteStream('test.lz4') 42 | 43 | input.pipe(encoder).pipe(output) 44 | 45 | ``` 46 | 47 | #### Synchronous encoding 48 | 49 | Read the data into memory and feed it to `LZ4#encode(input[, options])` to decode an LZ4 stream. 50 | 51 | * `input` (_Buffer_): data to encode 52 | * `options` (_Object_): LZ4 stream options (optional) 53 | * `options.blockMaxSize` (_Number_): chunk size to use (default=4Mb) 54 | * `options.highCompression` (_Boolean_): use high compression (default=false) 55 | * `options.blockIndependence` (_Boolean_): (default=true) 56 | * `options.blockChecksum` (_Boolean_): add compressed blocks checksum (default=false) 57 | * `options.streamSize` (_Boolean_): add full LZ4 stream size (default=false) 58 | * `options.streamChecksum` (_Boolean_): add full LZ4 stream checksum (default=true) 59 | * `options.dict` (_Boolean_): use dictionary (default=false) 60 | * `options.dictId` (_Integer_): dictionary id (default=0) 61 | 62 | 63 | ```javascript 64 | var fs = require('fs') 65 | var lz4 = require('lz4') 66 | 67 | var input = fs.readFileSync('test') 68 | var output = lz4.encode(input) 69 | 70 | fs.writeFileSync('test.lz4', output) 71 | 72 | ``` 73 | 74 | 75 | ### Decoding 76 | 77 | There are 2 ways to decode: 78 | 79 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations) 80 | * __synchronous__ by feeding the whole LZ4 data - faster but is limited by the amount of memory 81 | 82 | 83 | #### Asynchronous decoding 84 | 85 | First, create an LZ4 decoding NodeJS stream with `LZ4#createDecoderStream(options)`. 86 | 87 | * `options.chunkSize` (_Number_): chunk size to use (default=8Mb) (optional) 88 | * `options.outputSize` (_Number_): number of bytes for the output buffer (default=`chunkSize`) (optional) 89 | 90 | 91 | The stream can then decode any data piped to it. It will emit a `data` event on each decoded sequence, which can be saved into an output stream. 92 | 93 | The following example shows how to decode an LZ4 compressed file `test.lz4` into `test`. 94 | 95 | 96 | ```javascript 97 | var fs = require('fs') 98 | var lz4 = require('lz4') 99 | 100 | var decoder = lz4.createDecoderStream() 101 | 102 | var input = fs.createReadStream('test.lz4') 103 | var output = fs.createWriteStream('test') 104 | 105 | input.pipe(decoder).pipe(output) 106 | 107 | ``` 108 | 109 | #### Synchronous decoding 110 | 111 | Read the data into memory and feed it to `LZ4#decode(input)` to produce an LZ4 stream. 112 | 113 | * `input` (_Buffer_): data to decode 114 | 115 | 116 | ```javascript 117 | var fs = require('fs') 118 | var lz4 = require('lz4') 119 | 120 | var input = fs.readFileSync('test.lz4') 121 | var output = lz4.decode(input) 122 | 123 | fs.writeFileSync('test', output) 124 | 125 | ``` 126 | 127 | 128 | ## How it works 129 | 130 | * [LZ4 stream format](http://fastcompression.blogspot.fr/2011/05/lz4-explained.html) 131 | 132 | ## Restrictions / Issues 133 | 134 | * LZ4 streams have only been tested using `bin/lz4demo32`, not `bin/lz4demo64`. 135 | 136 | ## License 137 | 138 | MIT# LZ4 139 | 140 | [LZ4](http://fastcompression.blogspot.fr/) is a very fast compression and decompression algorithm. This nodejs module provides a Javascript implementation of the decoder as well as native bindings to the LZ4 functions. Nodejs Streams are also supported for compression and decompression. 141 | 142 | 143 | ## Install 144 | 145 | npm install lz4 146 | 147 | 148 | ## Usage 149 | 150 | ### Encoding 151 | 152 | There are 2 ways to encode: 153 | 154 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations). 155 | * __synchronous__ by feeding the whole set of data - faster but is limited by the amount of memory 156 | 157 | 158 | #### Asynchronous encoding 159 | 160 | First, create an LZ4 encoding NodeJS stream with `LZ4#createEncoderStream(options)`. 161 | 162 | * `options.chunkSize` (_Number_): chunk size to use (default=8Mb) (optional) 163 | * `options.hc` (_Boolean_): use high compression (default=false) (optional) 164 | 165 | 166 | The stream can then encode any data piped to it. It will emit a `data` event on each encoded chunk, which can be saved into an output stream. 167 | 168 | The following example shows how to encode a file `test` into `test.lz4`. 169 | 170 | 171 | ```javascript 172 | var fs = require('fs') 173 | var lz4 = require('lz4') 174 | 175 | var encoder = lz4.createEncoderStream() 176 | 177 | var input = fs.createReadStream('test') 178 | var output = fs.createWriteStream('test.lz4') 179 | 180 | input.pipe(encoder).pipe(output) 181 | 182 | ``` 183 | 184 | #### Synchronous encoding 185 | 186 | Read the data into memory and feed it to `LZ4#encode(input[, options])` to decode an LZ4 stream. 187 | 188 | * `input` (_Buffer_): data to encode 189 | * `options` (_Object_): LZ4 stream options (optional) 190 | * `options.blockMaxSize` (_Number_): chunk size to use (default=4Mb) 191 | * `options.highCompression` (_Boolean_): use high compression (default=false) 192 | * `options.blockIndependence` (_Boolean_): (default=true) 193 | * `options.blockChecksum` (_Boolean_): add compressed blocks checksum (default=false) 194 | * `options.streamSize` (_Boolean_): add full LZ4 stream size (default=false) 195 | * `options.streamChecksum` (_Boolean_): add full LZ4 stream checksum (default=true) 196 | * `options.dict` (_Boolean_): use dictionary (default=false) 197 | * `options.dictId` (_Integer_): dictionary id (default=0) 198 | 199 | 200 | ```javascript 201 | var fs = require('fs') 202 | var lz4 = require('lz4') 203 | 204 | var input = fs.readFileSync('test') 205 | var output = lz4.encode(input) 206 | 207 | fs.writeFileSync('test.lz4', output) 208 | 209 | ``` 210 | 211 | 212 | ### Decoding 213 | 214 | There are 2 ways to decode: 215 | 216 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations) 217 | * __synchronous__ by feeding the whole LZ4 data - faster but is limited by the amount of memory 218 | 219 | 220 | #### Asynchronous decoding 221 | 222 | First, create an LZ4 decoding NodeJS stream with `LZ4#createDecoderStream(options)`. 223 | 224 | * `options.chunkSize` (_Number_): chunk size to use (default=8Mb) (optional) 225 | * `options.outputSize` (_Number_): number of bytes for the output buffer (default=`chunkSize`) (optional) 226 | 227 | 228 | The stream can then decode any data piped to it. It will emit a `data` event on each decoded sequence, which can be saved into an output stream. 229 | 230 | The following example shows how to decode an LZ4 compressed file `test.lz4` into `test`. 231 | 232 | 233 | ```javascript 234 | var fs = require('fs') 235 | var lz4 = require('lz4') 236 | 237 | var decoder = lz4.createDecoderStream() 238 | 239 | var input = fs.createReadStream('test.lz4') 240 | var output = fs.createWriteStream('test') 241 | 242 | input.pipe(decoder).pipe(output) 243 | 244 | ``` 245 | 246 | #### Synchronous decoding 247 | 248 | Read the data into memory and feed it to `LZ4#decode(input)` to produce an LZ4 stream. 249 | 250 | * `input` (_Buffer_): data to decode 251 | 252 | 253 | ```javascript 254 | var fs = require('fs') 255 | var lz4 = require('lz4') 256 | 257 | var input = fs.readFileSync('test.lz4') 258 | var output = lz4.decode(input) 259 | 260 | fs.writeFileSync('test', output) 261 | 262 | ``` 263 | 264 | 265 | ## How it works 266 | 267 | * [LZ4 stream format](http://fastcompression.blogspot.fr/2011/05/lz4-explained.html) 268 | 269 | ## Restrictions / Issues 270 | 271 | * LZ4 streams have only been tested using `bin/lz4demo32`, not `bin/lz4demo64`. 272 | 273 | ## License 274 | 275 | MIT# LZ4 276 | 277 | [LZ4](http://fastcompression.blogspot.fr/) is a very fast compression and decompression algorithm. This nodejs module provides a Javascript implementation of the decoder as well as native bindings to the LZ4 functions. Nodejs Streams are also supported for compression and decompression. 278 | 279 | 280 | ## Install 281 | 282 | npm install lz4 283 | 284 | 285 | ## Usage 286 | 287 | ### Encoding 288 | 289 | There are 2 ways to encode: 290 | 291 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations). 292 | * __synchronous__ by feeding the whole set of data - faster but is limited by the amount of memory 293 | 294 | 295 | #### Asynchronous encoding 296 | 297 | First, create an LZ4 encoding NodeJS stream with `LZ4#createEncoderStream(options)`. 298 | 299 | * `options.chunkSize` (_Number_): chunk size to use (default=8Mb) (optional) 300 | * `options.hc` (_Boolean_): use high compression (default=false) (optional) 301 | 302 | 303 | The stream can then encode any data piped to it. It will emit a `data` event on each encoded chunk, which can be saved into an output stream. 304 | 305 | The following example shows how to encode a file `test` into `test.lz4`. 306 | 307 | 308 | ```javascript 309 | var fs = require('fs') 310 | var lz4 = require('lz4') 311 | 312 | var encoder = lz4.createEncoderStream() 313 | 314 | var input = fs.createReadStream('test') 315 | var output = fs.createWriteStream('test.lz4') 316 | 317 | input.pipe(encoder).pipe(output) 318 | 319 | ``` 320 | 321 | #### Synchronous encoding 322 | 323 | Read the data into memory and feed it to `LZ4#encode(input[, options])` to decode an LZ4 stream. 324 | 325 | * `input` (_Buffer_): data to encode 326 | * `options` (_Object_): LZ4 stream options (optional) 327 | * `options.blockMaxSize` (_Number_): chunk size to use (default=4Mb) 328 | * `options.highCompression` (_Boolean_): use high compression (default=false) 329 | * `options.blockIndependence` (_Boolean_): (default=true) 330 | * `options.blockChecksum` (_Boolean_): add compressed blocks checksum (default=false) 331 | * `options.streamSize` (_Boolean_): add full LZ4 stream size (default=false) 332 | * `options.streamChecksum` (_Boolean_): add full LZ4 stream checksum (default=true) 333 | * `options.dict` (_Boolean_): use dictionary (default=false) 334 | * `options.dictId` (_Integer_): dictionary id (default=0) 335 | 336 | 337 | ```javascript 338 | var fs = require('fs') 339 | var lz4 = require('lz4') 340 | 341 | var input = fs.readFileSync('test') 342 | var output = lz4.encode(input) 343 | 344 | fs.writeFileSync('test.lz4', output) 345 | 346 | ``` 347 | 348 | 349 | ### Decoding 350 | 351 | There are 2 ways to decode: 352 | 353 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations) 354 | * __synchronous__ by feeding the whole LZ4 data - faster but is limited by the amount of memory 355 | 356 | 357 | #### Asynchronous decoding 358 | 359 | First, create an LZ4 decoding NodeJS stream with `LZ4#createDecoderStream(options)`. 360 | 361 | * `options.chunkSize` (_Number_): chunk size to use (default=8Mb) (optional) 362 | * `options.outputSize` (_Number_): number of bytes for the output buffer (default=`chunkSize`) (optional) 363 | 364 | 365 | The stream can then decode any data piped to it. It will emit a `data` event on each decoded sequence, which can be saved into an output stream. 366 | 367 | The following example shows how to decode an LZ4 compressed file `test.lz4` into `test`. 368 | 369 | 370 | ```javascript 371 | var fs = require('fs') 372 | var lz4 = require('lz4') 373 | 374 | var decoder = lz4.createDecoderStream() 375 | 376 | var input = fs.createReadStream('test.lz4') 377 | var output = fs.createWriteStream('test') 378 | 379 | input.pipe(decoder).pipe(output) 380 | 381 | ``` 382 | 383 | #### Synchronous decoding 384 | 385 | Read the data into memory and feed it to `LZ4#decode(input)` to produce an LZ4 stream. 386 | 387 | * `input` (_Buffer_): data to decode 388 | 389 | 390 | ```javascript 391 | var fs = require('fs') 392 | var lz4 = require('lz4') 393 | 394 | var input = fs.readFileSync('test.lz4') 395 | var output = lz4.decode(input) 396 | 397 | fs.writeFileSync('test', output) 398 | 399 | ``` 400 | 401 | 402 | ## How it works 403 | 404 | * [LZ4 stream format](http://fastcompression.blogspot.fr/2011/05/lz4-explained.html) 405 | 406 | ## Restrictions / Issues 407 | 408 | * LZ4 streams have only been tested using `bin/lz4demo32`, not `bin/lz4demo64`. 409 | 410 | ## License 411 | 412 | MIT# LZ4 413 | 414 | [LZ4](http://fastcompression.blogspot.fr/) is a very fast compression and decompression algorithm. This nodejs module provides a Javascript implementation of the decoder as well as native bindings to the LZ4 functions. Nodejs Streams are also supported for compression and decompression. 415 | 416 | 417 | ## Install 418 | 419 | npm install lz4 420 | 421 | 422 | ## Usage 423 | 424 | ### Encoding 425 | 426 | There are 2 ways to encode: 427 | 428 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations). 429 | * __synchronous__ by feeding the whole set of data - faster but is limited by the amount of memory 430 | 431 | 432 | #### Asynchronous encoding 433 | 434 | First, create an LZ4 encoding NodeJS stream with `LZ4#createEncoderStream(options)`. 435 | 436 | * `options.chunkSize` (_Number_): chunk size to use (default=8Mb) (optional) 437 | * `options.hc` (_Boolean_): use high compression (default=false) (optional) 438 | 439 | 440 | The stream can then encode any data piped to it. It will emit a `data` event on each encoded chunk, which can be saved into an output stream. 441 | 442 | The following example shows how to encode a file `test` into `test.lz4`. 443 | 444 | 445 | ```javascript 446 | var fs = require('fs') 447 | var lz4 = require('lz4') 448 | 449 | var encoder = lz4.createEncoderStream() 450 | 451 | var input = fs.createReadStream('test') 452 | var output = fs.createWriteStream('test.lz4') 453 | 454 | input.pipe(encoder).pipe(output) 455 | 456 | ``` 457 | 458 | #### Synchronous encoding 459 | 460 | Read the data into memory and feed it to `LZ4#encode(input[, options])` to decode an LZ4 stream. 461 | 462 | * `input` (_Buffer_): data to encode 463 | * `options` (_Object_): LZ4 stream options (optional) 464 | * `options.blockMaxSize` (_Number_): chunk size to use (default=4Mb) 465 | * `options.highCompression` (_Boolean_): use high compression (default=false) 466 | * `options.blockIndependence` (_Boolean_): (default=true) 467 | * `options.blockChecksum` (_Boolean_): add compressed blocks checksum (default=false) 468 | * `options.streamSize` (_Boolean_): add full LZ4 stream size (default=false) 469 | * `options.streamChecksum` (_Boolean_): add full LZ4 stream checksum (default=true) 470 | * `options.dict` (_Boolean_): use dictionary (default=false) 471 | * `options.dictId` (_Integer_): dictionary id (default=0) 472 | 473 | 474 | ```javascript 475 | var fs = require('fs') 476 | var lz4 = require('lz4') 477 | 478 | var input = fs.readFileSync('test') 479 | var output = lz4.encode(input) 480 | 481 | fs.writeFileSync('test.lz4', output) 482 | 483 | ``` 484 | 485 | 486 | ### Decoding 487 | 488 | There are 2 ways to decode: 489 | 490 | * __asynchronous__ using nodejs Streams - slowest but can handle very large data sets (no memory limitations) 491 | * __synchronous__ by feeding the whole LZ4 data - faster but is limited by the amount of memory 492 | 493 | 494 | #### Asynchronous decoding 495 | 496 | First, create an LZ4 decoding NodeJS stream with `LZ4#createDecoderStream(options)`. 497 | 498 | * `options.chunkSize` (_Number_): chunk size to use (default=8Mb) (optional) 499 | * `options.outputSize` (_Number_): number of bytes for the output buffer (default=`chunkSize`) (optional) 500 | 501 | 502 | The stream can then decode any data piped to it. It will emit a `data` event on each decoded sequence, which can be saved into an output stream. 503 | 504 | The following example shows how to decode an LZ4 compressed file `test.lz4` into `test`. 505 | 506 | 507 | ```javascript 508 | var fs = require('fs') 509 | var lz4 = require('lz4') 510 | 511 | var decoder = lz4.createDecoderStream() 512 | 513 | var input = fs.createReadStream('test.lz4') 514 | var output = fs.createWriteStream('test') 515 | 516 | input.pipe(decoder).pipe(output) 517 | 518 | ``` 519 | 520 | #### Synchronous decoding 521 | 522 | Read the data into memory and feed it to `LZ4#decode(input)` to produce an LZ4 stream. 523 | 524 | * `input` (_Buffer_): data to decode 525 | 526 | 527 | ```javascript 528 | var fs = require('fs') 529 | var lz4 = require('lz4') 530 | 531 | var input = fs.readFileSync('test.lz4') 532 | var output = lz4.decode(input) 533 | 534 | fs.writeFileSync('test', output) 535 | 536 | ``` 537 | 538 | 539 | ## How it works 540 | 541 | * [LZ4 stream format](http://fastcompression.blogspot.fr/2011/05/lz4-explained.html) 542 | 543 | ## Restrictions / Issues 544 | 545 | * LZ4 streams have only been tested using `bin/lz4demo32`, not `bin/lz4demo64`. 546 | 547 | ## License 548 | 549 | MIT -------------------------------------------------------------------------------- /data/test_medium.lz4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierrec/node-lz4/943e768691a9fb29e2d9a88f9942463765a45468/data/test_medium.lz4 -------------------------------------------------------------------------------- /data/test_smallchunk.lz4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierrec/node-lz4/943e768691a9fb29e2d9a88f9942463765a45468/data/test_smallchunk.lz4 -------------------------------------------------------------------------------- /doc/format.txt: -------------------------------------------------------------------------------- 1 | lz4 format 2 | 3 | sequence = token(1) + literalslen(i) + literals(token >> 4 + i) + [match copy: offset(2) + length(token >> 4 << 4)] 4 | 5 | match copy: 6 | position = current postition - offset (0 is invalid) 7 | length = 4 + length 8 | 9 | last 5 bytes = literals 10 | last match starts 12 bytes before end of stream 11 | last sequence is incomplete and stops after the literals -------------------------------------------------------------------------------- /examples/compress.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | LZ4 compress 4 | 5 | 6 | 7 | 40 |
41 |
42 | 43 |
44 |

45 | 46 |

47 | 48 |
49 |
50 | 51 |
52 |

53 | 54 |

55 |
56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /examples/cu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/file_compress.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compress a stream 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test' 11 | var outputFile = process.argv[3] || inputFile + lz4.extension 12 | 13 | var encoder = lz4.createEncoderStream() 14 | 15 | var input = fs.createReadStream( inputFile ) 16 | var output = fs.createWriteStream( outputFile ) 17 | 18 | 19 | // Timing 20 | encoder.on('end', function () { 21 | var fileSize = fs.statSync(inputFile).size 22 | var delta = Date.now() - startTime 23 | console.log( 24 | 'lz4 compressed %d bytes in %dms (%dMb/s)' 25 | , fileSize 26 | , delta 27 | , Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 28 | ) 29 | }) 30 | 31 | console.log('Compressing %s to %s...', inputFile, outputFile) 32 | var startTime = Date.now() 33 | input.pipe(encoder).pipe(output) -------------------------------------------------------------------------------- /examples/file_compressBlock.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compress data into a block (no archive format) 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test' 11 | var outputFile = process.argv[3] || inputFile + lz4.extension 12 | 13 | var input = fs.readFileSync( inputFile ) 14 | // Allocate max block size, __to be sliced__ accordingly after compression 15 | var output = Buffer.alloc( lz4.encodeBound(input.length) ) 16 | 17 | console.log('Compressing %s to %s...', inputFile, outputFile) 18 | var startTime = Date.now() 19 | 20 | // encodeBlock is synchronous 21 | // native 22 | var compressedBlockSize = lz4.encodeBlock(input, output) 23 | // javascript 24 | //var compressedBlockSize = require('../lib/binding').compress(input, output) 25 | 26 | // Timing 27 | var delta = Date.now() - startTime 28 | 29 | if (compressedBlockSize > 0) { 30 | var fileSize = fs.statSync(inputFile).size 31 | console.log( 32 | 'lz4 block compressed %d bytes into %d bytes in %dms (%dMb/s)' 33 | , fileSize 34 | , compressedBlockSize 35 | , delta 36 | , delta > 0 ? Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 : 0 37 | ) 38 | output = output.slice(0, compressedBlockSize) 39 | } else { 40 | console.log('data could not be compressed') 41 | output = input 42 | } 43 | 44 | fs.writeFileSync( outputFile, output ) 45 | -------------------------------------------------------------------------------- /examples/file_compressHC.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compress a stream 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test' 11 | var outputFile = process.argv[3] || inputFile + lz4.extension 12 | 13 | var encoder = lz4.createEncoderStream({ highCompression: true }) 14 | 15 | var input = fs.createReadStream( inputFile ) 16 | var output = fs.createWriteStream( outputFile ) 17 | 18 | // Timing 19 | encoder.on('end', function () { 20 | var delta = Date.now() - startTime 21 | var fileSize = fs.statSync(inputFile).size 22 | var outfileSize = fs.statSync(outputFile).size 23 | console.log( 24 | 'lz4 compressed %d bytes into %d bytes in %dms (%dMb/s)' 25 | , fileSize 26 | , outfileSize 27 | , delta 28 | , Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 29 | ) 30 | }) 31 | 32 | console.log('Compressing %s to %s...', inputFile, outputFile) 33 | var startTime = Date.now() 34 | input.pipe(encoder).pipe(output) -------------------------------------------------------------------------------- /examples/file_compressHCSync.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compress a Buffer 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test' 11 | var outputFile = process.argv[3] || inputFile + lz4.extension 12 | 13 | // Load the data 14 | var input = fs.readFileSync( inputFile ) 15 | 16 | // Timing 17 | console.log('Compressing %s to %s...', inputFile, outputFile) 18 | var startTime = Date.now() 19 | var compressed = lz4.encode(input, { highCompression: true }) 20 | var fileSize = fs.statSync(inputFile).size 21 | var outfileSize = fs.statSync(outputFile).size 22 | var delta = Date.now() - startTime 23 | console.log( 24 | 'lz4 compressed %d bytes into %d bytes in %dms (%dMb/s)' 25 | , fileSize 26 | , outfileSize 27 | , delta 28 | , Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 29 | ) 30 | 31 | // Save the uncompressed data 32 | fs.writeFileSync( outputFile, compressed ) -------------------------------------------------------------------------------- /examples/file_compressJS.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compress a stream using Javascript only 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test' 11 | var outputFile = process.argv[3] || inputFile + lz4.extension 12 | 13 | var encoder = lz4.createEncoderStream({ useJS: true }) 14 | 15 | var input = fs.createReadStream( inputFile ) 16 | var output = fs.createWriteStream( outputFile ) 17 | 18 | 19 | // Timing 20 | encoder.on('end', function () { 21 | var fileSize = fs.statSync(inputFile).size 22 | var delta = Date.now() - startTime 23 | console.log( 24 | 'lz4 compressed %d bytes in %dms (%dMb/s)' 25 | , fileSize 26 | , delta 27 | , Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 28 | ) 29 | }) 30 | 31 | console.log('Compressing using Javascript %s to %s...', inputFile, outputFile) 32 | var startTime = Date.now() 33 | input.pipe(encoder).pipe(output) -------------------------------------------------------------------------------- /examples/file_compressSync.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compress a Buffer 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test' 11 | var outputFile = process.argv[3] || inputFile + lz4.extension 12 | 13 | // Load the data 14 | var input = fs.readFileSync( inputFile ) 15 | 16 | // Timing 17 | 18 | console.log('Compressing %s to %s...', inputFile, outputFile) 19 | var startTime = Date.now() 20 | var compressed = lz4.encode(input) 21 | var delta = Date.now() - startTime 22 | var fileSize = fs.statSync(inputFile).size 23 | console.log( 24 | 'lz4 compressed %d bytes in %dms (%dMb/s)' 25 | , fileSize 26 | , delta 27 | , Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 28 | ) 29 | 30 | // Save the uncompressed data 31 | fs.writeFileSync( outputFile, compressed ) -------------------------------------------------------------------------------- /examples/file_uncompress.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Uncompress an LZ4 stream 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test.lz4' 11 | var outputFile = process.argv[3] || path.basename(inputFile, lz4.extension) 12 | 13 | var decoder = lz4.createDecoderStream() 14 | 15 | // Higher buffer size increases performance 16 | var input = fs.createReadStream( inputFile, { highWaterMark: 4 << 20 } ) 17 | var output = fs.createWriteStream( outputFile ) 18 | 19 | // Timing 20 | var startTime = Date.now() 21 | var fileSize = fs.statSync(inputFile).size 22 | decoder.on('end', function () { 23 | var delta = Date.now() - startTime 24 | console.log( 25 | 'lz4 decompressed %d bytes in %dms (%dMb/s)' 26 | , fileSize 27 | , delta 28 | , Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 29 | ) 30 | }) 31 | 32 | console.log('Uncompressing %s to %s...', inputFile, outputFile) 33 | input.pipe(decoder).pipe(output) -------------------------------------------------------------------------------- /examples/file_uncompressBlock.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Uncompress data block (no archive format) 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test' 11 | var outputFile = process.argv[3] || path.basename(inputFile, lz4.extension) 12 | 13 | var input = fs.readFileSync( inputFile ) 14 | // Allocate output size... randomly :s 15 | var output = Buffer.alloc( input.length * 3 ) 16 | 17 | console.log('Uncompressing %s to %s...', inputFile, outputFile) 18 | var startTime = Date.now() 19 | 20 | // decodeBlock is synchronous 21 | // native 22 | // var uncompressedBlockSize = lz4.decodeBlock(input, output) 23 | // javascript 24 | var uncompressedBlockSize = require('../lib/binding').uncompress(input, output) 25 | 26 | // Timing 27 | var delta = Date.now() - startTime 28 | 29 | if (uncompressedBlockSize > 0) { 30 | var fileSize = fs.statSync(inputFile).size 31 | console.log( 32 | 'lz4 block uncompressed %d bytes into %d bytes in %dms (%dMb/s)' 33 | , fileSize 34 | , uncompressedBlockSize 35 | , delta 36 | , delta > 0 ? Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 : 0 37 | ) 38 | fs.writeFileSync( outputFile, output.slice(0, uncompressedBlockSize) ) 39 | } else { 40 | console.log('data could not be uncompressed') 41 | } 42 | -------------------------------------------------------------------------------- /examples/file_uncompressJS.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Uncompress an LZ4 stream using Javascript 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test.lz4' 11 | var outputFile = process.argv[3] || path.basename(inputFile, lz4.extension) 12 | 13 | var decoder = lz4.createDecoderStream({ useJS: true }) 14 | 15 | // Higher buffer size increases performance 16 | var input = fs.createReadStream( inputFile, { highWaterMark: 4 << 20 } ) 17 | var output = fs.createWriteStream( outputFile ) 18 | 19 | // Timing 20 | var startTime = Date.now() 21 | var fileSize = fs.statSync(inputFile).size 22 | decoder.on('end', function () { 23 | var delta = Date.now() - startTime 24 | console.log( 25 | 'lz4 decompressed %d bytes in %dms (%dMb/s)' 26 | , fileSize 27 | , delta 28 | , Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 29 | ) 30 | }) 31 | 32 | console.log('Uncompressing using Javascript %s to %s...', inputFile, outputFile) 33 | input.pipe(decoder).pipe(output) -------------------------------------------------------------------------------- /examples/file_uncompressSync.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Uncompress a Buffer containing LZ4 compressed data 3 | */ 4 | // Modules 5 | var path = require('path') 6 | var fs = require('fs') 7 | var lz4 = require('..') 8 | 9 | // Input/Output files 10 | var inputFile = process.argv[2] || 'test.lz4' 11 | var outputFile = process.argv[3] || path.basename(inputFile, lz4.extension) 12 | 13 | // Load the compressed data 14 | var input = fs.readFileSync( inputFile ) 15 | 16 | // Timing 17 | var startTime = Date.now() 18 | console.log('Uncompressing %s to %s...', inputFile, outputFile) 19 | var decoded = lz4.decode( input ) 20 | var delta = Date.now() - startTime 21 | 22 | var fileSize = fs.statSync(inputFile).size 23 | console.log( 24 | 'lz4 decompressed %d bytes in %dms (%dMb/s)' 25 | , fileSize 26 | , delta 27 | , Math.round( 100 * fileSize / ( delta * (1 << 20) ) * 1000 ) / 100 28 | ) 29 | 30 | // Save the uncompressed data 31 | fs.writeFileSync( outputFile, decoded ) -------------------------------------------------------------------------------- /examples/uncompress.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | LZ4 uncompress 4 | 5 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | 4 | // base path, that will be used to resolve files and exclude 5 | basePath: '', 6 | 7 | // frameworks to use 8 | frameworks: ['jasmine'], 9 | 10 | // list of files / patterns to load in the browser 11 | files: [ 12 | 'build/lz4.js', 13 | 'test/browser/**/*.js', 14 | { pattern: 'data/**/*', included: false, serve: true} 15 | ], 16 | 17 | // test results reporter to use 18 | // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' 19 | reporters: ['progress'], 20 | 21 | // web server port 22 | port: 9876, 23 | 24 | // enable / disable colors in the output (reporters and logs) 25 | colors: true, 26 | 27 | // level of logging 28 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 29 | logLevel: config.LOG_DEBUG, 30 | 31 | // enable / disable watching file and executing tests whenever any file changes 32 | autoWatch: true, 33 | 34 | // Start these browsers, currently available: 35 | // - Chrome 36 | // - ChromeCanary 37 | // - Firefox 38 | // - Opera (has to be installed with `npm install karma-opera-launcher`) 39 | // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`) 40 | // - PhantomJS 41 | // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`) 42 | browsers: ['Chrome','Firefox'], 43 | 44 | // If browser does not capture in given timeout [ms], kill it 45 | captureTimeout: 60000, 46 | 47 | // Continuous Integration mode 48 | // if true, it capture browsers, run tests and exit 49 | singleRun: false 50 | }); 51 | }; 52 | -------------------------------------------------------------------------------- /lib/binding.js: -------------------------------------------------------------------------------- 1 | /** 2 | Javascript version of the key LZ4 C functions 3 | */ 4 | var uint32 = require('cuint').UINT32 5 | 6 | if (!Math.imul) Math.imul = function imul(a, b) { 7 | var ah = a >>> 16; 8 | var al = a & 0xffff; 9 | var bh = b >>> 16; 10 | var bl = b & 0xffff; 11 | return (al*bl + ((ah*bl + al*bh) << 16))|0; 12 | }; 13 | 14 | /** 15 | * Decode a block. Assumptions: input contains all sequences of a 16 | * chunk, output is large enough to receive the decoded data. 17 | * If the output buffer is too small, an error will be thrown. 18 | * If the returned value is negative, an error occured at the returned offset. 19 | * 20 | * @param input {Buffer} input data 21 | * @param output {Buffer} output data 22 | * @return {Number} number of decoded bytes 23 | * @private 24 | */ 25 | exports.uncompress = function (input, output, sIdx, eIdx) { 26 | sIdx = sIdx || 0 27 | eIdx = eIdx || (input.length - sIdx) 28 | // Process each sequence in the incoming data 29 | for (var i = sIdx, n = eIdx, j = 0; i < n;) { 30 | var token = input[i++] 31 | 32 | // Literals 33 | var literals_length = (token >> 4) 34 | if (literals_length > 0) { 35 | // length of literals 36 | var l = literals_length + 240 37 | while (l === 255) { 38 | l = input[i++] 39 | literals_length += l 40 | } 41 | 42 | // Copy the literals 43 | var end = i + literals_length 44 | while (i < end) output[j++] = input[i++] 45 | 46 | // End of buffer? 47 | if (i === n) return j 48 | } 49 | 50 | // Match copy 51 | // 2 bytes offset (little endian) 52 | var offset = input[i++] | (input[i++] << 8) 53 | 54 | // 0 is an invalid offset value 55 | if (offset === 0 || offset > j) return -(i-2) 56 | 57 | // length of match copy 58 | var match_length = (token & 0xf) 59 | var l = match_length + 240 60 | while (l === 255) { 61 | l = input[i++] 62 | match_length += l 63 | } 64 | 65 | // Copy the match 66 | var pos = j - offset // position of the match copy in the current output 67 | var end = j + match_length + 4 // minmatch = 4 68 | while (j < end) output[j++] = output[pos++] 69 | } 70 | 71 | return j 72 | } 73 | 74 | var 75 | maxInputSize = 0x7E000000 76 | , minMatch = 4 77 | // uint32() optimization 78 | , hashLog = 16 79 | , hashShift = (minMatch * 8) - hashLog 80 | , hashSize = 1 << hashLog 81 | 82 | , copyLength = 8 83 | , lastLiterals = 5 84 | , mfLimit = copyLength + minMatch 85 | , skipStrength = 6 86 | 87 | , mlBits = 4 88 | , mlMask = (1 << mlBits) - 1 89 | , runBits = 8 - mlBits 90 | , runMask = (1 << runBits) - 1 91 | 92 | , hasher = 2654435761 93 | 94 | // CompressBound returns the maximum length of a lz4 block, given it's uncompressed length 95 | exports.compressBound = function (isize) { 96 | return isize > maxInputSize 97 | ? 0 98 | : (isize + (isize/255) + 16) | 0 99 | } 100 | 101 | exports.compress = function (src, dst, sIdx, eIdx) { 102 | // V8 optimization: non sparse array with integers 103 | var hashTable = new Array(hashSize) 104 | for (var i = 0; i < hashSize; i++) { 105 | hashTable[i] = 0 106 | } 107 | return compressBlock(src, dst, 0, hashTable, sIdx || 0, eIdx || dst.length) 108 | } 109 | 110 | exports.compressHC = exports.compress 111 | 112 | exports.compressDependent = compressBlock 113 | 114 | function compressBlock (src, dst, pos, hashTable, sIdx, eIdx) { 115 | var dpos = sIdx 116 | var dlen = eIdx - sIdx 117 | var anchor = 0 118 | 119 | if (src.length >= maxInputSize) throw new Error("input too large") 120 | 121 | // Minimum of input bytes for compression (LZ4 specs) 122 | if (src.length > mfLimit) { 123 | var n = exports.compressBound(src.length) 124 | if ( dlen < n ) throw Error("output too small: " + dlen + " < " + n) 125 | 126 | var 127 | step = 1 128 | , findMatchAttempts = (1 << skipStrength) + 3 129 | // Keep last few bytes incompressible (LZ4 specs): 130 | // last 5 bytes must be literals 131 | , srcLength = src.length - mfLimit 132 | 133 | while (pos + minMatch < srcLength) { 134 | // Find a match 135 | // min match of 4 bytes aka sequence 136 | var sequenceLowBits = src[pos+1]<<8 | src[pos] 137 | var sequenceHighBits = src[pos+3]<<8 | src[pos+2] 138 | // compute hash for the current sequence 139 | var hash = Math.imul(sequenceLowBits | (sequenceHighBits << 16), hasher) >>> hashShift 140 | // get the position of the sequence matching the hash 141 | // NB. since 2 different sequences may have the same hash 142 | // it is double-checked below 143 | // do -1 to distinguish between initialized and uninitialized values 144 | var ref = hashTable[hash] - 1 145 | // save position of current sequence in hash table 146 | hashTable[hash] = pos + 1 147 | 148 | // first reference or within 64k limit or current sequence !== hashed one: no match 149 | if ( ref < 0 || 150 | ((pos - ref) >>> 16) > 0 || 151 | ( 152 | ((src[ref+3]<<8 | src[ref+2]) != sequenceHighBits) || 153 | ((src[ref+1]<<8 | src[ref]) != sequenceLowBits ) 154 | ) 155 | ) { 156 | // increase step if nothing found within limit 157 | step = findMatchAttempts++ >> skipStrength 158 | pos += step 159 | continue 160 | } 161 | 162 | findMatchAttempts = (1 << skipStrength) + 3 163 | 164 | // got a match 165 | var literals_length = pos - anchor 166 | var offset = pos - ref 167 | 168 | // minMatch already verified 169 | pos += minMatch 170 | ref += minMatch 171 | 172 | // move to the end of the match (>=minMatch) 173 | var match_length = pos 174 | while (pos < srcLength && src[pos] == src[ref]) { 175 | pos++ 176 | ref++ 177 | } 178 | 179 | // match length 180 | match_length = pos - match_length 181 | 182 | // token 183 | var token = match_length < mlMask ? match_length : mlMask 184 | 185 | // encode literals length 186 | if (literals_length >= runMask) { 187 | // add match length to the token 188 | dst[dpos++] = (runMask << mlBits) + token 189 | for (var len = literals_length - runMask; len > 254; len -= 255) { 190 | dst[dpos++] = 255 191 | } 192 | dst[dpos++] = len 193 | } else { 194 | // add match length to the token 195 | dst[dpos++] = (literals_length << mlBits) + token 196 | } 197 | 198 | // write literals 199 | for (var i = 0; i < literals_length; i++) { 200 | dst[dpos++] = src[anchor+i] 201 | } 202 | 203 | // encode offset 204 | dst[dpos++] = offset 205 | dst[dpos++] = (offset >> 8) 206 | 207 | // encode match length 208 | if (match_length >= mlMask) { 209 | match_length -= mlMask 210 | while (match_length >= 255) { 211 | match_length -= 255 212 | dst[dpos++] = 255 213 | } 214 | 215 | dst[dpos++] = match_length 216 | } 217 | 218 | anchor = pos 219 | } 220 | } 221 | 222 | // cannot compress input 223 | if (anchor == 0) return 0 224 | 225 | // Write last literals 226 | // encode literals length 227 | literals_length = src.length - anchor 228 | if (literals_length >= runMask) { 229 | // add match length to the token 230 | dst[dpos++] = (runMask << mlBits) 231 | for (var ln = literals_length - runMask; ln > 254; ln -= 255) { 232 | dst[dpos++] = 255 233 | } 234 | dst[dpos++] = ln 235 | } else { 236 | // add match length to the token 237 | dst[dpos++] = (literals_length << mlBits) 238 | } 239 | 240 | // write literals 241 | pos = anchor 242 | while (pos < src.length) { 243 | dst[dpos++] = src[pos++] 244 | } 245 | 246 | return dpos 247 | } 248 | -------------------------------------------------------------------------------- /lib/binding/lz4_binding.cc: -------------------------------------------------------------------------------- 1 | #define NAPI_VERSION 3 2 | #include 3 | 4 | #include "../../deps/lz4/lib/lz4.h" 5 | #include "../../deps/lz4/lib/lz4hc.h" 6 | 7 | //----------------------------------------------------------------------------- 8 | // LZ4 Compress 9 | //----------------------------------------------------------------------------- 10 | // Simple functions 11 | 12 | // {Buffer} input, {Buffer} output 13 | Napi::Value LZ4Compress(const Napi::CallbackInfo& info) { 14 | Napi::Env env = info.Env(); 15 | 16 | uint32_t alen = info.Length(); 17 | if (alen < 2 || alen > 4) { 18 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 19 | return env.Null(); 20 | } 21 | 22 | if (!info[0].IsBuffer() || !info[1].IsBuffer()) { 23 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 24 | return env.Null(); 25 | } 26 | Napi::Buffer input = info[0].As>(); 27 | Napi::Buffer output = info[1].As>(); 28 | 29 | Napi::Number result; 30 | uint32_t sIdx = 0; 31 | uint32_t eIdx = output.Length(); 32 | switch (alen) { 33 | case 4: 34 | if (!info[3].IsNumber()) { 35 | Napi::TypeError::New(env, "Invalid endIdx").ThrowAsJavaScriptException(); 36 | return env.Null(); 37 | } 38 | eIdx = info[3].As().Uint32Value(); 39 | // fall through 40 | [[fallthrough]]; 41 | case 3: 42 | if (!info[2].IsNumber()) { 43 | Napi::TypeError::New(env, "Invalid startIdx").ThrowAsJavaScriptException(); 44 | return env.Null(); 45 | } 46 | sIdx = info[2].As().Uint32Value(); 47 | // fall through 48 | [[fallthrough]]; 49 | case 2: 50 | result = Napi::Number::New(env, LZ4_compress_default(input.Data(), 51 | output.Data() + sIdx, 52 | input.Length(), 53 | eIdx - sIdx) 54 | ); 55 | } 56 | 57 | return result; 58 | } 59 | 60 | // {Buffer} input, {Buffer} output, {Integer} compressionLevel 61 | Napi::Value LZ4CompressHC(const Napi::CallbackInfo& info) { 62 | Napi::Env env = info.Env(); 63 | 64 | uint32_t alen = info.Length(); 65 | if (alen != 2 && alen != 3) { 66 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 67 | return env.Null(); 68 | } 69 | 70 | if (!info[0].IsBuffer() || !info[1].IsBuffer()) { 71 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 72 | return env.Null(); 73 | } 74 | 75 | Napi::Buffer input = info[0].As>(); 76 | Napi::Buffer output = info[1].As>(); 77 | uint32_t compressionLevel = info[2].IsNumber() ? info[2].As().Uint32Value() : 9; 78 | 79 | Napi::Number result = Napi::Number::New(env, LZ4_compress_HC(input.Data(), 80 | output.Data(), 81 | input.Length(), 82 | output.Length(), 83 | compressionLevel) 84 | ); 85 | return result; 86 | } 87 | 88 | // Advanced functions 89 | 90 | // {Integer} Buffer size 91 | Napi::Value LZ4CompressBound(const Napi::CallbackInfo& info) { 92 | Napi::Env env = info.Env(); 93 | 94 | if (info.Length() != 1) { 95 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 96 | return env.Null(); 97 | } 98 | 99 | if (!info[0].IsNumber()) { 100 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 101 | return env.Null(); 102 | } 103 | 104 | uint32_t size = info[0].As().Uint32Value(); 105 | 106 | return Napi::Number::New(env, LZ4_compressBound(size)); 107 | } 108 | 109 | // {Buffer} input, {Buffer} output, {Integer} maxOutputSize 110 | Napi::Value LZ4CompressLimited(const Napi::CallbackInfo& info) { 111 | Napi::Env env = info.Env(); 112 | 113 | if (info.Length() != 3) { 114 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 115 | return env.Null(); 116 | } 117 | 118 | if (!info[0].IsBuffer() || !info[1].IsBuffer()) { 119 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 120 | return env.Null(); 121 | } 122 | 123 | if (!info[2].IsNumber()) { 124 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 125 | return env.Null(); 126 | } 127 | 128 | Napi::Buffer input = info[0].As>(); 129 | Napi::Buffer output = info[1].As>(); 130 | uint32_t size = info[2].As().Uint32Value(); 131 | 132 | Napi::Number result = Napi::Number::New(env, LZ4_compress_default(input.Data(), 133 | output.Data(), 134 | input.Length(), 135 | size) 136 | ); 137 | return result; 138 | } 139 | 140 | // {Buffer} input, {Buffer} output, {Integer} maxOutputSize, {Integer} compressionLevel 141 | Napi::Value LZ4CompressHCLimited(const Napi::CallbackInfo& info) { 142 | Napi::Env env = info.Env(); 143 | 144 | uint32_t alen = info.Length(); 145 | if (alen != 3 && alen != 4) { 146 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 147 | return env.Null(); 148 | } 149 | 150 | if (!info[0].IsBuffer() || !info[1].IsBuffer()) { 151 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 152 | return env.Null(); 153 | } 154 | 155 | if (!info[2].IsNumber()) { 156 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 157 | return env.Null(); 158 | } 159 | 160 | Napi::Buffer input = info[0].As>(); 161 | Napi::Buffer output = info[1].As>(); 162 | uint32_t size = info[2].As().Uint32Value(); 163 | uint32_t compressionLevel = info[3].IsNumber() ? info[3].As().Uint32Value() : 9; 164 | 165 | Napi::Number result = Napi::Number::New(env, LZ4_compress_HC(input.Data(), 166 | output.Data(), 167 | input.Length(), 168 | size, 169 | compressionLevel) 170 | ); 171 | return result; 172 | } 173 | 174 | /* 175 | //----------------------------------------------------------------------------- 176 | // LZ4 Stream 177 | //----------------------------------------------------------------------------- 178 | // {Buffer} input 179 | Napi::Value LZ4Stream_create(const Napi::CallbackInfo& info) { 180 | Napi::Env env = info.Env(); 181 | 182 | if (info.Length() != 1) { 183 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 184 | return env.Null(); 185 | } 186 | 187 | if (!info[0].IsBuffer()) { 188 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 189 | return env.Null(); 190 | } 191 | 192 | Napi::Buffer input = info[0].As>(); 193 | 194 | void* p = LZ4_create(input.Data()); 195 | 196 | if (p == NULL) { 197 | return env.Null(); 198 | } 199 | 200 | Napi::Buffer handle = Napi::Buffer::New(env, (char *)p, LZ4_sizeofStreamState()); 201 | 202 | return handle; 203 | } 204 | 205 | // {Buffer} lz4 data struct, {Buffer} input, {Buffer} output 206 | Napi::Value LZ4Stream_compress_continue(const Napi::CallbackInfo& info) { 207 | Napi::Env env = info.Env(); 208 | 209 | if (info.Length() != 3) { 210 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 211 | return env.Null(); 212 | } 213 | 214 | if (!info[0].IsBuffer() || !info[1].IsBuffer() || !info[2].IsBuffer()) { 215 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 216 | return env.Null(); 217 | } 218 | 219 | Napi::Buffer lz4ds = info[0].As>(); 220 | Napi::Buffer input = info[1].As>(); 221 | Napi::Buffer output = info[2].As>(); 222 | 223 | Napi::Number result = Napi::Number::New(env, LZ4_compress_continue( 224 | (LZ4_stream_t*)lz4ds.Data(), 225 | input.Data(), 226 | output.Data(), 227 | input.Length()) 228 | ); 229 | return result; 230 | } 231 | 232 | // {Buffer} input, {Buffer} lz4 data struct 233 | Napi::Value LZ4Stream_slideInputBuffer(const Napi::CallbackInfo& info) { 234 | Napi::Env env = info.Env(); 235 | 236 | if (info.Length() != 2) { 237 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 238 | return env.Null(); 239 | } 240 | 241 | if (!info[0].IsBuffer() || !info[1].IsBuffer()) { 242 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 243 | return env.Null(); 244 | } 245 | 246 | Napi::Buffer lz4ds = info[0].As>(); 247 | Napi::Buffer input = info[1].As>(); 248 | 249 | // Pointer to the position into the input buffer where the next data block should go 250 | char* input_next_block = LZ4_slideInputBuffer(lz4ds.Data()); 251 | char* input_current = (char *)input.Data(); 252 | 253 | // Return the position of the next block 254 | return Napi::Number::New(env, (int)(input_next_block - input_current)); 255 | } 256 | 257 | // {Buffer} lz4 data struct 258 | Napi::Value LZ4Stream_free(const Napi::CallbackInfo& info) { 259 | Napi::Env env = info.Env(); 260 | 261 | if (info.Length() != 1) { 262 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 263 | return env.Null(); 264 | } 265 | 266 | if (!info[0].IsBuffer()) { 267 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 268 | return env.Null(); 269 | } 270 | 271 | Napi::Buffer lz4ds = info[0].As>(); 272 | int res = LZ4_freeStream( (LZ4_stream_t*) lz4ds .Data()); 273 | 274 | return Napi::Number::New(env, res); 275 | } 276 | */ 277 | //----------------------------------------------------------------------------- 278 | // LZ4 Uncompress 279 | //----------------------------------------------------------------------------- 280 | // {Buffer} input, {Buffer} output 281 | Napi::Value LZ4Uncompress(const Napi::CallbackInfo& info) { 282 | Napi::Env env = info.Env(); 283 | 284 | uint32_t alen = info.Length(); 285 | if (alen < 2 || alen > 4) { 286 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 287 | return env.Null(); 288 | } 289 | 290 | if (!info[0].IsBuffer() || !info[1].IsBuffer()) { 291 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 292 | return env.Null(); 293 | } 294 | Napi::Buffer input = info[0].As>(); 295 | Napi::Buffer output = info[1].As>(); 296 | 297 | Napi::Number result; 298 | uint32_t sIdx = 0; 299 | uint32_t eIdx = input.Length(); 300 | switch (alen) { 301 | case 4: 302 | if (!info[3].IsNumber()) { 303 | Napi::TypeError::New(env, "Invalid endIdx").ThrowAsJavaScriptException(); 304 | return env.Null(); 305 | } 306 | if (!info[2].IsNumber()) { 307 | Napi::TypeError::New(env, "Invalid startIdx").ThrowAsJavaScriptException(); 308 | return env.Null(); 309 | } 310 | sIdx = info[2].As().Uint32Value(); 311 | eIdx = info[3].As().Uint32Value(); 312 | result = Napi::Number::New(env, LZ4_decompress_safe(input.Data() + sIdx, 313 | output.Data(), 314 | eIdx - sIdx, 315 | output.Length()) 316 | ); 317 | break; 318 | case 3: 319 | if (!info[2].IsNumber()) { 320 | Napi::TypeError::New(env, "Invalid startIdx").ThrowAsJavaScriptException(); 321 | return env.Null(); 322 | } 323 | sIdx = info[2].As().Uint32Value(); 324 | [[fallthrough]]; 325 | case 2: 326 | result = Napi::Number::New(env, LZ4_decompress_safe(input.Data() + sIdx, 327 | output.Data(), 328 | eIdx - sIdx, 329 | output.Length()) 330 | ); 331 | } 332 | 333 | return result; 334 | } 335 | 336 | // {Buffer} input, {Buffer} output 337 | Napi::Value LZ4Uncompress_fast(const Napi::CallbackInfo& info) { 338 | Napi::Env env = info.Env(); 339 | 340 | if (info.Length() != 2) { 341 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 342 | return env.Null(); 343 | } 344 | 345 | if (!info[0].IsBuffer() || !info[1].IsBuffer()) { 346 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 347 | return env.Null(); 348 | } 349 | 350 | Napi::Buffer input = info[0].As>(); 351 | Napi::Buffer output = info[1].As>(); 352 | 353 | #pragma GCC diagnostic push 354 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 355 | Napi::Number result = Napi::Number::New(env, LZ4_decompress_fast(input.Data(), 356 | output.Data(), 357 | output.Length()) 358 | ); 359 | #pragma GCC diagnostic pop 360 | return result; 361 | } 362 | 363 | 364 | Napi::Object init_lz4(Napi::Env env, Napi::Object exports) { 365 | exports.Set(Napi::String::New(env, "compressBound"), Napi::Function::New(env, LZ4CompressBound)); 366 | exports.Set(Napi::String::New(env, "compress"), Napi::Function::New(env, LZ4Compress)); 367 | exports.Set(Napi::String::New(env, "compressLimited"), Napi::Function::New(env, LZ4CompressLimited)); 368 | 369 | // exports.Set(Napi::String::New(env, "lz4s_create"), Napi::Function::New(env, LZ4Stream_create)); 370 | // exports.Set(Napi::String::New(env, "lz4s_compress_continue"), Napi::Function::New(env, LZ4Stream_compress_continue)); 371 | // exports.Set(Napi::String::New(env, "lz4s_slide_input"), Napi::Function::New(env, LZ4Stream_slideInputBuffer)); 372 | // exports.Set(Napi::String::New(env, "lz4s_free"), Napi::Function::New(env, LZ4Stream_free)); 373 | 374 | exports.Set(Napi::String::New(env, "compressHC"), Napi::Function::New(env, LZ4CompressHC)); 375 | exports.Set(Napi::String::New(env, "compressHCLimited"), Napi::Function::New(env, LZ4CompressHCLimited)); 376 | 377 | exports.Set(Napi::String::New(env, "uncompress"), Napi::Function::New(env, LZ4Uncompress)); 378 | exports.Set(Napi::String::New(env, "uncompress_fast"), Napi::Function::New(env, LZ4Uncompress_fast)); 379 | 380 | return exports; 381 | } 382 | NODE_API_MODULE(lz4_binding, init_lz4); -------------------------------------------------------------------------------- /lib/binding/xxhash_binding.cc: -------------------------------------------------------------------------------- 1 | #define NAPI_VERSION 3 2 | #include 3 | 4 | #define XXH_PRIVATE_API 5 | 6 | #include "../../deps/lz4/lib/xxhash.h" 7 | 8 | //----------------------------------------------------------------------------- 9 | // xxHash 10 | //----------------------------------------------------------------------------- 11 | // {Buffer} input, {Integer} seed (optional) 12 | Napi::Value xxHash(const Napi::CallbackInfo &info) { 13 | Napi::Env env = info.Env(); 14 | 15 | if (info.Length() == 0) { 16 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 17 | return env.Null(); 18 | } 19 | 20 | if (!info[0].IsBuffer()) { 21 | Napi::TypeError::New(env, "Wrong argument: Buffer expected").ThrowAsJavaScriptException(); 22 | return env.Null(); 23 | } 24 | 25 | Napi::Buffer input = info[0].As>(); 26 | uint32_t seed = 0; 27 | if (info[1].IsNumber()) { 28 | seed = info[1].As().Uint32Value(); 29 | } 30 | 31 | Napi::Number result = Napi::Number::New(env, XXH32(input.Data(), 32 | input.Length(), 33 | seed) 34 | ); 35 | return result; 36 | } 37 | 38 | // {Integer} seed 39 | Napi::Value xxHash_init(const Napi::CallbackInfo &info) { 40 | Napi::Env env = info.Env(); 41 | 42 | if (info.Length() == 0) { 43 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 44 | return env.Null(); 45 | } 46 | 47 | if (!info[0].IsNumber()) { 48 | Napi::TypeError::New(env, "Wrong argument: Integer expected").ThrowAsJavaScriptException(); 49 | return env.Null(); 50 | } 51 | 52 | uint32_t seed = info[0].As().Uint32Value(); 53 | 54 | XXH32_state_t* state = XXH32_createState(); 55 | XXH32_reset(state, seed); 56 | Napi::Buffer handle = Napi::Buffer::New(env, (char *) state, sizeof(XXH32_state_t)); 57 | 58 | return handle; 59 | } 60 | 61 | // {Buffer} state {Buffer} input {Integer} seed 62 | Napi::Value xxHash_update(const Napi::CallbackInfo &info) { 63 | Napi::Env env = info.Env(); 64 | 65 | if (info.Length() != 2) { 66 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 67 | return env.Null(); 68 | } 69 | 70 | if (!info[0].IsBuffer() || !info[1].IsBuffer()) { 71 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 72 | return env.Null(); 73 | } 74 | 75 | Napi::Buffer data0 = info[0].As>(); 76 | Napi::Buffer data1 = info[1].As>(); 77 | 78 | int err_code = XXH32_update( 79 | (XXH32_state_t *) data0.Data(), 80 | data1.Data(), 81 | data1.Length() 82 | ); 83 | 84 | return Napi::Number::New(env, err_code); 85 | } 86 | 87 | // {Buffer} state 88 | Napi::Value xxHash_digest(const Napi::CallbackInfo &info) { 89 | Napi::Env env = info.Env(); 90 | 91 | if (info.Length() != 1) { 92 | Napi::Error::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); 93 | return env.Null(); 94 | } 95 | 96 | if (!info[0].IsBuffer()) { 97 | Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); 98 | return env.Null(); 99 | } 100 | 101 | Napi::Number res = Napi::Number::New(env, 102 | XXH32_digest((XXH32_state_t *) info[0].As>().Data()) 103 | ); 104 | 105 | return res; 106 | } 107 | 108 | Napi::Object init_xxhash(Napi::Env env, Napi::Object exports) { 109 | exports.Set(Napi::String::New(env, "xxHash"), Napi::Function::New(env, xxHash)); 110 | exports.Set(Napi::String::New(env, "init"), Napi::Function::New(env, xxHash_init)); 111 | exports.Set(Napi::String::New(env, "update"), Napi::Function::New(env, xxHash_update)); 112 | exports.Set(Napi::String::New(env, "digest"), Napi::Function::New(env, xxHash_digest)); 113 | 114 | return exports; 115 | } 116 | 117 | NODE_API_MODULE(xxhash, init_xxhash); -------------------------------------------------------------------------------- /lib/decoder.js: -------------------------------------------------------------------------------- 1 | var Decoder = require('./decoder_stream') 2 | 3 | /** 4 | Decode an LZ4 stream 5 | */ 6 | function LZ4_uncompress (input, options) { 7 | var output = [] 8 | var decoder = new Decoder(options) 9 | 10 | decoder.on('data', function (chunk) { 11 | output.push(chunk) 12 | }) 13 | 14 | decoder.end(input) 15 | 16 | return Buffer.concat(output) 17 | } 18 | 19 | exports.LZ4_uncompress = LZ4_uncompress -------------------------------------------------------------------------------- /lib/decoder_stream.js: -------------------------------------------------------------------------------- 1 | var Transform = require('stream').Transform 2 | var inherits = require('util').inherits 3 | 4 | var lz4_static = require('./static') 5 | var utils = lz4_static.utils 6 | var lz4_binding = utils.bindings 7 | var lz4_jsbinding = require('./binding') 8 | 9 | var STATES = lz4_static.STATES 10 | var SIZES = lz4_static.SIZES 11 | 12 | function Decoder (options) { 13 | if ( !(this instanceof Decoder) ) 14 | return new Decoder(options) 15 | 16 | Transform.call(this, options) 17 | // Options 18 | this.options = options || {} 19 | 20 | this.binding = this.options.useJS ? lz4_jsbinding : lz4_binding 21 | 22 | // Encoded data being processed 23 | this.buffer = null 24 | // Current position within the data 25 | this.pos = 0 26 | this.descriptor = null 27 | 28 | // Current state of the parsing 29 | this.state = STATES.MAGIC 30 | 31 | this.notEnoughData = false 32 | this.descriptorStart = 0 33 | this.streamSize = null 34 | this.dictId = null 35 | this.currentStreamChecksum = null 36 | this.dataBlockSize = 0 37 | this.skippableSize = 0 38 | } 39 | inherits(Decoder, Transform) 40 | 41 | Decoder.prototype._transform = function (data, encoding, done) { 42 | // Handle skippable data 43 | if (this.skippableSize > 0) { 44 | this.skippableSize -= data.length 45 | if (this.skippableSize > 0) { 46 | // More to skip 47 | done() 48 | return 49 | } 50 | 51 | data = data.slice(-this.skippableSize) 52 | this.skippableSize = 0 53 | this.state = STATES.MAGIC 54 | } 55 | // Buffer the incoming data 56 | this.buffer = this.buffer 57 | ? Buffer.concat( [ this.buffer, data ], this.buffer.length + data.length ) 58 | : data 59 | 60 | this._main(done) 61 | } 62 | 63 | Decoder.prototype.emit_Error = function (msg) { 64 | this.emit( 'error', new Error(msg + ' @' + this.pos) ) 65 | } 66 | 67 | Decoder.prototype.check_Size = function (n) { 68 | var delta = this.buffer.length - this.pos 69 | if (delta <= 0 || delta < n) { 70 | if (this.notEnoughData) this.emit_Error( 'Unexpected end of LZ4 stream' ) 71 | return true 72 | } 73 | 74 | this.pos += n 75 | return false 76 | } 77 | 78 | Decoder.prototype.read_MagicNumber = function () { 79 | var pos = this.pos 80 | if ( this.check_Size(SIZES.MAGIC) ) return true 81 | 82 | var magic = utils.readUInt32LE(this.buffer, pos) 83 | 84 | // Skippable chunk 85 | if ( (magic & 0xFFFFFFF0) === lz4_static.MAGICNUMBER_SKIPPABLE ) { 86 | this.state = STATES.SKIP_SIZE 87 | return 88 | } 89 | 90 | // LZ4 stream 91 | if ( magic !== lz4_static.MAGICNUMBER ) { 92 | this.pos = pos 93 | this.emit_Error( 'Invalid magic number: ' + magic.toString(16).toUpperCase() ) 94 | return true 95 | } 96 | 97 | this.state = STATES.DESCRIPTOR 98 | } 99 | 100 | Decoder.prototype.read_SkippableSize = function () { 101 | var pos = this.pos 102 | if ( this.check_Size(SIZES.SKIP_SIZE) ) return true 103 | this.state = STATES.SKIP_DATA 104 | this.skippableSize = utils.readUInt32LE(this.buffer, pos) 105 | } 106 | 107 | Decoder.prototype.read_Descriptor = function () { 108 | // Flags 109 | var pos = this.pos 110 | if ( this.check_Size(SIZES.DESCRIPTOR) ) return true 111 | 112 | this.descriptorStart = pos 113 | 114 | // version 115 | var descriptor_flg = this.buffer[pos] 116 | var version = descriptor_flg >> 6 117 | if ( version !== lz4_static.VERSION ) { 118 | this.pos = pos 119 | this.emit_Error( 'Invalid version: ' + version + ' != ' + lz4_static.VERSION ) 120 | return true 121 | } 122 | 123 | // flags 124 | // reserved bit should not be set 125 | if ( (descriptor_flg >> 1) & 0x1 ) { 126 | this.pos = pos 127 | this.emit_Error('Reserved bit set') 128 | return true 129 | } 130 | 131 | var blockMaxSizeIndex = (this.buffer[pos+1] >> 4) & 0x7 132 | var blockMaxSize = lz4_static.blockMaxSizes[ blockMaxSizeIndex ] 133 | if ( blockMaxSize === null ) { 134 | this.pos = pos 135 | this.emit_Error( 'Invalid block max size: ' + blockMaxSizeIndex ) 136 | return true 137 | } 138 | 139 | this.descriptor = { 140 | blockIndependence: Boolean( (descriptor_flg >> 5) & 0x1 ) 141 | , blockChecksum: Boolean( (descriptor_flg >> 4) & 0x1 ) 142 | , blockMaxSize: blockMaxSize 143 | , streamSize: Boolean( (descriptor_flg >> 3) & 0x1 ) 144 | , streamChecksum: Boolean( (descriptor_flg >> 2) & 0x1 ) 145 | , dict: Boolean( descriptor_flg & 0x1 ) 146 | , dictId: 0 147 | } 148 | 149 | this.state = STATES.SIZE 150 | } 151 | 152 | Decoder.prototype.read_Size = function () { 153 | if (this.descriptor.streamSize) { 154 | var pos = this.pos 155 | if ( this.check_Size(SIZES.SIZE) ) return true 156 | //TODO max size is unsigned 64 bits 157 | this.streamSize = this.buffer.slice(pos, pos + 8) 158 | } 159 | 160 | this.state = STATES.DICTID 161 | } 162 | 163 | Decoder.prototype.read_DictId = function () { 164 | if (this.descriptor.dictId) { 165 | var pos = this.pos 166 | if ( this.check_Size(SIZES.DICTID) ) return true 167 | this.dictId = utils.readUInt32LE(this.buffer, pos) 168 | } 169 | 170 | this.state = STATES.DESCRIPTOR_CHECKSUM 171 | } 172 | 173 | Decoder.prototype.read_DescriptorChecksum = function () { 174 | var pos = this.pos 175 | if ( this.check_Size(SIZES.DESCRIPTOR_CHECKSUM) ) return true 176 | 177 | var checksum = this.buffer[pos] 178 | var currentChecksum = utils.descriptorChecksum( this.buffer.slice(this.descriptorStart, pos) ) 179 | if (currentChecksum !== checksum) { 180 | this.pos = pos 181 | this.emit_Error( 'Invalid stream descriptor checksum' ) 182 | return true 183 | } 184 | 185 | this.state = STATES.DATABLOCK_SIZE 186 | } 187 | 188 | Decoder.prototype.read_DataBlockSize = function () { 189 | var pos = this.pos 190 | if ( this.check_Size(SIZES.DATABLOCK_SIZE) ) return true 191 | var datablock_size = utils.readUInt32LE(this.buffer, pos) 192 | // Uncompressed 193 | if ( datablock_size === lz4_static.EOS ) { 194 | this.state = STATES.EOS 195 | return 196 | } 197 | 198 | // if (datablock_size > this.descriptor.blockMaxSize) { 199 | // this.emit_Error( 'ASSERTION: invalid datablock_size: ' + datablock_size.toString(16).toUpperCase() + ' > ' + this.descriptor.blockMaxSize.toString(16).toUpperCase() ) 200 | // } 201 | this.dataBlockSize = datablock_size 202 | 203 | this.state = STATES.DATABLOCK_DATA 204 | } 205 | 206 | Decoder.prototype.read_DataBlockData = function () { 207 | var pos = this.pos 208 | var datablock_size = this.dataBlockSize 209 | if ( datablock_size & 0x80000000 ) { 210 | // Uncompressed size 211 | datablock_size = datablock_size & 0x7FFFFFFF 212 | } 213 | if ( this.check_Size(datablock_size) ) return true 214 | 215 | this.dataBlock = this.buffer.slice(pos, pos + datablock_size) 216 | 217 | this.state = STATES.DATABLOCK_CHECKSUM 218 | } 219 | 220 | Decoder.prototype.read_DataBlockChecksum = function () { 221 | var pos = this.pos 222 | if (this.descriptor.blockChecksum) { 223 | if ( this.check_Size(SIZES.DATABLOCK_CHECKSUM) ) return true 224 | var checksum = utils.readUInt32LE(this.buffer, this.pos-4) 225 | var currentChecksum = utils.blockChecksum( this.dataBlock ) 226 | if (currentChecksum !== checksum) { 227 | this.pos = pos 228 | this.emit_Error( 'Invalid block checksum' ) 229 | return true 230 | } 231 | } 232 | 233 | this.state = STATES.DATABLOCK_UNCOMPRESS 234 | } 235 | 236 | Decoder.prototype.uncompress_DataBlock = function () { 237 | var uncompressed 238 | // uncompressed? 239 | if ( this.dataBlockSize & 0x80000000 ) { 240 | uncompressed = this.dataBlock 241 | } else { 242 | uncompressed = Buffer.alloc(this.descriptor.blockMaxSize) 243 | var decodedSize = this.binding.uncompress( this.dataBlock, uncompressed ) 244 | if (decodedSize < 0) { 245 | this.emit_Error( 'Invalid data block: ' + (-decodedSize) ) 246 | return true 247 | } 248 | if ( decodedSize < this.descriptor.blockMaxSize ) 249 | uncompressed = uncompressed.slice(0, decodedSize) 250 | } 251 | this.dataBlock = null 252 | this.push( uncompressed ) 253 | 254 | // Stream checksum 255 | if (this.descriptor.streamChecksum) { 256 | this.currentStreamChecksum = utils.streamChecksum(uncompressed, this.currentStreamChecksum) 257 | } 258 | 259 | this.state = STATES.DATABLOCK_SIZE 260 | } 261 | 262 | Decoder.prototype.read_EOS = function () { 263 | if (this.descriptor.streamChecksum) { 264 | var pos = this.pos 265 | if ( this.check_Size(SIZES.EOS) ) return true 266 | var checksum = utils.readUInt32LE(this.buffer, pos) 267 | if ( checksum !== utils.streamChecksum(null, this.currentStreamChecksum) ) { 268 | this.pos = pos 269 | this.emit_Error( 'Invalid stream checksum: ' + checksum.toString(16).toUpperCase() ) 270 | return true 271 | } 272 | } 273 | 274 | this.state = STATES.MAGIC 275 | } 276 | 277 | Decoder.prototype._flush = function (done) { 278 | // Error on missing data as no more will be coming 279 | this.notEnoughData = true 280 | this._main(done) 281 | } 282 | 283 | Decoder.prototype._main = function (done) { 284 | var pos = this.pos 285 | var notEnoughData 286 | 287 | while ( !notEnoughData && this.pos < this.buffer.length ) { 288 | if (this.state === STATES.MAGIC) 289 | notEnoughData = this.read_MagicNumber() 290 | 291 | if (this.state === STATES.SKIP_SIZE) 292 | notEnoughData = this.read_SkippableSize() 293 | 294 | if (this.state === STATES.DESCRIPTOR) 295 | notEnoughData = this.read_Descriptor() 296 | 297 | if (this.state === STATES.SIZE) 298 | notEnoughData = this.read_Size() 299 | 300 | if (this.state === STATES.DICTID) 301 | notEnoughData = this.read_DictId() 302 | 303 | if (this.state === STATES.DESCRIPTOR_CHECKSUM) 304 | notEnoughData = this.read_DescriptorChecksum() 305 | 306 | if (this.state === STATES.DATABLOCK_SIZE) 307 | notEnoughData = this.read_DataBlockSize() 308 | 309 | if (this.state === STATES.DATABLOCK_DATA) 310 | notEnoughData = this.read_DataBlockData() 311 | 312 | if (this.state === STATES.DATABLOCK_CHECKSUM) 313 | notEnoughData = this.read_DataBlockChecksum() 314 | 315 | if (this.state === STATES.DATABLOCK_UNCOMPRESS) 316 | notEnoughData = this.uncompress_DataBlock() 317 | 318 | if (this.state === STATES.EOS) 319 | notEnoughData = this.read_EOS() 320 | } 321 | 322 | if (this.pos > pos) { 323 | this.buffer = this.buffer.slice(this.pos) 324 | this.pos = 0 325 | } 326 | 327 | done() 328 | } 329 | 330 | module.exports = Decoder 331 | -------------------------------------------------------------------------------- /lib/encoder.js: -------------------------------------------------------------------------------- 1 | var Encoder = require('./encoder_stream') 2 | 3 | /** 4 | Encode an LZ4 stream 5 | */ 6 | function LZ4_compress (input, options) { 7 | var output = [] 8 | var encoder = new Encoder(options) 9 | 10 | encoder.on('data', function (chunk) { 11 | output.push(chunk) 12 | }) 13 | 14 | encoder.end(input) 15 | 16 | return Buffer.concat(output) 17 | } 18 | 19 | exports.LZ4_compress = LZ4_compress 20 | -------------------------------------------------------------------------------- /lib/encoder_stream.js: -------------------------------------------------------------------------------- 1 | var Transform = require('stream').Transform 2 | var inherits = require('util').inherits 3 | 4 | var lz4_static = require('./static') 5 | var utils = lz4_static.utils 6 | var lz4_binding = utils.bindings 7 | var lz4_jsbinding = require('./binding') 8 | 9 | var STATES = lz4_static.STATES 10 | var SIZES = lz4_static.SIZES 11 | 12 | var defaultOptions = { 13 | blockIndependence: true 14 | , blockChecksum: false 15 | , blockMaxSize: 4<<20 16 | , streamSize: false 17 | , streamChecksum: true 18 | , dict: false 19 | , dictId: 0 20 | , highCompression: false 21 | } 22 | 23 | function Encoder (options) { 24 | if ( !(this instanceof Encoder) ) 25 | return new Encoder(options) 26 | 27 | Transform.call(this, options) 28 | 29 | // Set the options 30 | var o = options || defaultOptions 31 | if (o !== defaultOptions) 32 | Object.keys(defaultOptions).forEach(function (p) { 33 | if ( !o.hasOwnProperty(p) ) o[p] = defaultOptions[p] 34 | }) 35 | 36 | this.options = o 37 | 38 | this.binding = this.options.useJS ? lz4_jsbinding : lz4_binding 39 | this.compress = o.highCompression ? this.binding.compressHC : this.binding.compress 40 | 41 | // Build the stream descriptor from the options 42 | // flags 43 | var descriptor_flg = 0 44 | descriptor_flg = descriptor_flg | (lz4_static.VERSION << 6) // Version 45 | descriptor_flg = descriptor_flg | ((o.blockIndependence & 1) << 5) // Block independence 46 | descriptor_flg = descriptor_flg | ((o.blockChecksum & 1) << 4) // Block checksum 47 | descriptor_flg = descriptor_flg | ((o.streamSize & 1) << 3) // Stream size 48 | descriptor_flg = descriptor_flg | ((o.streamChecksum & 1) << 2) // Stream checksum 49 | // Reserved bit 50 | descriptor_flg = descriptor_flg | (o.dict & 1) // Preset dictionary 51 | 52 | // block maximum size 53 | var descriptor_bd = lz4_static.blockMaxSizes.indexOf(o.blockMaxSize) 54 | if (descriptor_bd < 0) 55 | throw new Error('Invalid blockMaxSize: ' + o.blockMaxSize) 56 | 57 | this.descriptor = { flg: descriptor_flg, bd: (descriptor_bd & 0x7) << 4 } 58 | 59 | // Data being processed 60 | this.buffer = [] 61 | this.length = 0 62 | 63 | this.first = true 64 | this.checksum = null 65 | } 66 | inherits(Encoder, Transform) 67 | 68 | // Header = magic number + stream descriptor 69 | Encoder.prototype.headerSize = function () { 70 | var streamSizeSize = this.options.streamSize ? SIZES.DESCRIPTOR : 0 71 | var dictSize = this.options.dict ? SIZES.DICTID : 0 72 | 73 | return SIZES.MAGIC + 1 + 1 + streamSizeSize + dictSize + 1 74 | } 75 | 76 | Encoder.prototype.header = function () { 77 | var headerSize = this.headerSize() 78 | var output = Buffer.alloc(headerSize) 79 | 80 | this.state = STATES.MAGIC 81 | output.writeInt32LE(lz4_static.MAGICNUMBER, 0) 82 | 83 | this.state = STATES.DESCRIPTOR 84 | var descriptor = output.slice(SIZES.MAGIC, output.length - 1) 85 | 86 | // Update the stream descriptor 87 | descriptor.writeUInt8(this.descriptor.flg, 0) 88 | descriptor.writeUInt8(this.descriptor.bd, 1) 89 | 90 | var pos = 2 91 | this.state = STATES.SIZE 92 | if (this.options.streamSize) { 93 | //TODO only 32bits size supported 94 | descriptor.writeInt32LE(0, pos) 95 | descriptor.writeInt32LE(this.size, pos + 4) 96 | pos += SIZES.SIZE 97 | } 98 | this.state = STATES.DICTID 99 | if (this.options.dict) { 100 | descriptor.writeInt32LE(this.dictId, pos) 101 | pos += SIZES.DICTID 102 | } 103 | 104 | this.state = STATES.DESCRIPTOR_CHECKSUM 105 | output.writeUInt8( 106 | utils.descriptorChecksum( descriptor ) 107 | , SIZES.MAGIC + pos 108 | ) 109 | 110 | return output 111 | } 112 | 113 | Encoder.prototype.update_Checksum = function (data) { 114 | // Calculate the stream checksum 115 | this.state = STATES.CHECKSUM_UPDATE 116 | if (this.options.streamChecksum) { 117 | this.checksum = utils.streamChecksum(data, this.checksum) 118 | } 119 | } 120 | 121 | Encoder.prototype.compress_DataBlock = function (data) { 122 | this.state = STATES.DATABLOCK_COMPRESS 123 | var dbChecksumSize = this.options.blockChecksum ? SIZES.DATABLOCK_CHECKSUM : 0 124 | var maxBufSize = this.binding.compressBound(data.length) 125 | var buf = Buffer.alloc( SIZES.DATABLOCK_SIZE + maxBufSize + dbChecksumSize ) 126 | var compressed = buf.slice(SIZES.DATABLOCK_SIZE, SIZES.DATABLOCK_SIZE + maxBufSize) 127 | var compressedSize = this.compress(data, compressed) 128 | 129 | // Set the block size 130 | this.state = STATES.DATABLOCK_SIZE 131 | // Block size shall never be larger than blockMaxSize 132 | // console.log("blockMaxSize", this.options.blockMaxSize, "compressedSize", compressedSize) 133 | if (compressedSize > 0 && compressedSize <= this.options.blockMaxSize) { 134 | // highest bit is 0 (compressed data) 135 | buf.writeUInt32LE(compressedSize, 0) 136 | buf = buf.slice(0, SIZES.DATABLOCK_SIZE + compressedSize + dbChecksumSize) 137 | } else { 138 | // Cannot compress the data, leave it as is 139 | // highest bit is 1 (uncompressed data) 140 | buf.writeInt32LE( 0x80000000 | data.length, 0) 141 | buf = buf.slice(0, SIZES.DATABLOCK_SIZE + data.length + dbChecksumSize) 142 | data.copy(buf, SIZES.DATABLOCK_SIZE); 143 | } 144 | 145 | // Set the block checksum 146 | this.state = STATES.DATABLOCK_CHECKSUM 147 | if (this.options.blockChecksum) { 148 | // xxHash checksum on undecoded data with a seed of 0 149 | var checksum = buf.slice(-dbChecksumSize) 150 | checksum.writeUInt32LE( utils.blockChecksum(buf.slice(SIZES.DATABLOCK_SIZE, -dbChecksumSize)), 0 ) 151 | } 152 | 153 | // Update the stream checksum 154 | this.update_Checksum(data) 155 | 156 | this.size += data.length 157 | 158 | return buf 159 | } 160 | 161 | Encoder.prototype._transform = function (data, encoding, done) { 162 | if (data) { 163 | // Buffer the incoming data 164 | this.buffer.push(data) 165 | this.length += data.length 166 | } 167 | 168 | // Stream header 169 | if (this.first) { 170 | this.push( this.header() ) 171 | this.first = false 172 | } 173 | 174 | var blockMaxSize = this.options.blockMaxSize 175 | // Not enough data for a block 176 | if ( this.length < blockMaxSize ) return done() 177 | 178 | // Build the data to be compressed 179 | var buf = Buffer.concat(this.buffer, this.length) 180 | 181 | for (var j = 0, i = buf.length; i >= blockMaxSize; i -= blockMaxSize, j += blockMaxSize) { 182 | // Compress the block 183 | this.push( this.compress_DataBlock( buf.slice(j, j + blockMaxSize) ) ) 184 | } 185 | 186 | // Set the remaining data 187 | if (i > 0) { 188 | this.buffer = [ buf.slice(j) ] 189 | this.length = this.buffer[0].length 190 | } else { 191 | this.buffer = [] 192 | this.length = 0 193 | } 194 | 195 | done() 196 | } 197 | 198 | Encoder.prototype._flush = function (done) { 199 | if (this.first) { 200 | this.push( this.header() ) 201 | this.first = false 202 | } 203 | 204 | if (this.length > 0) { 205 | var buf = Buffer.concat(this.buffer, this.length) 206 | this.buffer = [] 207 | this.length = 0 208 | var cc = this.compress_DataBlock(buf) 209 | this.push( cc ) 210 | } 211 | 212 | if (this.options.streamChecksum) { 213 | this.state = STATES.CHECKSUM 214 | var eos = Buffer.alloc(SIZES.EOS + SIZES.CHECKSUM) 215 | eos.writeUInt32LE( utils.streamChecksum(null, this.checksum), SIZES.EOS ) 216 | } else { 217 | var eos = Buffer.alloc(SIZES.EOS) 218 | } 219 | 220 | this.state = STATES.EOS 221 | eos.writeInt32LE(lz4_static.EOS, 0) 222 | this.push(eos) 223 | 224 | done() 225 | } 226 | 227 | module.exports = Encoder 228 | -------------------------------------------------------------------------------- /lib/lz4.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LZ4 based compression and decompression 3 | * Copyright (c) 2014 Pierre Curto 4 | * MIT Licensed 5 | */ 6 | 7 | module.exports = require('./static') 8 | 9 | module.exports.version = "0.5.1" 10 | module.exports.createDecoderStream = require('./decoder_stream') 11 | module.exports.decode = require('./decoder').LZ4_uncompress 12 | 13 | module.exports.createEncoderStream = require('./encoder_stream') 14 | module.exports.encode = require('./encoder').LZ4_compress 15 | 16 | // Expose block decoder and encoders 17 | var bindings = module.exports.utils.bindings 18 | 19 | module.exports.decodeBlock = bindings.uncompress 20 | 21 | module.exports.encodeBound = bindings.compressBound 22 | module.exports.encodeBlock = bindings.compress 23 | module.exports.encodeBlockHC = bindings.compressHC 24 | -------------------------------------------------------------------------------- /lib/lz4l.js: -------------------------------------------------------------------------------- 1 | lz4.js -------------------------------------------------------------------------------- /lib/static.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LZ4 based compression and decompression 3 | * Copyright (c) 2014 Pierre Curto 4 | * MIT Licensed 5 | */ 6 | 7 | // LZ4 stream constants 8 | exports.MAGICNUMBER = 0x184D2204 9 | exports.MAGICNUMBER_BUFFER = Buffer.alloc(4) 10 | exports.MAGICNUMBER_BUFFER.writeUInt32LE(exports.MAGICNUMBER, 0) 11 | 12 | exports.EOS = 0 13 | exports.EOS_BUFFER = Buffer.alloc(4) 14 | exports.EOS_BUFFER.writeUInt32LE(exports.EOS, 0) 15 | 16 | exports.VERSION = 1 17 | 18 | exports.MAGICNUMBER_SKIPPABLE = 0x184D2A50 19 | 20 | // n/a, n/a, n/a, n/a, 64KB, 256KB, 1MB, 4MB 21 | exports.blockMaxSizes = [ null, null, null, null, 64<<10, 256<<10, 1<<20, 4<<20 ] 22 | 23 | // Compressed file extension 24 | exports.extension = '.lz4' 25 | 26 | // Internal stream states 27 | exports.STATES = { 28 | // Compressed stream 29 | MAGIC: 0 30 | , DESCRIPTOR: 1 31 | , SIZE: 2 32 | , DICTID: 3 33 | , DESCRIPTOR_CHECKSUM: 4 34 | , DATABLOCK_SIZE: 5 35 | , DATABLOCK_DATA: 6 36 | , DATABLOCK_CHECKSUM: 7 37 | , DATABLOCK_UNCOMPRESS: 8 38 | , DATABLOCK_COMPRESS: 9 39 | , CHECKSUM: 10 40 | , CHECKSUM_UPDATE: 11 41 | , EOS: 90 42 | // Skippable chunk 43 | , SKIP_SIZE: 101 44 | , SKIP_DATA: 102 45 | } 46 | 47 | exports.SIZES = { 48 | MAGIC: 4 49 | , DESCRIPTOR: 2 50 | , SIZE: 8 51 | , DICTID: 4 52 | , DESCRIPTOR_CHECKSUM: 1 53 | , DATABLOCK_SIZE: 4 54 | , DATABLOCK_CHECKSUM: 4 55 | , CHECKSUM: 4 56 | , EOS: 4 57 | , SKIP_SIZE: 4 58 | } 59 | 60 | exports.utils = require('./utils') 61 | -------------------------------------------------------------------------------- /lib/utils-js.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Javascript emulated bindings 3 | */ 4 | var XXH = require('xxhashjs').h32 // XXX .h64 5 | 6 | var CHECKSUM_SEED = 0 7 | 8 | // Header checksum is second byte of xxhash using 0 as a seed 9 | exports.descriptorChecksum = function (d) { 10 | return (XXH(d, CHECKSUM_SEED).toNumber() >> 8) & 0xFF 11 | } 12 | 13 | exports.blockChecksum = function (d) { 14 | return XXH(d, CHECKSUM_SEED).toNumber() 15 | } 16 | 17 | exports.streamChecksum = function (d, c) { 18 | if (c === null) 19 | c = XXH(CHECKSUM_SEED) 20 | 21 | if (d === null) 22 | return c.digest().toNumber() 23 | 24 | return c.update(d) 25 | } 26 | 27 | // Provide simple readUInt32LE as the Buffer ones from node and browserify are incompatible 28 | exports.readUInt32LE = function (buffer, offset) { 29 | const val = (buffer[offset]) | 30 | (buffer[offset + 1] << 8) | 31 | (buffer[offset + 2] << 16) | 32 | (buffer[offset + 3] << 24) 33 | // bitwise operators operate on signed values, this trick returns the result unsigned 34 | return val >>> 0; 35 | } 36 | 37 | exports.bindings = require('./binding') 38 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Native bindings 3 | */ 4 | var XXH = require('../build/Release/xxhash') 5 | 6 | var CHECKSUM_SEED = 0 7 | 8 | // Header checksum is second byte of xxhash using 0 as a seed 9 | exports.descriptorChecksum = function (d) { 10 | return (XXH.xxHash(d, CHECKSUM_SEED) >> 8) & 0xFF 11 | } 12 | 13 | exports.blockChecksum = function (d) { 14 | return XXH.xxHash(d, CHECKSUM_SEED) 15 | } 16 | 17 | exports.streamChecksum = function (d, c) { 18 | if (c === null) 19 | c = XXH.init(CHECKSUM_SEED) 20 | 21 | if (d === null) 22 | return XXH.digest(c) 23 | 24 | XXH.update(c, d) 25 | 26 | return c 27 | } 28 | 29 | // Provide simple readUInt32LE as the Buffer ones from node and browserify are incompatible 30 | exports.readUInt32LE = function (buffer, offset) { 31 | // this is nodejs Buffer.readUInt32LE() implementation... 32 | const val = ((buffer[offset]) | 33 | (buffer[offset + 1] << 8) | 34 | (buffer[offset + 2] << 16)) + 35 | (buffer[offset + 3] * 0x1000000) 36 | // bitwise operators operate on signed values, this trick returns the result unsigned 37 | return val >>> 0; 38 | } 39 | 40 | exports.bindings = require('../build/Release/lz4') 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "Pierre Curto" 4 | }, 5 | "name": "lz4", 6 | "description": "LZ4 streaming compression and decompression", 7 | "keywords": [ 8 | "lz4", 9 | "compression", 10 | "decompression", 11 | "stream" 12 | ], 13 | "version": "0.6.3", 14 | "homepage": "http://github.com/pierrec/node-lz4", 15 | "repository": { 16 | "type": "git", 17 | "url": "git://github.com/pierrec/node-lz4.git" 18 | }, 19 | "main": "./lib/lz4.js", 20 | "browser": "./build/lz4.js", 21 | "bugs": { 22 | "url": "http://github.com/pierrec/node-lz4/issues" 23 | }, 24 | "gypfile": true, 25 | "licenses": [ 26 | { 27 | "type": "MIT", 28 | "url": "http://github.com/pierrec/node-lz4/raw/master/LICENSE" 29 | } 30 | ], 31 | "engines": { 32 | "node": ">= 10.13" 33 | }, 34 | "dependencies": { 35 | "buffer": "^5.2.1", 36 | "cuint": "^0.2.2", 37 | "node-addon-api": "^3.2.1", 38 | "xxhashjs": "^0.2.2" 39 | }, 40 | "devDependencies": { 41 | "benchmark": "^1.0.0", 42 | "browserify": "^16.2.3", 43 | "jasmine-core": "^2.2.0", 44 | "karma": "^0.12.31", 45 | "karma-chrome-launcher": "^0.1.7", 46 | "karma-cli": "0.0.4", 47 | "karma-firefox-launcher": "^0.1.4", 48 | "karma-jasmine": "^0.3.5", 49 | "karma-mocha": "^0.1.10", 50 | "minify": "^4.1.1", 51 | "mocha": "^2.2.4" 52 | }, 53 | "scripts": { 54 | "test": "mocha", 55 | "install": "node-gyp rebuild", 56 | "prepublish": "./build.sh" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/block-test.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var assert = require('assert') 3 | 4 | var lz4 = require('..') 5 | 6 | describe('LZ4 block encoder/decoder', function () { 7 | var decoded_data_valid = fs.readFileSync( __dirname + '/../data/test' ) 8 | 9 | it('should encode/decode data', function (done) { 10 | var encoded_data = Buffer.alloc( lz4.encodeBound(decoded_data_valid.length) ) 11 | var n = lz4.encodeBlock(decoded_data_valid, encoded_data) 12 | 13 | assert( n > 0 ) 14 | encoded_data = encoded_data.slice(0, n) 15 | 16 | var decoded_data = Buffer.alloc(decoded_data_valid.length) 17 | n = lz4.decodeBlock(encoded_data, decoded_data) 18 | assert( n === decoded_data_valid.length ) 19 | assert( decoded_data.toString() === decoded_data_valid.toString() ) 20 | 21 | done() 22 | }) 23 | 24 | }) -------------------------------------------------------------------------------- /test/browser/block.js: -------------------------------------------------------------------------------- 1 | describe('Browser block encoding/decoding', function () { 2 | var lz4 = require('lz4') 3 | var Buffer = require('buffer').Buffer 4 | 5 | describe('block', function () { 6 | it('should encode short uncompressible string', function () { 7 | lz4.encodeBlock(Buffer.from('Test'), Buffer.alloc(32)) 8 | }) 9 | 10 | it('should encode/decode test data', function () { 11 | var decoded_data_valid 12 | 13 | downloadDataFile('test', 'arraybuffer', function (response) { 14 | decoded_data_valid = Buffer.from(new Uint8Array(response)) 15 | }) 16 | 17 | runs(function () { 18 | expect(decoded_data_valid).toBeDefined() 19 | 20 | var encoded_data = Buffer.alloc(lz4.encodeBound(decoded_data_valid.length)) 21 | var decoded_data = Buffer.alloc(decoded_data_valid.length) 22 | 23 | expect(encoded_data).toBeDefined() 24 | expect(decoded_data).toBeDefined() 25 | 26 | var n = lz4.encodeBlock(decoded_data_valid, encoded_data) 27 | expect(n).toBeDefined() 28 | if (n > 0) { 29 | encoded_data = encoded_data.slice(0, n) 30 | n = lz4.decodeBlock(encoded_data, decoded_data) 31 | 32 | expect(n).toEqual(decoded_data_valid.length) 33 | 34 | decoded_data = decoded_data.slice(0, n) 35 | expect( decoded_data.toString() ).toEqual( decoded_data_valid.toString() ) 36 | } 37 | }) 38 | }) 39 | 40 | it('should encode/decode test data', function () { 41 | var decoded_data_valid 42 | 43 | downloadDataFile('test', 'arraybuffer', function (response) { 44 | decoded_data_valid = Buffer.from(new Uint8Array(response)) 45 | }) 46 | 47 | runs(function () { 48 | expect(decoded_data_valid).toBeDefined() 49 | 50 | var encoded_data = Buffer.alloc(lz4.encodeBound(decoded_data_valid.length) + 4) 51 | var decoded_data = Buffer.alloc(decoded_data_valid.length) 52 | 53 | expect(encoded_data).toBeDefined() 54 | expect(decoded_data).toBeDefined() 55 | 56 | var n = lz4.encodeBlock(decoded_data_valid, encoded_data, 4) 57 | expect(n).toBeDefined() 58 | if (n > 0) { 59 | encoded_data = encoded_data.slice(4, n) 60 | n = lz4.decodeBlock(encoded_data, decoded_data) 61 | 62 | expect(n).toEqual(decoded_data_valid.length) 63 | 64 | decoded_data = decoded_data.slice(0, n) 65 | expect( decoded_data.toString() ).toEqual( decoded_data_valid.toString() ) 66 | } 67 | }) 68 | }) 69 | }) 70 | }) -------------------------------------------------------------------------------- /test/browser/checksum.js: -------------------------------------------------------------------------------- 1 | describe('Browser checksum', function () { 2 | var lz4 = require('lz4') 3 | var Buffer = require('buffer').Buffer 4 | 5 | it('should encode/decode test data', function () { 6 | runs(function () { 7 | var data = Buffer.alloc(200) 8 | data.fill(0) 9 | 10 | lz4.decode(lz4.encode(data)) 11 | }) 12 | }) 13 | 14 | it('should encode/decode test data', function () { 15 | runs(function () { 16 | var data = Buffer.alloc(200) 17 | data.fill(16) 18 | 19 | lz4.decode(lz4.encode(data)) 20 | }) 21 | }) 22 | 23 | it('should encode/decode test data', function () { 24 | runs(function () { 25 | var data = Buffer.alloc(200) 26 | data.slice(0, 100).fill(0) 27 | data.slice(100).fill(16) 28 | 29 | lz4.decode(lz4.encode(data)) 30 | }) 31 | }) 32 | 33 | }) -------------------------------------------------------------------------------- /test/browser/decoder.js: -------------------------------------------------------------------------------- 1 | describe('Browser encoding', function () { 2 | var lz4 = require('lz4') 3 | var Buffer = require('buffer').Buffer 4 | 5 | describe('sync', function () { 6 | it('should be able to encode and decode collada file', function () { 7 | var text 8 | 9 | downloadDataFile('sphere.dae', 'text', function (response) { 10 | text = response 11 | }) 12 | 13 | runs(function () { 14 | expect(text).toBeDefined() 15 | var encoded_data = lz4.encode(text) 16 | expect(lz4.decode(encoded_data).toString()).toEqual(text) 17 | }) 18 | }) 19 | 20 | it('should decode collada file encoded by node.js', function () { 21 | var decoded_data, encoded_data 22 | 23 | downloadDataFile('sphere.dae', 'text', function (response) { 24 | decoded_data = response 25 | }) 26 | 27 | downloadDataFile('sphere.lz4.dat', 'arraybuffer', function (response) { 28 | encoded_data = Buffer.from(new Uint8Array(response)) 29 | }) 30 | 31 | runs(function () { 32 | expect(decoded_data).toBeDefined() 33 | expect(encoded_data).toBeDefined() 34 | expect(lz4.decode(encoded_data).toString()).toEqual(decoded_data) 35 | }) 36 | }) 37 | }) 38 | }) -------------------------------------------------------------------------------- /test/browser/encoder.js: -------------------------------------------------------------------------------- 1 | describe('Browser encoding', function () { 2 | var lz4 = require('lz4') 3 | var Buffer = require('buffer').Buffer 4 | 5 | describe('sync', function () { 6 | it('should encode short uncompressible string', function () { 7 | lz4.encode('Test') 8 | }) 9 | 10 | it('should encode test data', function () { 11 | var decoded_data, encoded_data 12 | 13 | downloadDataFile('test', 'text', function (response) { 14 | decoded_data = response 15 | }) 16 | 17 | downloadDataFile('test.lz4', 'arraybuffer', function (response) { 18 | encoded_data = Buffer.from(new Uint8Array(response)) 19 | }) 20 | 21 | runs(function () { 22 | expect(decoded_data).toBeDefined() 23 | expect(encoded_data).toBeDefined() 24 | expect(lz4.encode(decoded_data)).toBeDefined() 25 | }) 26 | }) 27 | }) 28 | }) -------------------------------------------------------------------------------- /test/browser/helpers/download_data_file.js: -------------------------------------------------------------------------------- 1 | function downloadDataFile(name, type, cb) { 2 | var loaded = false, 3 | xhr = new XMLHttpRequest() 4 | xhr.open('GET', '/base/data/' + name, true) 5 | xhr.responseType = type 6 | 7 | xhr.onload = function(e) { 8 | cb(this.response) 9 | loaded = true 10 | } 11 | 12 | xhr.send() 13 | waitsFor(function () { 14 | return loaded 15 | }) 16 | } -------------------------------------------------------------------------------- /test/browser/helpers/spec_helper.js: -------------------------------------------------------------------------------- 1 | beforeEach(function () { 2 | this.addMatchers({ 3 | toEqualBuffer: function (expected) { 4 | return Buffer.compare(this.actual, expected) 5 | } 6 | }); 7 | }); -------------------------------------------------------------------------------- /test/checksum-test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | 3 | 4 | describe('LZ4 checksum', function () { 5 | var lz4 = require('..') 6 | 7 | it('should encode/decode data', function () { 8 | var data = Buffer.alloc(200) 9 | data.fill(0) 10 | 11 | assert.deepEqual(lz4.decode(lz4.encode(data, { blockChecksum: true })), data) 12 | }) 13 | 14 | it('should encode/decode data', function () { 15 | var data = Buffer.alloc(200) 16 | data.fill(16) 17 | 18 | assert.deepEqual(lz4.decode(lz4.encode(data, { blockChecksum: true })), data) 19 | }) 20 | 21 | it('should encode/decode data', function () { 22 | var data = Buffer.alloc(200) 23 | data.slice(0, 100).fill(0) 24 | data.slice(100).fill(16) 25 | 26 | assert.deepEqual(lz4.decode(lz4.encode(data, { blockChecksum: true })), data) 27 | }) 28 | 29 | it('should encode/decode data #107', function () { 30 | const data = Buffer.from('Lorem ipsum dolor sit amet, consectetur adipiscing elit.') 31 | 32 | assert.deepEqual(lz4.decode(lz4.encode(data, { blockChecksum: true })), data) 33 | }) 34 | 35 | }) -------------------------------------------------------------------------------- /test/decode-test.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var assert = require('assert') 3 | var lz4 = require('..') 4 | 5 | describe('LZ4 decoder', function () { 6 | var decoded_data = fs.readFileSync( __dirname + '/../data/test' ).toString().replace(/\r/g, '') // cleanup line endings 7 | var decoded_data_medium = fs.readFileSync( __dirname + '/../data/test_medium' ).toString().replace(/\r/g, '') // cleanup line endings 8 | var encoded_data = fs.readFileSync( __dirname + '/../data/test.lz4' ) 9 | 10 | describe('sync', function () { 11 | it('should decode data', function (done) { 12 | var decoded = lz4.decode(encoded_data) 13 | 14 | assert.equal( decoded_data, decoded.toString() ) 15 | done() 16 | }) 17 | }) 18 | 19 | describe('async', function () { 20 | it('should decode data', function (done) { 21 | var input = fs.createReadStream( __dirname + '/../data/test.lz4' ) 22 | var decoder = lz4.createDecoderStream() 23 | var decoded = '' 24 | 25 | function add (data) { 26 | if (data) decoded += data.toString() 27 | } 28 | decoder.on('data', add) 29 | decoder.on('end', add) 30 | decoder.on('end', function () { 31 | assert.equal( decoded_data, decoded ) 32 | done() 33 | }) 34 | 35 | input.pipe(decoder) 36 | }) 37 | 38 | it('should decode data with small stream chunks', function (done) { 39 | var input = fs.createReadStream( __dirname + '/../data/test_medium.lz4', { bufferSize: 1024 } ) 40 | var decoder = lz4.createDecoderStream() 41 | var decoded = '' 42 | 43 | function add (data) { 44 | if (data) decoded += data.toString() 45 | } 46 | decoder.on('data', add) 47 | decoder.on('end', add) 48 | decoder.on('end', function () { 49 | assert.equal( decoded_data_medium, decoded ) 50 | done() 51 | }) 52 | 53 | input.pipe(decoder) 54 | }) 55 | }) 56 | }) -------------------------------------------------------------------------------- /test/encode-test.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var assert = require('assert') 3 | 4 | var lz4 = require('..') 5 | 6 | describe('LZ4 encoder', function () { 7 | var decoded_data = fs.readFileSync( __dirname + '/../data/test' ) 8 | 9 | function compare (a, b) { 10 | if (a.length !== b.length) return false 11 | 12 | for (var i = 0, n = a.length; i < n; i++) { 13 | if (a[i] !== b[i]) return false 14 | } 15 | 16 | return true 17 | } 18 | 19 | describe('sync', function () { 20 | describe('empty', function () { 21 | it('should encode no data', function (done) { 22 | var empty = Buffer.from("") 23 | var encoded = lz4.encode(empty) 24 | 25 | assert( compare(lz4.decode(encoded), empty) ) 26 | done() 27 | }) 28 | }) 29 | 30 | describe('encoding', function () { 31 | it('should encode data', function (done) { 32 | var encoded = lz4.encode(decoded_data) 33 | 34 | assert( compare(lz4.decode(encoded), decoded_data) ) 35 | done() 36 | }) 37 | }) 38 | 39 | describe('HC encoding', function () { 40 | it('should encode data', function (done) { 41 | var encoded = lz4.encode(decoded_data, { highCompression: true }) 42 | 43 | assert( compare(lz4.decode(encoded), decoded_data) ) 44 | done() 45 | }) 46 | }) 47 | 48 | // https://github.com/pierrec/node-lz4/issues/69 49 | describe('HC block compression', function () { 50 | it('decoded should match with original', function (done) { 51 | var str = 'a'.repeat(81) + 'XXXXXX' + 'a'.repeat(65531) + 'XXXXXXaaaaaa' 52 | var input = Buffer.from(str) 53 | var output = Buffer.alloc(lz4.encodeBound(input.length)) 54 | var compressedSize = lz4.encodeBlockHC(input, output) 55 | output = output.slice(0, compressedSize) 56 | 57 | var uncompressed = Buffer.alloc(input.length) 58 | var uncompressedSize = lz4.decodeBlock(output, uncompressed) 59 | uncompressed = uncompressed.slice(0, uncompressedSize) 60 | 61 | assert( compare(input, uncompressed) ) 62 | done() 63 | }) 64 | }) 65 | }) 66 | 67 | describe('async', function () { 68 | describe('encoding', function () { 69 | it('should encode data', function (done) { 70 | var input = fs.createReadStream( __dirname + '/../data/test' ) 71 | var encoder = lz4.createEncoderStream() 72 | var encoded = [] 73 | 74 | function add (chunk) { 75 | if (chunk) encoded.push(chunk) 76 | } 77 | 78 | encoder.on('data', add) 79 | encoder.on('end', add) 80 | encoder.on('end', function () { 81 | assert( compare(lz4.decode(Buffer.concat(encoded)), decoded_data) ) 82 | done() 83 | }) 84 | 85 | input.pipe(encoder) 86 | }) 87 | }) 88 | 89 | describe('encoding with small chunk size', function () { 90 | it('should encode data', function (done) { 91 | var input = fs.createReadStream( __dirname + '/../data/test' ) 92 | var encoder = lz4.createEncoderStream({ blockMaxSize: 64<<10 }) 93 | var encoded = [] 94 | 95 | function add (chunk) { 96 | if (chunk) encoded.push(chunk) 97 | } 98 | 99 | encoder.on('data', add) 100 | encoder.on('end', add) 101 | encoder.on('end', function () { 102 | assert( compare(lz4.decode(Buffer.concat(encoded)), decoded_data) ) 103 | done() 104 | }) 105 | 106 | input.pipe(encoder) 107 | }) 108 | }) 109 | 110 | describe('HC encoding', function () { 111 | it('should encode data', function (done) { 112 | var input = fs.createReadStream( __dirname + '/../data/test' ) 113 | var encoder = lz4.createEncoderStream({ highCompression: true }) 114 | var encoded = [] 115 | 116 | function add (chunk) { 117 | if (chunk) encoded.push(chunk) 118 | } 119 | 120 | encoder.on('data', add) 121 | encoder.on('end', add) 122 | encoder.on('end', function () { 123 | assert( compare(lz4.decode(Buffer.concat(encoded)), decoded_data) ) 124 | done() 125 | }) 126 | 127 | input.pipe(encoder) 128 | }) 129 | }) 130 | }) 131 | }) 132 | -------------------------------------------------------------------------------- /test/jsencode_decode-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Javascript based encoding 3 | */ 4 | var fs = require('fs') 5 | var assert = require('assert') 6 | 7 | var lz4 = require('../lib/binding') 8 | 9 | describe('LZ4 js encoder', function () { 10 | 11 | function compare (a, b) { 12 | if (a.length !== b.length) return false 13 | 14 | for (var i = 0, n = a.length; i < n; i++) { 15 | if (a[i] !== b[i]) return false 16 | } 17 | 18 | return true 19 | } 20 | 21 | it('should encode/decode data', function (done) { 22 | var data = fs.readFileSync( __dirname + '/../data/test' ) 23 | var maxSize = lz4.compressBound(data.length) 24 | 25 | var jsencoded = Buffer.alloc(maxSize) 26 | var jsencodedSize = lz4.compress(data, jsencoded) 27 | 28 | assert( jsencodedSize > 0 ) 29 | jsencoded = jsencoded.slice(0, jsencodedSize) 30 | 31 | var jsdecoded = Buffer.alloc(data.length) 32 | var jsdecodedSize = lz4.uncompress(jsencoded, jsdecoded) 33 | 34 | assert( jsdecodedSize > 0 ) 35 | 36 | assert( 37 | compare( 38 | data 39 | , jsdecoded.slice(0, jsdecodedSize) 40 | ) 41 | ) 42 | done() 43 | }) 44 | 45 | //TODO node v0.10.26 seg faults on this test 46 | false&&it('should encode/decode data #2', function (done) { 47 | var data = Buffer.from("R0lGODlhDAAMAIAAAGZmZv///yH5BAEAAAEALAAAAAAMAAwAAAIYjI8BmbBsHIwPSsXuPbrSj3QRKIrKYl4FADs=") 48 | var maxSize = lz4.compressBound(data.length) 49 | 50 | var jsencoded = Buffer.alloc(maxSize) 51 | var jsencodedSize = lz4.compress(data, jsencoded) 52 | 53 | assert( jsencodedSize > 0 ) 54 | jsencoded = jsencoded.slice(0, jsencodedSize) 55 | 56 | var jsdecoded = Buffer.alloc(data.length) 57 | var jsdecodedSize = lz4.uncompress(jsencoded, jsdecoded) 58 | 59 | assert( jsdecodedSize > 0 ) 60 | 61 | assert( 62 | compare( 63 | data 64 | , jsdecoded.slice(0, jsdecodedSize) 65 | ) 66 | ) 67 | done() 68 | }) 69 | }) --------------------------------------------------------------------------------