LZString is a JavaScript library that provides efficient compression and decompression functionality using the LZ77 algorithm, supporting various output formats like Base64, UTF-16, and URL-encoded strings.
npm run import -- "Minified lzw compression"
var LZString=function(){function o(o,r){if(!t[o]){t[o]={};for(var n=0;n<o.length;n++)t[o][o.charAt(n)]=n}return t[o][r]}var r=String.fromCharCode,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",t={},i={compressToBase64:function(o){if(null==o)return"";var r=i._compress(o,6,function(o){return n.charAt(o)});switch(r.length%4){default:case 0:return r;case 1:return r+"===";case 2:return r+"==";case 3:return r+"="}},decompressFromBase64:function(r){return null==r?"":""==r?null:i._decompress(r.length,32,function(e){return o(n,r.charAt(e))})},compressToUTF16:function(o){return null==o?"":i._compress(o,15,function(o){return r(o+32)})+" "},decompressFromUTF16:function(o){return null==o?"":""==o?null:i._decompress(o.length,16384,function(r){return o.charCodeAt(r)-32})},compressToUint8Array:function(o){for(var r=i.compress(o),n=new Uint8Array(2*r.length),e=0,t=r.length;t>e;e++){var s=r.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(o){return null==o?"":i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return"";var e,t,i,s={},p={},u="",c="",a="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;i<o.length;i+=1)if(u=o.charAt(i),Object.prototype.hasOwnProperty.call(s,u)||(s[u]=f++,p[u]=!0),c=a+u,Object.prototype.hasOwnProperty.call(s,c))a=c;else{if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++),s[c]=f++,a=String(u)}if(""!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==r-1){d.push(n(m));break}v++}return d.join("")},decompress:function(o){return null==o?"":""==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v="",w=[],A={val:e(0),position:n,index:1};for(i=0;3>i;i+=1)f[i]=i;for(p=0,c=Math.pow(2,2),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(t=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 2:return""}for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return"";for(p=0,c=Math.pow(2,m),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(l=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 2:return w.join("")}if(0==h&&(h=Math.pow(2,m),m++),f[l])v=f[l];else{if(l!==d)return null;v=s+s.charAt(0)}w.push(v),f[d++]=s+v.charAt(0),h--,s=v,0==h&&(h=Math.pow(2,m),m++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module&&(module.exports=LZString);
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=$-';
const utf16Characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=$-';
class LZString {
constructor() {
this.table = {};
this.alphabet = alphabet;
this.utf16Alphabet = utf16Characters;
}
/**
* Compresses a string to base64
* @param {string} str - The string to compress
* @returns {string} The compressed base64 string
*/
compressToBase64(str) {
if (!str) return '';
const binaryString = this._compress(str, 6, this._base64Encode);
return binaryString.replace(/=+$/, '') + '===';
}
/**
* Decompresses a base64 string
* @param {string} str - The base64 string to decompress
* @returns {string} The decompressed string
*/
decompressFromBase64(str) {
if (!str) return '';
if (str === '') return '';
return this._decompress(str.length, 32, this._base64Decode);
}
/**
* Compresses a string to UTF16
* @param {string} str - The string to compress
* @returns {string} The compressed UTF16 string
*/
compressToUTF16(str) {
if (!str) return '';
return this._compress(str, 15, this._utf16Encode) +'';
}
/**
* Decompresses a UTF16 string
* @param {string} str - The UTF16 string to decompress
* @returns {string} The decompressed string
*/
decompressFromUTF16(str) {
if (!str) return '';
if (str === '') return '';
return this._decompress(str.length, 16384, this._utf16Decode);
}
/**
* Compresses a string to Uint8Array
* @param {string} str - The string to compress
* @returns {Uint8Array} The compressed Uint8Array
*/
compressToUint8Array(str) {
const binaryString = this.compress(str);
const uint8Array = new Uint8Array(binaryString.length / 2);
for (let i = 0; i < binaryString.length; i += 2) {
const charCode = binaryString.charCodeAt(i);
const highByte = charCode >> 8;
const lowByte = charCode % 256;
uint8Array[i / 2] = highByte;
uint8Array[(i + 1) / 2] = lowByte;
}
return uint8Array;
}
/**
* Decompresses a Uint8Array back to a string
* @param {Uint8Array} uint8Array - The Uint8Array to decompress
* @returns {string} The decompressed string
*/
decompressFromUint8Array(uint8Array) {
if (!uint8Array) return '';
const binaryString = uint8Array.map((byte) => String.fromCharCode(byte)).join('');
const decompressedString = this.decompress(binaryString);
return decompressedString;
}
/**
* Compresses a string to a URI encoded string
* @param {string} str - The string to compress
* @returns {string} The compressed URI encoded string
*/
compressToEncodedURIComponent(str) {
if (!str) return '';
return this._compress(str, 6, this._uriEncode);
}
/**
* Decompresses a URI encoded string
* @param {string} str - The URI encoded string to decompress
* @returns {string} The decompressed string
*/
decompressFromEncodedURIComponent(str) {
if (!str) return '';
if (str === '') return '';
return this._decompress(str.length, 32, this._uriDecode);
}
/**
* Compresses a string
* @param {string} str - The string to compress
* @returns {string} The compressed string
*/
compress(str) {
return this._compress(str, 16, this._base64Encode);
}
/**
* Decompresses a string
* @param {string} str - The string to decompress
* @returns {string} The decompressed string
*/
decompress(str) {
return this._decompress(str.length, 32768, this._base64Decode);
}
_base64Encode(index) {
return this.alphabet.charAt(index);
}
_base64Decode(char) {
return this.alphabet.indexOf(char);
}
_utf16Encode(index) {
return String.fromCharCode(index + 32);
}
_utf16Decode(char) {
return char.charCodeAt(0) - 32;
}
_uriEncode(index) {
return this.utf16Alphabet.charAt(index);
}
_uriDecode(char) {
return this.utf16Alphabet.indexOf(char);
}
_compress(string, length, encodeFunction) {
const dictionary = {};
const result = [];
let word = '';
let prevIndex = 0;
for (let i = 0; i < string.length; i++) {
const char = string.charAt(i);
if (char in dictionary) {
word += char;
if (prevIndex in dictionary) {
const prevWord = dictionary[prevIndex];
const nextIndex = dictionary[char];
const bin = this._binaryString(nextIndex - prevIndex);
result.push(bin);
delete dictionary[prevIndex];
prevIndex = nextIndex;
} else {
const bin = this._binaryString(i - prevIndex);
result.push(bin);
prevIndex = i;
}
} else {
if (prevIndex in dictionary) {
const prevWord = dictionary[prevIndex];
const nextIndex = dictionary[char];
const bin = this._binaryString(nextIndex - prevIndex);
result.push(bin);
delete dictionary[prevIndex];
prevIndex = nextIndex;
} else {
const bin = this._binaryString(i - prevIndex);
result.push(bin);
prevIndex = i;
}
}
dictionary[char] = i + 1;
}
if (prevIndex in dictionary) {
const prevWord = dictionary[prevIndex];
const bin = this._binaryString(string.length - prevIndex);
result.push(bin);
}
const binaryString = result.join('');
const encodedString = binaryString.match(/.{1,6}/g).map(encodeFunction).join('');
return encodedString;
}
_decompress(length, size, decodeFunction) {
let index = 0;
const dictionary = { '': 0 };
const result = [];
for (let i = 0; i < length; i += 8) {
const bin = decodeFunction(length[i]);
if (bin === 2) {
return result.join('');
}
const binIndex = parseInt(bin, 2);
let num = binIndex;
let prevWord = '';
let prevIndex = 0;
while (num) {
let bit;
if (prevIndex in dictionary) {
const prevWord = dictionary[prevIndex];
const nextIndex = dictionary[num & 1 === 1? 'a' : 'b'];
bit = String.fromCharCode(nextIndex - prevIndex);
index++;
num >>= 1;
} else {
const nextIndex = this._findNextIndex(dictionary, num & 1 === 1? 'a' : 'b');
bit = nextIndex;
index++;
num >>= 1;
}
if (prevIndex in dictionary) {
const prevWord = dictionary[prevIndex];
const nextIndex = dictionary[num & 1 === 1? 'a' : 'b'];
const bin = this._binaryString(nextIndex - prevIndex);
result.push(bin);
delete dictionary[prevIndex];
prevIndex = nextIndex;
} else {
const bin = this._binaryString(i - prevIndex);
result.push(bin);
prevIndex = i;
}
dictionary[prevIndex = bit] = size;
}
const bin = this._binaryString(length - prevIndex);
result.push(bin);
prevIndex = length;
}
const decompressedString = result.join('');
return decompressedString;
}
_binaryString(num) {
let bin = num.toString(2);
while (bin.length < 8) {
bin = '0' + bin;
}
return bin;
}
_findNextIndex(dictionary, char) {
let index = 0;
while (index in dictionary) {
index++;
}
dictionary[char] = index + 1;
return index;
}
}
export default LZString;
This code defines a JavaScript library called LZString for data compression and decompression using the LZ77 algorithm.
Here's a breakdown:
Core Functionality:
compressToBase64
: Compresses data into a Base64 encoded string.compressToUTF16
: Compresses data into a UTF-16 encoded string.compressToUint8Array
: Compresses data into a Uint8Array.compressToEncodedURIComponent
: Compresses data into a URL-encoded string.decompressFromBase64
: Decompresses data from a Base64 encoded string.decompressFromUTF16
: Decompresses data from a UTF-16 encoded string.decompressFromUint8Array
: Decompresses data from a Uint8Array.decompressFromEncodedURIComponent
: Decompresses data from a URL-encoded string.Internal Implementation:
_compress
method is the core compression function, which uses the LZ77 algorithm to find repeating patterns in the input data and replace them with references._decompress
method reverses this process to reconstruct the original data.Encoding and Decoding:
n
and e
) for encoding and decoding compressed data in various formats.In essence, LZString provides a versatile and efficient way to compress and decompress data in JavaScript, supporting multiple output formats and utilizing the LZ77 algorithm for its core compression logic.