// Copyright © 2013 Pieroxy // This work is free. You can redistribute it and/or modify it // under the terms of the WTFPL, Version 2 // For more information see LICENSE.txt or http://www.wtfpl.net/ // // LZ-based compression algorithm, version 1.0.2-rc1 var LZString = { writeBit : function(value, data) { data.val = (data.val << 1) | value; if (data.position == 15) { data.position = 0; data.string += String.fromCharCode(data.val); data.val = 0; } else { data.position++; } }, writeBits : function(numBits, value, data) { if (typeof(value)=="string") value = value.charCodeAt(0); for (var i=0 ; i> 1; } }, produceW : function (context) { if (Object.prototype.hasOwnProperty.call(context.dictionaryToCreate,context.w)) { if (context.w.charCodeAt(0)<256) { this.writeBits(context.numBits, 0, context.data); this.writeBits(8, context.w, context.data); } else { this.writeBits(context.numBits, 1, context.data); this.writeBits(16, context.w, context.data); } this.decrementEnlargeIn(context); delete context.dictionaryToCreate[context.w]; } else { this.writeBits(context.numBits, context.dictionary[context.w], context.data); } this.decrementEnlargeIn(context); }, decrementEnlargeIn : function(context) { context.enlargeIn--; if (context.enlargeIn == 0) { context.enlargeIn = Math.pow(2, context.numBits); context.numBits++; } }, compress: function (uncompressed) { var context = { dictionary: {}, dictionaryToCreate: {}, c:"", wc:"", w:"", enlargeIn: 2, // Compensate for the first entry which should not count dictSize: 3, numBits: 2, result: "", data: {string:"", val:0, position:0} }, i; for (i = 0; i < uncompressed.length; i += 1) { context.c = uncompressed.charAt(i); if (!Object.prototype.hasOwnProperty.call(context.dictionary,context.c)) { context.dictionary[context.c] = context.dictSize++; context.dictionaryToCreate[context.c] = true; } context.wc = context.w + context.c; if (Object.prototype.hasOwnProperty.call(context.dictionary,context.wc)) { context.w = context.wc; } else { this.produceW(context); // Add wc to the dictionary. context.dictionary[context.wc] = context.dictSize++; context.w = String(context.c); } } // Output the code for w. if (context.w !== "") { this.produceW(context); } // Mark the end of the stream this.writeBits(context.numBits, 2, context.data); // Flush the last char while (context.data.val>0) this.writeBit(0,context.data) return context.data.string; }, readBit : function(data) { var res = data.val & data.position; data.position >>= 1; if (data.position == 0) { data.position = 32768; data.val = data.string.charCodeAt(data.index++); } //data.val = (data.val << 1); return res>0 ? 1 : 0; }, readBits : function(numBits, data) { var res = 0; var maxpower = Math.pow(2,numBits); var power=1; while (power!=maxpower) { res |= this.readBit(data) * power; power <<= 1; } return res; }, decompress: function (compressed) { var dictionary = {}, next, enlargeIn = 4, dictSize = 4, numBits = 3, entry = "", result = "", i, w, c, errorCount=0, literal, data = {string:compressed, val:compressed.charCodeAt(0), position:32768, index:1}; for (i = 0; i < 3; i += 1) { dictionary[i] = i; } next = this.readBits(2, data); switch (next) { case 0: c = String.fromCharCode(this.readBits(8, data)); break; case 1: c = String.fromCharCode(this.readBits(16, data)); break; case 2: return ""; } dictionary[3] = c; w = result = c; while (true) { c = this.readBits(numBits, data); switch (c) { case 0: if (errorCount++ > 10000) return "Error"; c = String.fromCharCode(this.readBits(8, data)); dictionary[dictSize++] = c; c = dictSize-1; enlargeIn--; break; case 1: c = String.fromCharCode(this.readBits(16, data)); dictionary[dictSize++] = c; c = dictSize-1; enlargeIn--; break; case 2: return result; } if (enlargeIn == 0) { enlargeIn = Math.pow(2, numBits); numBits++; } if (dictionary[c]) { entry = dictionary[c]; } else { if (c === dictSize) { entry = w + w.charAt(0); } else { return null; } } result += entry; // Add w+entry[0] to the dictionary. dictionary[dictSize++] = w + entry.charAt(0); enlargeIn--; w = entry; if (enlargeIn == 0) { enlargeIn = Math.pow(2, numBits); numBits++; } } return result; } };