├── .npmignore ├── tests ├── .eslintrc.json └── test.js ├── .github └── workflows │ └── ci.yml ├── LICENSE ├── package.json ├── .eslintrc.json ├── CHANGELOG.md ├── .gitignore ├── bin └── lzjs ├── README.md ├── lzjs.min.js └── lzjs.js /.npmignore: -------------------------------------------------------------------------------- 1 | **/.* 2 | docs/ 3 | tests/ 4 | node_modules/ 5 | .npmignore 6 | -------------------------------------------------------------------------------- /tests/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 13 4 | }, 5 | "env": { 6 | "node": true, 7 | "shared-node-browser": true, 8 | "mocha": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | permissions: 4 | contents: read 5 | 6 | jobs: 7 | test: 8 | strategy: 9 | matrix: 10 | os: [ubuntu-latest, windows-latest] 11 | node: [14, 16, 18] 12 | name: Test 13 | runs-on: ${{ matrix.os }} 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | 18 | - uses: actions/setup-node@v3 19 | name: Use Node.js ${{ matrix.node-version }} 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | 23 | - name: Install 24 | run: npm ci 25 | 26 | - name: Test 27 | run: npm run test 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 polygonplanet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lzjs", 3 | "version": "1.3.1", 4 | "description": "A JavaScript library for compressing and decompressing strings using an original algorithm based on the LZ algorithm", 5 | "main": "lzjs.js", 6 | "files": [ 7 | "lzjs.js", 8 | "lzjs.min.js" 9 | ], 10 | "directories": { 11 | "test": "tests" 12 | }, 13 | "devDependencies": { 14 | "eslint": "^8.56.0", 15 | "mocha": "^10.2.0", 16 | "uglify-js": "^3.17.4" 17 | }, 18 | "scripts": { 19 | "minify": "uglifyjs lzjs.js -o lzjs.min.js --comments -c -m -b ascii_only=true,beautify=false", 20 | "test": "eslint . && mocha tests/test.js" 21 | }, 22 | "engines": { 23 | "node": ">=14.15.0" 24 | }, 25 | "bin": { 26 | "lzjs": "bin/lzjs" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "git@github.com:polygonplanet/lzjs.git" 31 | }, 32 | "keywords": [ 33 | "compression", 34 | "lz77", 35 | "lzss", 36 | "base64", 37 | "string" 38 | ], 39 | "author": "polygonplanet", 40 | "license": "MIT", 41 | "bugs": { 42 | "url": "https://github.com/polygonplanet/lzjs/issues" 43 | }, 44 | "homepage": "https://github.com/polygonplanet/lzjs" 45 | } 46 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "root": true, 4 | "parserOptions": { 5 | "ecmaVersion": 5, 6 | "ecmaFeatures": { 7 | "globalReturn": true, 8 | "impliedStrict": true 9 | } 10 | }, 11 | "env": { 12 | "amd": true, 13 | "es6": true, 14 | "browser": true, 15 | "node": true, 16 | "shared-node-browser": true, 17 | "worker": true, 18 | "mocha": true 19 | }, 20 | "ignorePatterns": [ 21 | "lzjs.min.js" 22 | ], 23 | "rules": { 24 | "comma-dangle": ["error", "never"], 25 | "indent": [ 26 | "error", 2, { 27 | "ArrayExpression": 1, 28 | "ignoreComments": true, 29 | "ignoredNodes": ["ConditionalExpression"], 30 | "MemberExpression": 1, 31 | "ObjectExpression": 1, 32 | "outerIIFEBody": "off", 33 | "SwitchCase": 1, 34 | "VariableDeclarator": "first" 35 | } 36 | ], 37 | "key-spacing": [ 38 | "error", { 39 | "beforeColon": false, 40 | "afterColon": true 41 | } 42 | ], 43 | "keyword-spacing": "error", 44 | "max-len": [ 45 | "error", { 46 | "code": 120, 47 | "tabWidth": 2, 48 | "ignoreUrls": true, 49 | "ignoreStrings": true, 50 | "ignoreTemplateLiterals": true, 51 | "ignoreRegExpLiterals": true 52 | } 53 | ], 54 | "no-empty": "off", 55 | "no-mixed-spaces-and-tabs": "error", 56 | "no-multiple-empty-lines": ["error", { "max": 2 }], 57 | "no-unused-vars": ["error", { "args": "none" }], 58 | "no-tabs": "error", 59 | "no-useless-escape": "warn", 60 | "no-console": "warn", 61 | "no-undef": "error", 62 | "object-curly-spacing": ["error", "always", { "objectsInObjects": false }], 63 | "quotes": ["error", "single", { "allowTemplateLiterals": true, "avoidEscape": true }], 64 | "quote-props": ["error", "consistent-as-needed", { "keywords": true }], 65 | "semi": "error", 66 | "space-infix-ops": "error", 67 | "space-unary-ops": "error" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [1.3.1](https://github.com/polygonplanet/lzjs/compare/1.3.0...1.3.1) (2023-06-13) 6 | 7 | ### Added 8 | - Add `.eslint.json` ([0aa4513](https://github.com/polygonplanet/lzjs/commit/0aa45131ea33cd73cae9017ceeaab91d37589007)) 9 | - Add uglify-js and minify in scripts ([b09925b](https://github.com/polygonplanet/lzjs/commit/b09925bb49cea53ce06cc38c1a11b52368d94bc0)) 10 | 11 | ### Changed 12 | - Migrate CI from Travis to GitHub Actions ([76c67f6](https://github.com/polygonplanet/lzjs/commit/76c67f608d87cc514a1c67af15ba1ea8ed824298)) 13 | 14 | ### Removed 15 | - Drop bower support ([ee980ac](https://github.com/polygonplanet/lzjs/commit/ee980ac9951bb66b8fd8f267a3bb15a560c50e6c)) 16 | 17 | ## [1.3.0](https://github.com/polygonplanet/lzjs/compare/1.2.5...1.3.0) (2015-10-05) 18 | 19 | ### Added 20 | - Add bower ([370dbd9](https://github.com/polygonplanet/lzjs/commit/370dbd9c636d6c01788e90db57ee9b55735dbff0)) 21 | 22 | ### Fixed 23 | - Fix surrogate pairs ([3198c20](https://github.com/polygonplanet/lzjs/commit/3198c20d8f24949fca59411fdcdcf8bb299f7e81)) 24 | 25 | ## [1.2.5](https://github.com/polygonplanet/lzjs/compare/1.2.4...1.2.5) (2015-10-03) 26 | 27 | ### Fixed 28 | - Fix String.prototype.lastIndexOf bug in IE ([52a45f6](https://github.com/polygonplanet/lzjs/commit/52a45f6237e9f6a508e29db19ef7eca2ff7b2fe0)) 29 | 30 | ## [1.2.4](https://github.com/polygonplanet/lzjs/compare/1.2.3...1.2.4) (2014-12-15) 31 | 32 | ### Notes 33 | - No API changes in this release. 34 | 35 | ## [1.2.3](https://github.com/polygonplanet/lzjs/compare/1.2.0...1.2.3) (2014-11-26) 36 | 37 | ### Fixed 38 | - Fix CLI ([0310739](https://github.com/polygonplanet/lzjs/commit/0310739be9d06288a174b4eb1940312e65df4177)) 39 | 40 | ## [1.2.0](https://github.com/polygonplanet/lzjs/compare/1.1.0...1.2.0) (2014-11-26) 41 | 42 | ### Added 43 | - Add CLI ([47c7884](https://github.com/polygonplanet/lzjs/commit/47c788498bb00b0bce004e15292c2b00adaac025)) 44 | 45 | ## [1.1.0](https://github.com/polygonplanet/lzjs/compare/1.0.2...1.1.0) (2014-11-21) 46 | 47 | ### Added 48 | - Add compressBase64 and decompressBase64 ([c9d8e93](https://github.com/polygonplanet/lzjs/commit/c9d8e93f3eb710ebedc2b3d8dac8e53fa192ec33)) 49 | 50 | ### Fixed 51 | - Fix unicode chars ([c6d0683](https://github.com/polygonplanet/lzjs/commit/c6d06839c6ef2f7325dad9655a3c461b842f1343)) 52 | 53 | ## [1.0.2](https://github.com/polygonplanet/lzjs/releases/tag/1.0.2) (2014-11-10) 54 | 55 | ### Added 56 | - Initial release 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | 132 | # local 133 | bk 134 | docs 135 | local-test 136 | -------------------------------------------------------------------------------- /bin/lzjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /* eslint-disable no-console */ 4 | var lzjs = require('../lzjs'); 5 | var path = require('path'); 6 | var fs = require('fs'); 7 | 8 | var argv = process.argv.slice(2); 9 | var command, filename; 10 | 11 | switch (argv.length) { 12 | case 0: 13 | command = '-h'; 14 | break; 15 | case 1: 16 | command = argv[0]; 17 | filename = argv[1]; 18 | break; 19 | default: 20 | command = argv[0]; 21 | filename = argv[1]; 22 | break; 23 | } 24 | 25 | switch (command) { 26 | case '-v': 27 | case '--version': 28 | console.log('lzjs', require('../package.json').version); 29 | process.exit(0); 30 | break; 31 | case '-a': 32 | case '--add': 33 | compress(filename); 34 | process.exit(0); 35 | break; 36 | case '-x': 37 | case '--extract': 38 | decompress(filename); 39 | process.exit(0); 40 | break; 41 | case '-h': 42 | case '--help': 43 | default: 44 | help(); 45 | process.exit(0); 46 | break; 47 | } 48 | 49 | function compress(filename) { 50 | if (filename == null || filename.length === 0) { 51 | throw new Error('Missing argument .'); 52 | } 53 | 54 | var basename = path.basename(filename); 55 | if (basename == null || basename.length === 0) { 56 | throw new Error('Empty filename.'); 57 | } 58 | 59 | if (fs.statSync(filename).isDirectory()) { 60 | throw new Error('Cannot add to archive a directory.'); 61 | } 62 | 63 | var outputName = path.resolve( 64 | path.dirname(filename) + path.sep + basename + '.lzjs' 65 | ); 66 | 67 | var data = fs.readFileSync(filename); 68 | var compressed = lzjs.compress(data); 69 | fs.writeFileSync(outputName, compressed); 70 | } 71 | 72 | function decompress(filename) { 73 | if (filename == null || filename.length === 0) { 74 | throw new Error('Missing argument .'); 75 | } 76 | 77 | var basename = path.basename(filename); 78 | if (basename == null || basename.length === 0) { 79 | throw new Error('Empty filename'); 80 | } 81 | 82 | if (fs.statSync(filename).isDirectory()) { 83 | throw new Error('Cannot extract a directory.'); 84 | } 85 | 86 | var outputName = path.resolve( 87 | path.dirname(filename) + path.sep + path.basename(filename, '.lzjs') 88 | ); 89 | 90 | var data = fs.readFileSync(filename); 91 | var decompressed = lzjs.decompress(data); 92 | fs.writeFileSync(outputName, decompressed); 93 | } 94 | 95 | function help() { 96 | console.log('Usage: lzjs [file_name]'); 97 | console.log(''); 98 | console.log('Commands:'); 99 | console.log(' -h, --help show Help'); 100 | console.log(' -v, --version show Version'); 101 | console.log(' -a, --add Add file to archive'); 102 | console.log(' -x, --extract eXtract file'); 103 | } 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lzjs 2 | ======== 3 | 4 | [![GitHub Actions Build Status](https://github.com/polygonplanet/lzjs/actions/workflows/ci.yml/badge.svg)](https://github.com/polygonplanet/lzjs/actions) 5 | 6 | lzjs is a JavaScript library that compresses and decompresses strings using an original algorithm based on the LZ algorithm. 7 | 8 | This can be particularly useful when storing large amounts of data in storage with size limitations, such as localStorage or cookies. 9 | 10 | ## Installation 11 | 12 | ### npm 13 | 14 | ```bash 15 | $ npm install --save lzjs 16 | ``` 17 | 18 | #### using `import` 19 | 20 | ```javascript 21 | import lzjs from 'lzjs'; 22 | ``` 23 | 24 | #### using `require` 25 | 26 | ```javascript 27 | const lzjs = require('lzjs'); 28 | ``` 29 | 30 | ### browser (standalone) 31 | 32 | You can install the library via npm or download it from the [release list](https://github.com/polygonplanet/lzjs/tags). Use the `lzjs.js` or `lzjs.min.js` files included in the package. 33 | \*Please note that if you use `git clone`, even the *master* branch may be under development. 34 | 35 | ```html 36 | 37 | ``` 38 | or the minified `lzjs.min.js`: 39 | 40 | ```html 41 | 42 | ``` 43 | 44 | When the script is loaded, the `lzjs` object is defined in the global scope (i.e., `window.lzjs`). 45 | 46 | ## Demo 47 | 48 | * [lzjs compression demo](https://polygonplanet.github.io/lzjs/demo/) 49 | 50 | ## API 51 | 52 | * [compress](#lzjscompressdata-options) 53 | * [decompress](#lzjsdecompressdata-options) 54 | * [compressToBase64](#lzjscompresstobase64data) 55 | * [decompressFromBase64](#lzjsdecompressfrombase64data) 56 | 57 | ---- 58 | 59 | ### lzjs.compress(data, [options]) 60 | 61 | Compresses data into a binary string. 62 | 63 | #### Arguments 64 | 65 | * **data** *(string)* : Input data 66 | * **[options]** *(object)* : Compression options 67 | * **onData** *(function (data) {})* : Called when a data is chunked 68 | * **onEnd** *(function () {})* : Called when process ends 69 | 70 | #### Returns 71 | 72 | *(string)* : Compressed data 73 | 74 | #### Example 75 | 76 | Example of compressing and decompressing a string. 77 | 78 | ```javascript 79 | const data = 'hello hello hello'; 80 | const compressed = lzjs.compress(data); 81 | console.log(compressed); // 'Whello \x80\x82\x84\x86\x83' 82 | 83 | const decompressed = lzjs.decompress(compressed); 84 | console.log(decompressed === data); // true 85 | ``` 86 | 87 | Compress data using `onData` and `onEnd` events. 88 | 89 | ```javascript 90 | const string = 'hello hello hello'; 91 | const compressed = []; 92 | 93 | lzjs.compress(string, { 94 | onData: (data) => { 95 | compressed.push(data); 96 | }, 97 | onEnd: () => { 98 | console.log(compressed.join('')); // 'Whello \x80\x82\x84\x86\x83' 99 | } 100 | }); 101 | ``` 102 | 103 | ---- 104 | 105 | ### lzjs.decompress(data, [options]) 106 | 107 | Decompresses a string that has been compressed with [`lzjs.compress()`](#lzjscompressdata-options) 108 | 109 | #### Arguments 110 | 111 | * **data** *(string)* : Input data 112 | * **[options]** *(object)* : Decompression options 113 | * **onData** *(function (data) {})* : Called when a data is chunked 114 | * **onEnd** *(function () {})* : Called when process ends 115 | 116 | #### Returns 117 | 118 | *(string)* : Decompressed data 119 | 120 | #### Example 121 | 122 | Example of decompressing a string that has been compressed with [`lzjs.compress()`](#lzjscompressdata-options). 123 | 124 | ```javascript 125 | const decompressed = lzjs.decompress('Wabc\x80\x82\x81\x83\x83'); 126 | console.log(decompressed); // 'abcabcabcabcabc' 127 | ``` 128 | 129 | Decompress data using `onData` and `onEnd` events. 130 | 131 | ```javascript 132 | const compressed = 'Whello \x80\x82\x84\x86\x83'; 133 | const decompressed = []; 134 | 135 | lzjs.decompress(compressed, { 136 | onData: (data) => { 137 | decompressed.push(data); 138 | }, 139 | onEnd: () => { 140 | console.log(decompressed.join('')); // 'hello hello hello' 141 | } 142 | }); 143 | ``` 144 | 145 | ---- 146 | 147 | ### lzjs.compressToBase64(data) 148 | 149 | Compresses and encodes data into a Base64 string. 150 | 151 | #### Arguments 152 | 153 | * **data** *(string)* : Input data 154 | 155 | #### Returns 156 | 157 | *(string)* : Compressed and Base64 encoded string 158 | 159 | #### Example 160 | 161 | ```javascript 162 | const data = 'hello hello hello'; 163 | const compressed = lzjs.compressToBase64(data); 164 | console.log(compressed); // 'V2hlbGxvIMKAwoLChMKGwoM=' 165 | ``` 166 | 167 | ---- 168 | 169 | ### lzjs.decompressFromBase64(data) 170 | 171 | Decompresses a string that has been compressed with [`lzjs.compressToBase64()`](#lzjscompresstobase64data). 172 | 173 | #### Arguments 174 | 175 | * **data** *(string)* : Input data 176 | 177 | #### Returns 178 | 179 | *(string)* : Decompressed data 180 | 181 | #### Example 182 | 183 | ```javascript 184 | const decompressed = lzjs.decompressFromBase64('V2FiY8KAwoLCgcKDwoM='); 185 | console.log(decompressed); // 'abcabcabcabcabc' 186 | ``` 187 | 188 | ## Command line usage 189 | 190 | After `npm install -g lzjs` 191 | 192 | #### Add file to archive 193 | 194 | ```bash 195 | lzjs -a something.txt 196 | ``` 197 | 198 | #### Extract file 199 | 200 | ```bash 201 | lzjs -x something.txt.lzjs 202 | ``` 203 | 204 | ### All command line options 205 | 206 | ``` 207 | -h, --help show Help 208 | -v, --version show Version 209 | -a, --add Add file to archive 210 | -x, --extract eXtract file 211 | ``` 212 | 213 | Note that command line compression is only valid for the UTF-8 encoded file. 214 | 215 | ## Contributing 216 | 217 | We welcome contributions from everyone. 218 | For bug reports and feature requests, please [create an issue on GitHub](https://github.com/polygonplanet/lzjs/issues). 219 | 220 | ### Pull Requests 221 | 222 | Before submitting a pull request, please run `$ npm run test` to ensure there are no errors. 223 | We only accept pull requests that pass all tests. 224 | 225 | ## License 226 | 227 | This project is licensed under the terms of the MIT license. 228 | See the [LICENSE](LICENSE) file for details. 229 | -------------------------------------------------------------------------------- /tests/test.js: -------------------------------------------------------------------------------- 1 | const lzjs = require('../lzjs'); 2 | const assert = require('assert'); 3 | 4 | describe('lzjs test', () => { 5 | describe('compress and decompress', () => { 6 | it('should have compress and decompress methods', () => { 7 | assert(typeof lzjs.decompress === 'function'); 8 | assert(typeof lzjs.decompress === 'function'); 9 | }); 10 | 11 | describe('ASCII string', () => { 12 | let asciiStr = null; 13 | 14 | beforeEach(() => { 15 | asciiStr = 'Hello World.'; 16 | }); 17 | 18 | afterEach(() => { 19 | asciiStr = null; 20 | }); 21 | 22 | it('should correctly compress and decompress ASCII string', () => { 23 | assert(asciiStr.length > 0); 24 | const compressed = lzjs.compress(asciiStr); 25 | assert(compressed.length > 0); 26 | const decompressed = lzjs.decompress(compressed); 27 | assert.equal(decompressed, asciiStr); 28 | }); 29 | 30 | it('should correctly compress and decompress repeated ASCII', () => { 31 | const repeatedAsciiStr = new Array(6).join(asciiStr); 32 | assert(repeatedAsciiStr.length > 0); 33 | const compressed = lzjs.compress(repeatedAsciiStr); 34 | assert(compressed.length > 0); 35 | assert(repeatedAsciiStr.length > compressed.length); 36 | const decompressed = lzjs.decompress(compressed); 37 | assert.equal(decompressed, repeatedAsciiStr); 38 | }); 39 | }); 40 | 41 | describe('Unicode string [U+0000 - U+FFFF]', () => { 42 | let codeUnitStr = null; 43 | 44 | beforeEach(() => { 45 | codeUnitStr = ''; 46 | for (let i = 0; i <= 0xffff; i++) { 47 | codeUnitStr += String.fromCharCode(i); 48 | } 49 | }); 50 | 51 | afterEach(() => { 52 | codeUnitStr = null; 53 | }); 54 | 55 | it('should correctly compress and decompress Unicode string', () => { 56 | assert(codeUnitStr.length > 0); 57 | const compressed = lzjs.compress(codeUnitStr); 58 | assert(compressed.length > 0); 59 | const decompressed = lzjs.decompress(compressed); 60 | assert.equal(decompressed, codeUnitStr); 61 | }); 62 | 63 | it('should correctly compress and decompress repeated Unicode string', () => { 64 | const doubleCodeUnitStr = codeUnitStr + codeUnitStr; 65 | assert(doubleCodeUnitStr.length > 0); 66 | const compressed = lzjs.compress(doubleCodeUnitStr); 67 | assert(compressed.length > 0); 68 | const decompressed = lzjs.decompress(compressed); 69 | assert.equal(decompressed, doubleCodeUnitStr); 70 | }); 71 | }); 72 | 73 | describe('reversed Unicode string [U+0000 - U+FFFF]', () => { 74 | let reversedCodeUnitStr = null; 75 | 76 | beforeEach(() => { 77 | reversedCodeUnitStr = ''; 78 | for (let i = 0xffff; i >= 0; --i) { 79 | reversedCodeUnitStr += String.fromCharCode(i); 80 | } 81 | }); 82 | 83 | afterEach(() => { 84 | reversedCodeUnitStr = null; 85 | }); 86 | 87 | it('should correctly compress and decompress reversed Unicode string', () => { 88 | assert(reversedCodeUnitStr.length > 0); 89 | const compressed = lzjs.compress(reversedCodeUnitStr); 90 | assert(compressed.length > 0); 91 | const decompressed = lzjs.decompress(compressed); 92 | assert.equal(decompressed, reversedCodeUnitStr); 93 | }); 94 | }); 95 | 96 | describe('Unicode characters [U+0000 - U+FFFF]', () => { 97 | let codeUnitChars = null; 98 | 99 | beforeEach(() => { 100 | codeUnitChars = []; 101 | for (let i = 0; i <= 0xffff; i += 32) { 102 | codeUnitChars.push(new Array(100).join(String.fromCharCode(i))); 103 | } 104 | }); 105 | 106 | afterEach(() => { 107 | codeUnitChars = null; 108 | }); 109 | 110 | it('should correctly compress and decompress Unicode characters', () => { 111 | codeUnitChars.forEach((c) => { 112 | assert(c.length > 0); 113 | const compressed = lzjs.compress(c); 114 | assert(compressed.length > 0); 115 | const decompressed = lzjs.decompress(compressed); 116 | assert.equal(decompressed, c); 117 | 118 | const repeatedChars = new Array(10).join(c); 119 | assert.equal(lzjs.decompress(lzjs.compress(repeatedChars)), repeatedChars); 120 | }); 121 | }); 122 | }); 123 | 124 | describe('Repeated characters', () => { 125 | let asciiBits = null; 126 | let nonAsciiBits = null; 127 | 128 | beforeEach(() => { 129 | asciiBits = []; 130 | 131 | // Make repeated characters for a specific number of times 132 | const max = 60 * (60 + 1); 133 | const bits = [59, 60, 61, max - 1, max, max + 1]; 134 | for (let i = 0; i < bits.length; i++) { 135 | asciiBits.push(new Array(bits[i] + 1).join('a')); 136 | } 137 | 138 | nonAsciiBits = []; 139 | for (let i = 0; i < bits.length; i++) { 140 | nonAsciiBits.push(new Array(bits[i] + 1).join('a\u3042')); 141 | nonAsciiBits.push(new Array(bits[i] + 1).join('\u3042')); 142 | nonAsciiBits.push(new Array(bits[i] + 1).join('\u3042a')); 143 | } 144 | }); 145 | 146 | afterEach(() => { 147 | asciiBits = null; 148 | nonAsciiBits = null; 149 | }); 150 | 151 | it('should correctly compress and decompress repeated ASCII characters', () => { 152 | asciiBits.forEach((c) => { 153 | assert(c.length > 0); 154 | const compressed = lzjs.compress(c); 155 | assert(compressed.length > 0); 156 | const decompressed = lzjs.decompress(compressed); 157 | assert.equal(decompressed, c); 158 | }); 159 | }); 160 | 161 | it('should correctly compress and decompress repeated non-ASCII characters', () => { 162 | nonAsciiBits.forEach((c) => { 163 | assert(c.length > 0); 164 | const compressed = lzjs.compress(c); 165 | assert(compressed.length > 0); 166 | const decompressed = lzjs.decompress(compressed); 167 | assert.equal(decompressed, c); 168 | }); 169 | }); 170 | }); 171 | 172 | describe('ASCII string and Buffer', () => { 173 | let sampleStr = null; 174 | 175 | beforeEach(() => { 176 | sampleStr = 'Lorem ipsum dolor sit amet, Consectetur adipiscing. 123!@#$'; 177 | }); 178 | 179 | afterEach(() => { 180 | sampleStr = null; 181 | }); 182 | 183 | it('should correctly compress and decompress sample string', () => { 184 | assert(sampleStr.length > 0); 185 | const compressed = lzjs.compress(sampleStr); 186 | assert(compressed.length > 0); 187 | const decompressed = lzjs.decompress(compressed); 188 | assert.equal(decompressed, sampleStr); 189 | }); 190 | 191 | it('should correctly compress and decompress Buffer', () => { 192 | const sampleBuffer = Buffer.from(sampleStr); 193 | assert(sampleBuffer.length > 0); 194 | const compressed = lzjs.compress(sampleBuffer); 195 | assert(compressed.length > 0); 196 | const decompressed = lzjs.decompress(compressed); 197 | assert.equal(decompressed.toString(), sampleStr); 198 | }); 199 | }); 200 | }); 201 | 202 | describe('compressToBase64 and decompressFromBase64', () => { 203 | it('should have compressToBase64 and decompressFromBase64 methods', () => { 204 | assert(typeof lzjs.compressToBase64 === 'function'); 205 | assert(typeof lzjs.decompressFromBase64 === 'function'); 206 | }); 207 | 208 | it('should compress data to base64 string and decompress to original data', () => { 209 | const data = 'hello hello hello'; 210 | const compressed = lzjs.compressToBase64(data); 211 | assert.equal(compressed, 'V2hlbGxvIMKAwoLChMKGwoM='); 212 | 213 | const decompressed = lzjs.decompressFromBase64(compressed); 214 | assert.equal(decompressed, data); 215 | }); 216 | }); 217 | }); 218 | -------------------------------------------------------------------------------- /lzjs.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * lzjs v1.3.1 - compressing strings using an original algorithm based on the LZ algorithm 3 | * Copyright (c) 2014 polygonplanet 4 | * https://github.com/polygonplanet/lzjs 5 | * @license MIT 6 | */ 7 | !function(t,e,n){"undefined"!=typeof exports?"undefined"!=typeof module&&module.exports?module.exports=n():exports[t]=n():"function"==typeof define&&define.amd?define(n):e[t]=n()}("lzjs",this,function(){var g=String.fromCharCode,p=Object.prototype.hasOwnProperty,n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array,o=!1,l=!1;try{"a"===g.apply(null,[97])&&(o=!0)}catch(t){}if(n)try{"a"===g.apply(null,new Uint8Array([97]))&&(l=!0)}catch(t){}var c=65533,u=null,f=!1,r=(-1!=="abc\u307b\u3052".lastIndexOf("\u307b\u3052",1)&&(f=!0),function(){for(var t="",e={8:1,10:1,11:1,12:1,13:1,92:1},n=0;n<127;n++)p.call(e,n)||(t+=g(n));return t}()),d=r.length,t=Math.max(d,62)-Math.min(d,62),A=d-1,m=1024,_=c,y=_-d,s=c,b=s+2*m,C=40,v=1640,x=d+1,w=20+t,k=d+5,B=d-t-19;function h(t){this._init(t)}function e(t){this._init(t)}function D(t){this._init(t)}function S(t){this._init(t)}function E(){for(var t,e,n="abcdefghijklmnopqrstuvwxyz",r="",s=n.length,a=0;ac&&(u=!0);continue}catch(t){u=!1}return function(t){for(var e="",n=t.length,r=0;r>6&31,r[r.length]=128|63&e):e<65536?(r[r.length]=224|e>>12&15,r[r.length]=128|e>>6&63,r[r.length]=128|63&e):e<2097152&&(r[r.length]=240|e>>18&15,r[r.length]=128|e>>12&63,r[r.length]=128|e>>6&63,r[r.length]=128|63&e);return U(r)}function a(t){for(var e,n,r,s=[],a=0,i=t.length;a>4)&&e<=7?r=n:12==e||13==e?r=(31&n)<<6|63&t.charCodeAt(a++):14==e?r=(15&n)<<12|(63&t.charCodeAt(a++))<<6|63&t.charCodeAt(a++):15==e&&(r=(7&n)<<18|(63&t.charCodeAt(a++))<<12|(63&t.charCodeAt(a++))<<6|63&t.charCodeAt(a++)),r<=65535?s[s.length]=r:(s[s.length]=55296+((r-=65536)>>10),s[s.length]=r%1024+56320);return U(s)}function O(t){for(var e,n,r=0,s=0,a=t.length;sthis._maxBytes)return!1;y<=o&&(this._onData(h,o),o=0)}return 0h&&(o.length=h),l=o.length,0=h));n++);d=null}this._result.length>=b&&this._onData()}return this._result=this._result.slice(m),this._onData(!0),this._onEnd(),e=U(this._result),this._result=null,e}},D.prototype={_init:function(t){this._codeStart=(t=t||{}).codeStart||255,this._codeMax=t.codeMax||65535,this._maxBytes=t.maxBytes},compress:function(t){if(null==t||0===t.length)return"";var e,n,r,s,a="",i=0,h=0,o=t.length,l="",c=this._codeStart+1,u=this._codeMax,f=2,d=[],_=0;for(0this._maxBytes)return!1;c<=u&&(r=1<<(s=(n=l+e).length),(s<32&&!(_&r)||32<=s&&void 0===d[s])&&(d[s]={},_|=r),d[s][n]=g(c++),2048===c)&&(f=3),l=e}return 1===l.length?(a+=l,i++):(a+=d[l.length][l],i+=f),!(i>this._maxBytes)&&a},decompress:function(t){if(null==t||0===t.length)return"";var e,n,r,s,a="",i={},h=this._codeStart+1,o=this._codeStart,l=0,c=t.length;for(0n)&&(i="N",e=t),i+e)},decompress:function(t){if(null==t||0===t.length)return"";switch((t=""+t).charAt(0)){case"S":return this._decompressByS(t.substring(1));case"W":return this._decompressByW(t.substring(1));case"U":return this._decompressByU(t.substring(1));case"N":return this._decompressByN(t.substring(1));default:return t}},_decompressByS:function(t){return(new e).decompress(t)},_decompressByW:function(t){return new D({codeStart:127,codeMax:2047}).decompress(t)},_decompressByU:function(t){return a((new D).decompress(t))},_decompressByN:function(t){return t}};var T="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",L=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1];return{compress:function(t,e){return new S(e).compress(t)},decompress:function(t,e){return new S(e).decompress(t)},compressToBase64:function(t,e){for(var n,r,s,a=N(new S(e).compress(t)),i=a.length,h=0,o="";h>2)+T.charAt((3&n)<<4)+"==";break}if(r=a.charCodeAt(h++),h===i){o+=T.charAt(n>>2)+T.charAt((3&n)<<4|(240&r)>>4)+T.charAt((15&r)<<2)+"=";break}s=a.charCodeAt(h++),o+=T.charAt(n>>2)+T.charAt((3&n)<<4|(240&r)>>4)+T.charAt((15&r)<<2|(192&s)>>6)+T.charAt(63&s)}return o},decompressFromBase64:function(t,e){return new S(e).decompress(a(function(t){for(var e,n,r,s,a=t.length,i=0,h="";i>4);do{if(61===(r=255&t.charCodeAt(i++)))return h}while(r=L[r],i>2);do{if(61===(s=255&t.charCodeAt(i++)))return h}while(s=L[s],i 4 | * https://github.com/polygonplanet/lzjs 5 | * @license MIT 6 | */ 7 | (function(name, context, factory) { 8 | // Supports UMD. AMD, CommonJS/Node.js and browser context 9 | if (typeof exports !== 'undefined') { 10 | if (typeof module !== 'undefined' && module.exports) { 11 | module.exports = factory(); 12 | } else { 13 | exports[name] = factory(); 14 | } 15 | } else if (typeof define === 'function' && define.amd) { 16 | define(factory); 17 | } else { 18 | context[name] = factory(); 19 | } 20 | }('lzjs', this, function() { 21 | var fromCharCode = String.fromCharCode; 22 | var hasOwnProperty = Object.prototype.hasOwnProperty; 23 | var HAS_TYPED = typeof Uint8Array !== 'undefined' && typeof Uint16Array !== 'undefined'; 24 | 25 | // Test for String.fromCharCode.apply 26 | var CAN_CHARCODE_APPLY = false; 27 | var CAN_CHARCODE_APPLY_TYPED = false; 28 | 29 | try { 30 | if (fromCharCode.apply(null, [0x61]) === 'a') { 31 | CAN_CHARCODE_APPLY = true; 32 | } 33 | } catch (e) {} 34 | 35 | if (HAS_TYPED) { 36 | try { 37 | if (fromCharCode.apply(null, new Uint8Array([0x61])) === 'a') { 38 | CAN_CHARCODE_APPLY_TYPED = true; 39 | } 40 | } catch (e) {} 41 | } 42 | 43 | // Stack maximum range of Function.prototype.apply 44 | var APPLY_BUFFER_SIZE = 65533; 45 | var APPLY_BUFFER_SIZE_OK = null; 46 | 47 | // IE has a bug in String.prototype.lastIndexOf when the second argument is specified 48 | var STRING_LASTINDEXOF_BUG = false; 49 | if ('abc\u307b\u3052'.lastIndexOf('\u307b\u3052', 1) !== -1) { 50 | STRING_LASTINDEXOF_BUG = true; 51 | } 52 | 53 | var TABLE = (function() { 54 | var table = ''; 55 | var esc = { 56 | 0x8: 1, 57 | 0xa: 1, 58 | 0xb: 1, 59 | 0xc: 1, 60 | 0xd: 1, 61 | 0x5c: 1 62 | }; 63 | 64 | for (var i = 0; i < 0x7f; i++) { 65 | if (!hasOwnProperty.call(esc, i)) { 66 | table += fromCharCode(i); 67 | } 68 | } 69 | 70 | return table; 71 | }()); 72 | 73 | // Buffers 74 | var TABLE_LENGTH = TABLE.length; 75 | var TABLE_DIFF = Math.max(TABLE_LENGTH, 62) - Math.min(TABLE_LENGTH, 62); 76 | var BUFFER_MAX = TABLE_LENGTH - 1; 77 | // var TABLE_BUFFER_MAX = BUFFER_MAX * (BUFFER_MAX + 1); 78 | 79 | // Sliding Window 80 | var WINDOW_MAX = 1024; 81 | var WINDOW_BUFFER_MAX = 304; // maximum 304 82 | 83 | // Chunk buffer length 84 | var COMPRESS_CHUNK_SIZE = APPLY_BUFFER_SIZE; 85 | var COMPRESS_CHUNK_MAX = COMPRESS_CHUNK_SIZE - TABLE_LENGTH; 86 | var DECOMPRESS_CHUNK_SIZE = APPLY_BUFFER_SIZE; 87 | var DECOMPRESS_CHUNK_MAX = DECOMPRESS_CHUNK_SIZE + WINDOW_MAX * 2; 88 | 89 | // Unicode table : U+0000 - U+0084 90 | var LATIN_CHAR_MAX = 11; 91 | var LATIN_BUFFER_MAX = LATIN_CHAR_MAX * (LATIN_CHAR_MAX + 1); 92 | 93 | // Unicode table : U+0000 - U+FFFF 94 | var UNICODE_CHAR_MAX = 40; 95 | var UNICODE_BUFFER_MAX = UNICODE_CHAR_MAX * (UNICODE_CHAR_MAX + 1); 96 | 97 | // Index positions 98 | var LATIN_INDEX = TABLE_LENGTH + 1; 99 | var LATIN_INDEX_START = TABLE_DIFF + 20; 100 | var UNICODE_INDEX = TABLE_LENGTH + 5; 101 | 102 | // Decode/Start positions 103 | var DECODE_MAX = TABLE_LENGTH - TABLE_DIFF - 19; 104 | var LATIN_DECODE_MAX = UNICODE_CHAR_MAX + 7; 105 | var CHAR_START = LATIN_DECODE_MAX + 1; 106 | var COMPRESS_START = CHAR_START + 1; 107 | var COMPRESS_FIXED_START = COMPRESS_START + 5; 108 | var COMPRESS_INDEX = COMPRESS_FIXED_START + 5; // 59 109 | 110 | // LZSS Compressor is based on the lzbase62 v1.4.6 (MIT license) compression algorithm 111 | // https://github.com/polygonplanet/lzbase62 112 | function LZSSCompressor(options) { 113 | this._init(options); 114 | } 115 | 116 | LZSSCompressor.prototype = { 117 | _init: function(options) { 118 | options = options || {}; 119 | 120 | this._data = null; 121 | this._table = null; 122 | this._result = null; 123 | this._onDataCallback = options.onData; 124 | this._onEndCallback = options.onEnd; 125 | this._maxBytes = options.maxBytes; 126 | }, 127 | _createTable: function() { 128 | var table = createBuffer(8, TABLE_LENGTH); 129 | for (var i = 0; i < TABLE_LENGTH; i++) { 130 | table[i] = TABLE.charCodeAt(i); 131 | } 132 | return table; 133 | }, 134 | _onData: function(buffer, length) { 135 | var data = bufferToString_fast(buffer, length); 136 | 137 | if (this._onDataCallback) { 138 | this._onDataCallback(data); 139 | } else { 140 | this._result += data; 141 | } 142 | }, 143 | _onEnd: function() { 144 | if (this._onEndCallback) { 145 | this._onEndCallback(); 146 | } 147 | this._data = this._table = null; 148 | }, 149 | // Searches for a longest match 150 | _search: function() { 151 | var i = 2; 152 | var data = this._data; 153 | var offset = this._offset; 154 | var len = BUFFER_MAX; 155 | if (this._dataLen - offset < len) { 156 | len = this._dataLen - offset; 157 | } 158 | if (i > len) { 159 | return false; 160 | } 161 | 162 | var pos = offset - WINDOW_BUFFER_MAX; 163 | var win = data.substring(pos, offset + len); 164 | var limit = offset + i - 3 - pos; 165 | var j, s, index, lastIndex, bestIndex, winPart; 166 | 167 | do { 168 | if (i === 2) { 169 | s = data.charAt(offset) + data.charAt(offset + 1); 170 | 171 | // Faster check by pre-matching slow lastIndexOf 172 | index = win.indexOf(s); 173 | if (index === -1 || index > limit) { 174 | break; 175 | } 176 | } else if (i === 3) { 177 | s = s + data.charAt(offset + 2); 178 | } else { 179 | s = data.substr(offset, i); 180 | } 181 | 182 | if (STRING_LASTINDEXOF_BUG) { 183 | winPart = data.substring(pos, offset + i - 1); 184 | lastIndex = winPart.lastIndexOf(s); 185 | } else { 186 | lastIndex = win.lastIndexOf(s, limit); 187 | } 188 | 189 | if (lastIndex === -1) { 190 | break; 191 | } 192 | 193 | bestIndex = lastIndex; 194 | j = pos + lastIndex; 195 | do { 196 | if (data.charCodeAt(offset + i) !== data.charCodeAt(j + i)) { 197 | break; 198 | } 199 | } while (++i < len); 200 | 201 | if (index === lastIndex) { 202 | i++; 203 | break; 204 | } 205 | 206 | } while (++i < len); 207 | 208 | if (i === 2) { 209 | return false; 210 | } 211 | 212 | this._index = WINDOW_BUFFER_MAX - bestIndex; 213 | this._length = i - 1; 214 | return true; 215 | }, 216 | compress: function(data) { 217 | if (data == null || data.length === 0) { 218 | return ''; 219 | } 220 | 221 | var result = ''; 222 | var table = this._createTable(); 223 | var win = createWindow(); 224 | var buffer = createBuffer(8, COMPRESS_CHUNK_SIZE); 225 | var i = 0; 226 | var bytes = 0; 227 | 228 | this._result = ''; 229 | this._offset = win.length; 230 | this._data = win + data; 231 | this._dataLen = this._data.length; 232 | win = data = null; 233 | 234 | var index = -1; 235 | var lastIndex = -1; 236 | var c, c1, c2, c3, c4; 237 | 238 | while (this._offset < this._dataLen) { 239 | if (!this._search()) { 240 | c = this._data.charCodeAt(this._offset++); 241 | if (c < LATIN_BUFFER_MAX) { 242 | if (c < UNICODE_CHAR_MAX) { 243 | c1 = c; 244 | c2 = 0; 245 | index = LATIN_INDEX; 246 | } else { 247 | c1 = c % UNICODE_CHAR_MAX; 248 | c2 = (c - c1) / UNICODE_CHAR_MAX; 249 | index = c2 + LATIN_INDEX; 250 | } 251 | 252 | // Latin index 253 | if (lastIndex === index) { 254 | buffer[i++] = table[c1]; 255 | bytes++; 256 | } else { 257 | buffer[i++] = table[index - LATIN_INDEX_START]; 258 | buffer[i++] = table[c1]; 259 | bytes += 2; 260 | lastIndex = index; 261 | } 262 | } else { 263 | if (c < UNICODE_BUFFER_MAX) { 264 | c1 = c; 265 | c2 = 0; 266 | index = UNICODE_INDEX; 267 | } else { 268 | c1 = c % UNICODE_BUFFER_MAX; 269 | c2 = (c - c1) / UNICODE_BUFFER_MAX; 270 | index = c2 + UNICODE_INDEX; 271 | } 272 | 273 | if (c1 < UNICODE_CHAR_MAX) { 274 | c3 = c1; 275 | c4 = 0; 276 | } else { 277 | c3 = c1 % UNICODE_CHAR_MAX; 278 | c4 = (c1 - c3) / UNICODE_CHAR_MAX; 279 | } 280 | 281 | // Unicode index 282 | if (lastIndex === index) { 283 | buffer[i++] = table[c3]; 284 | buffer[i++] = table[c4]; 285 | bytes += 2; 286 | } else { 287 | buffer[i++] = table[CHAR_START]; 288 | buffer[i++] = table[index - TABLE_LENGTH]; 289 | buffer[i++] = table[c3]; 290 | buffer[i++] = table[c4]; 291 | bytes += 4; 292 | 293 | lastIndex = index; 294 | } 295 | } 296 | } else { 297 | if (this._index < BUFFER_MAX) { 298 | c1 = this._index; 299 | c2 = 0; 300 | } else { 301 | c1 = this._index % BUFFER_MAX; 302 | c2 = (this._index - c1) / BUFFER_MAX; 303 | } 304 | 305 | if (this._length === 2) { 306 | buffer[i++] = table[c2 + COMPRESS_FIXED_START]; 307 | buffer[i++] = table[c1]; 308 | bytes += 2; 309 | } else { 310 | buffer[i++] = table[c2 + COMPRESS_START]; 311 | buffer[i++] = table[c1]; 312 | buffer[i++] = table[this._length]; 313 | bytes += 3; 314 | } 315 | 316 | this._offset += this._length; 317 | if (~lastIndex) { 318 | lastIndex = -1; 319 | } 320 | } 321 | 322 | if (bytes > this._maxBytes) { 323 | return false; 324 | } 325 | 326 | if (i >= COMPRESS_CHUNK_MAX) { 327 | this._onData(buffer, i); 328 | i = 0; 329 | } 330 | } 331 | 332 | if (i > 0) { 333 | this._onData(buffer, i); 334 | } 335 | 336 | this._onEnd(); 337 | result = this._result; 338 | this._result = null; 339 | return result === null ? '' : result; 340 | } 341 | }; 342 | 343 | // LZSS Decompressor 344 | function LZSSDecompressor(options) { 345 | this._init(options); 346 | } 347 | 348 | LZSSDecompressor.prototype = { 349 | _init: function(options) { 350 | options = options || {}; 351 | 352 | this._result = null; 353 | this._onDataCallback = options.onData; 354 | this._onEndCallback = options.onEnd; 355 | }, 356 | _createTable: function() { 357 | var table = {}; 358 | for (var i = 0; i < TABLE_LENGTH; i++) { 359 | table[TABLE.charAt(i)] = i; 360 | } 361 | return table; 362 | }, 363 | _onData: function(ended) { 364 | var data; 365 | 366 | if (this._onDataCallback) { 367 | if (ended) { 368 | data = this._result; 369 | this._result = []; 370 | } else { 371 | var len = DECOMPRESS_CHUNK_SIZE - WINDOW_MAX; 372 | data = this._result.slice(WINDOW_MAX, WINDOW_MAX + len); 373 | 374 | this._result = this._result.slice(0, WINDOW_MAX).concat( 375 | this._result.slice(WINDOW_MAX + len)); 376 | } 377 | 378 | if (data.length > 0) { 379 | this._onDataCallback(bufferToString_fast(data)); 380 | } 381 | } 382 | }, 383 | _onEnd: function() { 384 | if (this._onEndCallback) { 385 | this._onEndCallback(); 386 | } 387 | }, 388 | decompress: function(data) { 389 | if (data == null || data.length === 0) { 390 | return ''; 391 | } 392 | 393 | this._result = stringToArray(createWindow()); 394 | var result = ''; 395 | var table = this._createTable(); 396 | 397 | var out = false; 398 | var index = null; 399 | var len = data.length; 400 | var offset = 0; 401 | 402 | var i, c, c2, c3; 403 | var code, pos, length, sub, subLen, expandLen; 404 | 405 | for (; offset < len; offset++) { 406 | c = table[data.charAt(offset)]; 407 | if (c === void 0) { 408 | continue; 409 | } 410 | 411 | if (c < DECODE_MAX) { 412 | if (!out) { 413 | // Latin index 414 | code = index * UNICODE_CHAR_MAX + c; 415 | } else { 416 | // Unicode index 417 | c3 = table[data.charAt(++offset)]; 418 | code = c3 * UNICODE_CHAR_MAX + c + UNICODE_BUFFER_MAX * index; 419 | } 420 | this._result[this._result.length] = code; 421 | } else if (c < LATIN_DECODE_MAX) { 422 | // Latin starting point 423 | index = c - DECODE_MAX; 424 | out = false; 425 | } else if (c === CHAR_START) { 426 | // Unicode starting point 427 | c2 = table[data.charAt(++offset)]; 428 | index = c2 - 5; 429 | out = true; 430 | } else if (c < COMPRESS_INDEX) { 431 | c2 = table[data.charAt(++offset)]; 432 | 433 | if (c < COMPRESS_FIXED_START) { 434 | pos = (c - COMPRESS_START) * BUFFER_MAX + c2; 435 | length = table[data.charAt(++offset)]; 436 | } else { 437 | pos = (c - COMPRESS_FIXED_START) * BUFFER_MAX + c2; 438 | length = 2; 439 | } 440 | 441 | sub = this._result.slice(-pos); 442 | if (sub.length > length) { 443 | sub.length = length; 444 | } 445 | subLen = sub.length; 446 | 447 | if (sub.length > 0) { 448 | expandLen = 0; 449 | while (expandLen < length) { 450 | for (i = 0; i < subLen; i++) { 451 | this._result[this._result.length] = sub[i]; 452 | if (++expandLen >= length) { 453 | break; 454 | } 455 | } 456 | } 457 | } 458 | index = null; 459 | } 460 | 461 | if (this._result.length >= DECOMPRESS_CHUNK_MAX) { 462 | this._onData(); 463 | } 464 | } 465 | 466 | this._result = this._result.slice(WINDOW_MAX); 467 | this._onData(true); 468 | this._onEnd(); 469 | 470 | result = bufferToString_fast(this._result); 471 | this._result = null; 472 | return result; 473 | } 474 | }; 475 | 476 | // LZW Compression 477 | function LZW(options) { 478 | this._init(options); 479 | } 480 | 481 | LZW.prototype = { 482 | _init: function(options) { 483 | options = options || {}; 484 | 485 | this._codeStart = options.codeStart || 0xff; 486 | this._codeMax = options.codeMax || 0xffff; 487 | this._maxBytes = options.maxBytes; 488 | }, 489 | compress: function(data) { 490 | if (data == null || data.length === 0) { 491 | return ''; 492 | } 493 | 494 | var result = ''; 495 | var resultBytes = 0; 496 | var i = 0; 497 | var len = data.length; 498 | var buffer = ''; 499 | var code = this._codeStart + 1; 500 | var codeMax = this._codeMax; 501 | var codeBytes = 2; 502 | 503 | var dict = []; 504 | var dictLen = 0; 505 | 506 | var c, key, bitLen, length; 507 | 508 | if (len > 0) { 509 | buffer = c = data.charAt(i++); 510 | } 511 | 512 | while (i < len) { 513 | c = data.charAt(i++); 514 | 515 | key = buffer + c; 516 | length = key.length; 517 | bitLen = 1 << length; 518 | 519 | if (((length < 32 && (dictLen & bitLen)) || 520 | (length >= 32 && dict[length] !== void 0)) && 521 | hasOwnProperty.call(dict[length], key)) { 522 | buffer += c; 523 | } else { 524 | if (buffer.length === 1) { 525 | result += buffer; 526 | resultBytes++; 527 | } else { 528 | result += dict[buffer.length][buffer]; 529 | resultBytes += codeBytes; 530 | } 531 | 532 | if (resultBytes > this._maxBytes) { 533 | return false; 534 | } 535 | 536 | if (code <= codeMax) { 537 | key = buffer + c; 538 | length = key.length; 539 | bitLen = 1 << length; 540 | 541 | if ((length < 32 && !(dictLen & bitLen)) || 542 | (length >= 32 && dict[length] === void 0)) { 543 | dict[length] = {}; 544 | dictLen |= bitLen; 545 | } 546 | 547 | dict[length][key] = fromCharCode(code++); 548 | if (code === 0x800) { 549 | codeBytes = 3; 550 | } 551 | } 552 | 553 | buffer = c; 554 | } 555 | } 556 | 557 | if (buffer.length === 1) { 558 | result += buffer; 559 | resultBytes++; 560 | } else { 561 | result += dict[buffer.length][buffer]; 562 | resultBytes += codeBytes; 563 | } 564 | 565 | if (resultBytes > this._maxBytes) { 566 | return false; 567 | } 568 | 569 | return result; 570 | }, 571 | decompress: function(data) { 572 | if (data == null || data.length === 0) { 573 | return ''; 574 | } 575 | 576 | var result = ''; 577 | 578 | var dict = {}; 579 | var code = this._codeStart + 1; 580 | var codeMax = this._codeStart; 581 | 582 | var i = 0; 583 | var len = data.length; 584 | var c, ch, prev, buffer; 585 | 586 | if (len > 0) { 587 | c = data.charCodeAt(i++); 588 | ch = fromCharCode(c); 589 | result += ch; 590 | prev = ch; 591 | } 592 | 593 | while (i < len) { 594 | c = data.charCodeAt(i++); 595 | 596 | if (c <= codeMax) { 597 | buffer = fromCharCode(c); 598 | } else { 599 | if (hasOwnProperty.call(dict, c)) { 600 | buffer = dict[c]; 601 | } else { 602 | buffer = prev + ch; 603 | } 604 | } 605 | 606 | result += buffer; 607 | 608 | ch = buffer.charAt(0); 609 | dict[code++] = prev + ch; 610 | prev = buffer; 611 | } 612 | 613 | return result; 614 | } 615 | }; 616 | 617 | // LZJS Compression 618 | function LZJS(options) { 619 | this._init(options); 620 | } 621 | 622 | LZJS.prototype = { 623 | _init: function(options) { 624 | options = options || {}; 625 | 626 | //TODO: Validate utf-8 encoding for command line. 627 | this._encoding = options.encoding || 'utf-8'; 628 | }, 629 | compress: function(data) { 630 | if (data == null || data.length === 0) { 631 | return ''; 632 | } 633 | 634 | data = '' + data; 635 | 636 | var result = ''; 637 | var dataBytes = byteLength(data); 638 | var asciiLimitBytes = dataBytes * 0.9 | 0; 639 | var len = data.length; 640 | var options = { 641 | maxBytes: dataBytes 642 | }; 643 | var type; 644 | 645 | if (dataBytes === len) { 646 | // Ascii string [U+0000 - U+007F] 647 | type = 'W'; 648 | options.codeStart = 0x7f; 649 | options.codeMax = 0x7ff; 650 | result = new LZW(options).compress(data); 651 | if (result === false) { 652 | type = 'S'; 653 | result = new LZSSCompressor(options).compress(data); 654 | if (result === false) { 655 | type = 'N'; 656 | result = data; 657 | } 658 | } 659 | } else if (dataBytes > len && asciiLimitBytes < len) { 660 | // String consisting mostly of ASCII 661 | type = 'U'; 662 | result = new LZW(options).compress(toUTF8(data)); 663 | if (result === false) { 664 | type = 'S'; 665 | result = new LZSSCompressor(options).compress(data); 666 | if (result === false) { 667 | type = 'N'; 668 | result = data; 669 | } 670 | } 671 | } else { 672 | // String consisting mostly of non-ASCII 673 | type = 'S'; 674 | result = new LZSSCompressor(options).compress(data); 675 | if (result === false) { 676 | type = 'U'; 677 | result = new LZW(options).compress(toUTF8(data)); 678 | if (result === false || byteLength(result) > dataBytes) { 679 | type = 'N'; 680 | result = data; 681 | } 682 | } 683 | } 684 | 685 | return type + result; 686 | }, 687 | decompress: function(data) { 688 | if (data == null || data.length === 0) { 689 | return ''; 690 | } 691 | 692 | data = '' + data; 693 | var type = data.charAt(0); 694 | 695 | switch (type) { 696 | case 'S': return this._decompressByS(data.substring(1)); 697 | case 'W': return this._decompressByW(data.substring(1)); 698 | case 'U': return this._decompressByU(data.substring(1)); 699 | case 'N': return this._decompressByN(data.substring(1)); 700 | default: return data; 701 | } 702 | }, 703 | _decompressByS: function(data) { 704 | return new LZSSDecompressor().decompress(data); 705 | }, 706 | _decompressByW: function(data) { 707 | var options = { 708 | codeStart: 0x7f, 709 | codeMax: 0x7ff 710 | }; 711 | return new LZW(options).decompress(data); 712 | }, 713 | _decompressByU: function(data) { 714 | return toUTF16(new LZW().decompress(data)); 715 | }, 716 | _decompressByN: function(data) { 717 | return data; 718 | } 719 | }; 720 | 721 | // Create Sliding window 722 | function createWindow() { 723 | var alpha = 'abcdefghijklmnopqrstuvwxyz'; 724 | var win = ''; 725 | var len = alpha.length; 726 | var i, j, c, c2; 727 | 728 | for (i = 0; i < len; i++) { 729 | c = alpha.charAt(i); 730 | for (j = len - 1; j > 15 && win.length < WINDOW_MAX; j--) { 731 | c2 = alpha.charAt(j); 732 | win += ' ' + c + ' ' + c2; 733 | } 734 | } 735 | 736 | while (win.length < WINDOW_MAX) { 737 | win = ' ' + win; 738 | } 739 | win = win.slice(0, WINDOW_MAX); 740 | 741 | return win; 742 | } 743 | 744 | function truncateBuffer(buffer, length) { 745 | if (buffer.length === length) { 746 | return buffer; 747 | } 748 | 749 | if (buffer.subarray) { 750 | return buffer.subarray(0, length); 751 | } 752 | 753 | buffer.length = length; 754 | return buffer; 755 | } 756 | 757 | function bufferToString_fast(buffer, length) { 758 | if (length == null) { 759 | length = buffer.length; 760 | } else { 761 | buffer = truncateBuffer(buffer, length); 762 | } 763 | 764 | if (CAN_CHARCODE_APPLY && CAN_CHARCODE_APPLY_TYPED) { 765 | if (length < APPLY_BUFFER_SIZE) { 766 | if (APPLY_BUFFER_SIZE_OK) { 767 | return fromCharCode.apply(null, buffer); 768 | } 769 | 770 | if (APPLY_BUFFER_SIZE_OK === null) { 771 | try { 772 | var s = fromCharCode.apply(null, buffer); 773 | if (length > APPLY_BUFFER_SIZE) { 774 | APPLY_BUFFER_SIZE_OK = true; 775 | } 776 | return s; 777 | } catch (e) { 778 | // Ignore RangeError: arguments too large 779 | APPLY_BUFFER_SIZE_OK = false; 780 | } 781 | } 782 | } 783 | } 784 | 785 | return bufferToString_chunked(buffer); 786 | } 787 | 788 | function bufferToString_chunked(buffer) { 789 | var string = ''; 790 | var length = buffer.length; 791 | var i = 0; 792 | var sub; 793 | 794 | while (i < length) { 795 | if (buffer.subarray) { 796 | sub = buffer.subarray(i, i + APPLY_BUFFER_SIZE); 797 | } else { 798 | sub = buffer.slice(i, i + APPLY_BUFFER_SIZE); 799 | } 800 | i += APPLY_BUFFER_SIZE; 801 | 802 | if (APPLY_BUFFER_SIZE_OK) { 803 | string += fromCharCode.apply(null, sub); 804 | continue; 805 | } 806 | 807 | if (APPLY_BUFFER_SIZE_OK === null) { 808 | try { 809 | string += fromCharCode.apply(null, sub); 810 | if (sub.length > APPLY_BUFFER_SIZE) { 811 | APPLY_BUFFER_SIZE_OK = true; 812 | } 813 | continue; 814 | } catch (e) { 815 | APPLY_BUFFER_SIZE_OK = false; 816 | } 817 | } 818 | 819 | return bufferToString_slow(buffer); 820 | } 821 | 822 | return string; 823 | } 824 | 825 | function bufferToString_slow(buffer) { 826 | var string = ''; 827 | var length = buffer.length; 828 | 829 | for (var i = 0; i < length; i++) { 830 | string += fromCharCode(buffer[i]); 831 | } 832 | 833 | return string; 834 | } 835 | 836 | function createBuffer(bits, size) { 837 | if (!HAS_TYPED) { 838 | return new Array(size); 839 | } 840 | 841 | switch (bits) { 842 | case 8: return new Uint8Array(size); 843 | case 16: return new Uint16Array(size); 844 | } 845 | } 846 | 847 | function stringToArray(string) { 848 | var array = []; 849 | var len = string && string.length; 850 | 851 | for (var i = 0; i < len; i++) { 852 | array[i] = string.charCodeAt(i); 853 | } 854 | 855 | return array; 856 | } 857 | 858 | // UTF-16 to UTF-8 859 | function toUTF8(data) { 860 | var results = []; 861 | var i = 0; 862 | var len = data.length; 863 | var c, second; 864 | 865 | for (; i < len; i++) { 866 | c = data.charCodeAt(i); 867 | 868 | // high surrogate 869 | if (c >= 0xd800 && c <= 0xdbff && i + 1 < len) { 870 | second = data.charCodeAt(i + 1); 871 | // low surrogate 872 | if (second >= 0xdc00 && second <= 0xdfff) { 873 | c = (c - 0xd800) * 0x400 + second - 0xdc00 + 0x10000; 874 | i++; 875 | } 876 | } 877 | 878 | if (c < 0x80) { 879 | results[results.length] = c; 880 | } else if (c < 0x800) { 881 | results[results.length] = 0xc0 | ((c >> 6) & 0x1f); 882 | results[results.length] = 0x80 | (c & 0x3f); 883 | } else if (c < 0x10000) { 884 | results[results.length] = 0xe0 | ((c >> 12) & 0xf); 885 | results[results.length] = 0x80 | ((c >> 6) & 0x3f); 886 | results[results.length] = 0x80 | (c & 0x3f); 887 | } else if (c < 0x200000) { 888 | results[results.length] = 0xf0 | ((c >> 18) & 0xf); 889 | results[results.length] = 0x80 | ((c >> 12) & 0x3f); 890 | results[results.length] = 0x80 | ((c >> 6) & 0x3f); 891 | results[results.length] = 0x80 | (c & 0x3f); 892 | } 893 | } 894 | 895 | return bufferToString_fast(results); 896 | } 897 | 898 | // UTF-8 to UTF-16 899 | function toUTF16(data) { 900 | var results = []; 901 | var i = 0; 902 | var len = data.length; 903 | var n, c, c2, c3, c4, code; 904 | 905 | while (i < len) { 906 | c = data.charCodeAt(i++); 907 | n = c >> 4; 908 | if (n >= 0 && n <= 7) { 909 | code = c; 910 | } else if (n === 12 || n === 13) { 911 | c2 = data.charCodeAt(i++); 912 | code = ((c & 0x1f) << 6) | (c2 & 0x3f); 913 | } else if (n === 14) { 914 | c2 = data.charCodeAt(i++); 915 | c3 = data.charCodeAt(i++); 916 | code = ((c & 0x0f) << 12) | 917 | ((c2 & 0x3f) << 6) | 918 | (c3 & 0x3f); 919 | } else if (n === 15) { 920 | c2 = data.charCodeAt(i++); 921 | c3 = data.charCodeAt(i++); 922 | c4 = data.charCodeAt(i++); 923 | code = ((c & 0x7) << 18) | 924 | ((c2 & 0x3f) << 12) | 925 | ((c3 & 0x3f) << 6) | 926 | (c4 & 0x3f); 927 | } 928 | 929 | if (code <= 0xffff) { 930 | results[results.length] = code; 931 | } else { 932 | // Split in surrogate halves 933 | code -= 0x10000; 934 | results[results.length] = (code >> 10) + 0xd800; // High surrogate 935 | results[results.length] = (code % 0x400) + 0xdc00; // Low surrogate 936 | } 937 | } 938 | 939 | return bufferToString_fast(results); 940 | } 941 | 942 | // UTF-8 byte length 943 | function byteLength(data, encoding) { 944 | var length = 0; 945 | var c, c2; 946 | 947 | for (var i = 0, len = data.length; i < len; i++) { 948 | c = data.charCodeAt(i); 949 | 950 | if ((c & 0xfc00) === 0xd800 && (i + 1 < len)) { 951 | c2 = data.charCodeAt(i + 1); 952 | if ((c2 & 0xfc00) === 0xdc00) { 953 | c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); 954 | i++; 955 | } 956 | } 957 | 958 | if (c < 0x80) { 959 | length++; 960 | } else if (c < 0x800) { 961 | length += 2; 962 | } else if (c < 0x10000) { 963 | length += 3; 964 | } else { 965 | length += 4; 966 | } 967 | } 968 | 969 | return length; 970 | } 971 | 972 | // Base64 from http://www.onicos.com/staff/iz/amuse/javascript/expert/base64.txt 973 | /* 974 | * Copyright (C) 1999 Masanao Izumo 975 | * Version: 1.0 976 | * LastModified: Dec 25 1999 977 | * This library is free. You can redistribute it and/or modify it. 978 | */ 979 | var base64EncodeChars = 980 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 981 | 982 | var base64DecodeChars = [ 983 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 984 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 985 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 986 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 987 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 988 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 989 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 990 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 991 | ]; 992 | 993 | function base64encode(str) { 994 | var out, i, len; 995 | var c1, c2, c3; 996 | 997 | len = str.length; 998 | i = 0; 999 | out = ''; 1000 | while (i < len) { 1001 | c1 = str.charCodeAt(i++) & 0xff; 1002 | if (i === len) { 1003 | out += base64EncodeChars.charAt(c1 >> 2) + 1004 | base64EncodeChars.charAt((c1 & 0x3) << 4) + 1005 | '=='; 1006 | break; 1007 | } 1008 | 1009 | c2 = str.charCodeAt(i++); 1010 | if (i === len) { 1011 | out += base64EncodeChars.charAt(c1 >> 2) + 1012 | base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4)) + 1013 | base64EncodeChars.charAt((c2 & 0xf) << 2) + 1014 | '='; 1015 | break; 1016 | } 1017 | 1018 | c3 = str.charCodeAt(i++); 1019 | out += base64EncodeChars.charAt(c1 >> 2) + 1020 | base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4)) + 1021 | base64EncodeChars.charAt(((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6)) + 1022 | base64EncodeChars.charAt(c3 & 0x3f); 1023 | } 1024 | 1025 | return out; 1026 | } 1027 | 1028 | function base64decode(str) { 1029 | var c1, c2, c3, c4; 1030 | var i, len, out; 1031 | 1032 | len = str.length; 1033 | i = 0; 1034 | out = ''; 1035 | 1036 | while (i < len) { 1037 | do { 1038 | c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff]; 1039 | } while (i < len && c1 === -1); 1040 | 1041 | if (c1 === -1) { 1042 | break; 1043 | } 1044 | 1045 | do { 1046 | c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff]; 1047 | } while (i < len && c2 === -1); 1048 | 1049 | if (c2 === -1) { 1050 | break; 1051 | } 1052 | 1053 | out += fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); 1054 | 1055 | do { 1056 | c3 = str.charCodeAt(i++) & 0xff; 1057 | if (c3 === 61) { 1058 | return out; 1059 | } 1060 | c3 = base64DecodeChars[c3]; 1061 | } while (i < len && c3 === -1); 1062 | 1063 | if (c3 === -1) { 1064 | break; 1065 | } 1066 | 1067 | out += fromCharCode(((c2 & 0xf) << 4) | ((c3 & 0x3c) >> 2)); 1068 | 1069 | do { 1070 | c4 = str.charCodeAt(i++) & 0xff; 1071 | if (c4 === 61) { 1072 | return out; 1073 | } 1074 | c4 = base64DecodeChars[c4]; 1075 | } while (i < len && c4 === -1); 1076 | 1077 | if (c4 === -1) { 1078 | break; 1079 | } 1080 | 1081 | out += fromCharCode(((c3 & 0x03) << 6) | c4); 1082 | } 1083 | 1084 | return out; 1085 | } 1086 | 1087 | /** 1088 | * @name lzjs 1089 | * @type {Object} 1090 | * @public 1091 | * @class 1092 | */ 1093 | var lzjs = { 1094 | /** 1095 | * @lends lzjs 1096 | */ 1097 | /** 1098 | * Compress data. 1099 | * 1100 | * @param {string} data Input data 1101 | * @param {Object=} [options] Options 1102 | * @return {string} Compressed data 1103 | */ 1104 | compress: function(data, options) { 1105 | return new LZJS(options).compress(data); 1106 | }, 1107 | /** 1108 | * Decompress data. 1109 | * 1110 | * @param {string} data Input data 1111 | * @param {Object=} [options] Options 1112 | * @return {string} Decompressed data 1113 | */ 1114 | decompress: function(data, options) { 1115 | return new LZJS(options).decompress(data); 1116 | }, 1117 | /** 1118 | * Compress data to base64 string. 1119 | * 1120 | * @param {string} data Input data 1121 | * @param {Object=} [options] Options 1122 | * @return {string} Compressed data 1123 | */ 1124 | compressToBase64: function(data, options) { 1125 | return base64encode(toUTF8(new LZJS(options).compress(data))); 1126 | }, 1127 | /** 1128 | * Decompress data from base64 string. 1129 | * 1130 | * @param {string} data Input data 1131 | * @param {Object=} [options] Options 1132 | * @return {string} Decompressed data 1133 | */ 1134 | decompressFromBase64: function(data, options) { 1135 | return new LZJS(options).decompress(toUTF16(base64decode(data))); 1136 | } 1137 | }; 1138 | 1139 | return lzjs; 1140 | })); 1141 | --------------------------------------------------------------------------------