/*
* lzwCompress.js
*
* Copyright (c) 2012-2016 floydpink
* Licensed under the MIT license.
*
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
'use strict';
(function () {
var root = this;
var lzwCompress = (function (Array, JSON, undefined) {
var _self = {},
_lzwLoggingEnabled = false,
_lzwLog = function (message) {
try {
console.log('lzwCompress: ' +
(new Date()).toISOString() + ' : ' + (typeof(message) === 'object' ? JSON.stringify(message) : message));
} catch (e) {
}
};
// KeyOptimize
// http://stackoverflow.com/questions/4433402/replace-keys-json-in-javascript
(function (self, Array, JSON) {
var _keys = [],
comparer = function (key) {
return function (e) {
return e === key;
};
},
inArray = function (array,comparer) {
for (var i = 0; i < array.length; i++) {
if (comparer(array[i])) {
return true;
}
}
return false;
},
pushNew = function (array,element, comparer) {
if (!inArray(array,comparer)) {
array.push(element);
}
},
_extractKeys = function (obj) {
if (typeof obj === 'object') {
for (var key in obj) {
if (!Array.isArray(obj)) {
pushNew(_keys,key, comparer(key));
}
_extractKeys(obj[key]);
}
}
},
_encode = function (obj) {
if (typeof obj !== 'object') {
return obj;
}
for (var prop in obj) {
if (!Array.isArray(obj)) {
if (obj.hasOwnProperty(prop)) {
obj[_keys.indexOf(prop)] = _encode(obj[prop]);
delete obj[prop];
}
} else {
obj[prop] = _encode(obj[prop]);
}
}
return obj;
},
_decode = function (obj) {
if (typeof obj !== 'object') {
return obj;
}
for (var prop in obj) {
if (!Array.isArray(obj)) {
if (obj.hasOwnProperty(prop) && _keys[prop]) {
obj[_keys[prop]] = _decode(obj[prop]);
delete obj[prop];
}
} else {
obj[prop] = _decode(obj[prop]);
}
}
return obj;
},
compress = function (json) {
_keys = [];
var jsonObj = JSON.parse(json);
_extractKeys(jsonObj);
_lzwLoggingEnabled && _lzwLog('keys length : ' + _keys.length);
_lzwLoggingEnabled && _lzwLog('keys : ' + _keys);
return JSON.stringify({ __k : _keys, __v : _encode(jsonObj) });
},
decompress = function (minifiedJson) {
var obj = minifiedJson;
if (typeof(obj) !== 'object') {
return minifiedJson;
}
if (!obj.hasOwnProperty('__k')) {
return JSON.stringify(obj);
}
_keys = obj.__k;
return _decode(obj.__v);
};
self.KeyOptimize = {
pack : compress,
unpack : decompress
};
}(_self, Array, JSON));
// LZWCompress
// http://stackoverflow.com/a/2252533/218882
// http://rosettacode.org/wiki/LZW_compression#JavaScript
(function (self, Array) {
var compress = function (uncompressed) {
if (typeof(uncompressed) !== 'string') {
return uncompressed;
}
var i,
dictionary = {},
c,
wc,
w = '',
result = [],
dictSize = 256;
for (i = 0; i < 256; i += 1) {
dictionary[String.fromCharCode(i)] = i;
}
for (i = 0; i < uncompressed.length; i += 1) {
c = uncompressed.charAt(i);
wc = w + c;
if (dictionary[wc]) {
w = wc;
} else {
if (dictionary[w] === undefined) {
return uncompressed;
}
result.push(dictionary[w]);
dictionary[wc] = dictSize++;
w = String(c);
}
}
if (w !== '') {
result.push(dictionary[w]);
}
return result;
},
decompress = function (compressed) {
if (!Array.isArray(compressed)) {
return compressed;
}
var i,
dictionary = [],
w,
result,
k,
entry = '',
dictSize = 256;
for (i = 0; i < 256; i += 1) {
dictionary[i] = String.fromCharCode(i);
}
w = String.fromCharCode(compressed[0]);
result = w;
for (i = 1; i < compressed.length; i += 1) {
k = compressed[i];
if (dictionary[k]) {
entry = dictionary[k];
} else {
if (k === dictSize) {
entry = w + w.charAt(0);
} else {
return null;
}
}
result += entry;
dictionary[dictSize++] = w + entry.charAt(0);
w = entry;
}
return result;
};
self.LZWCompress = {
pack : compress,
unpack : decompress
};
}(_self, Array));
var _compress = function (obj) {
_lzwLoggingEnabled && _lzwLog('original (uncompressed) : ' + obj);
if (!obj || obj === true || obj instanceof Date) {
return obj;
}
var result = obj;
if (typeof obj === 'object') {
result = _self.KeyOptimize.pack(JSON.stringify(obj));
_lzwLoggingEnabled && _lzwLog('key optimized: ' + result);
}
var packedObj = _self.LZWCompress.pack(result);
_lzwLoggingEnabled && _lzwLog('packed (compressed) : ' + packedObj);
return packedObj;
},
_decompress = function (compressedObj) {
_lzwLoggingEnabled && _lzwLog('original (compressed) : ' + compressedObj);
if (!compressedObj || compressedObj === true || compressedObj instanceof Date) {
return compressedObj;
}
var probableJSON, result = _self.LZWCompress.unpack(compressedObj);
try {
probableJSON = JSON.parse(result);
} catch (e) {
_lzwLoggingEnabled && _lzwLog('unpacked (uncompressed) : ' + result);
return result;
}
if (typeof probableJSON === 'object') {
result = _self.KeyOptimize.unpack(probableJSON);
}
_lzwLoggingEnabled && _lzwLog('unpacked (uncompressed) : ' + result);
return result;
},
_enableLogging = function (enable) {
_lzwLoggingEnabled = enable;
};
return {
pack : _compress,
unpack : _decompress,
enableLogging : _enableLogging
};
})(Array, JSON);
if (typeof module !== 'undefined' && module.exports) {
module.exports = lzwCompress;
}
else {
root.lzwCompress = lzwCompress;
}
}).call(this);