lz-string.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. // Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
  2. // This work is free. You can redistribute it and/or modify it
  3. // under the terms of the WTFPL, Version 2
  4. // For more information see LICENSE.txt or http://www.wtfpl.net/
  5. //
  6. // For more information, the home page:
  7. // http://pieroxy.net/blog/pages/lz-string/testing.html
  8. //
  9. // LZ-based compression algorithm, version 1.4.4
  10. var LZString = (function() {
  11. // private property
  12. var f = String.fromCharCode;
  13. var keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  14. var keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
  15. var baseReverseDic = {};
  16. function getBaseValue(alphabet, character) {
  17. if (!baseReverseDic[alphabet]) {
  18. baseReverseDic[alphabet] = {};
  19. for (var i=0 ; i<alphabet.length ; i++) {
  20. baseReverseDic[alphabet][alphabet.charAt(i)] = i;
  21. }
  22. }
  23. return baseReverseDic[alphabet][character];
  24. }
  25. var LZString = {
  26. compressToBase64 : function (input) {
  27. if (input == null) return "";
  28. var res = LZString._compress(input, 6, function(a){return keyStrBase64.charAt(a);});
  29. switch (res.length % 4) { // To produce valid Base64
  30. default: // When could this happen ?
  31. case 0 : return res;
  32. case 1 : return res+"===";
  33. case 2 : return res+"==";
  34. case 3 : return res+"=";
  35. }
  36. },
  37. decompressFromBase64 : function (input) {
  38. if (input == null) return "";
  39. if (input == "") return null;
  40. return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrBase64, input.charAt(index)); });
  41. },
  42. compressToUTF16 : function (input) {
  43. if (input == null) return "";
  44. return LZString._compress(input, 15, function(a){return f(a+32);}) + " ";
  45. },
  46. decompressFromUTF16: function (compressed) {
  47. if (compressed == null) return "";
  48. if (compressed == "") return null;
  49. return LZString._decompress(compressed.length, 16384, function(index) { return compressed.charCodeAt(index) - 32; });
  50. },
  51. //compress into uint8array (UCS-2 big endian format)
  52. compressToUint8Array: function (uncompressed) {
  53. var compressed = LZString.compress(uncompressed);
  54. var buf=new Uint8Array(compressed.length*2); // 2 bytes per character
  55. for (var i=0, TotalLen=compressed.length; i<TotalLen; i++) {
  56. var current_value = compressed.charCodeAt(i);
  57. buf[i*2] = current_value >>> 8;
  58. buf[i*2+1] = current_value % 256;
  59. }
  60. return buf;
  61. },
  62. //decompress from uint8array (UCS-2 big endian format)
  63. decompressFromUint8Array:function (compressed) {
  64. if (compressed===null || compressed===undefined){
  65. return LZString.decompress(compressed);
  66. } else {
  67. var buf=new Array(compressed.length/2); // 2 bytes per character
  68. for (var i=0, TotalLen=buf.length; i<TotalLen; i++) {
  69. buf[i]=compressed[i*2]*256+compressed[i*2+1];
  70. }
  71. var result = [];
  72. buf.forEach(function (c) {
  73. result.push(f(c));
  74. });
  75. return LZString.decompress(result.join(''));
  76. }
  77. },
  78. //compress into a string that is already URI encoded
  79. compressToEncodedURIComponent: function (input) {
  80. if (input == null) return "";
  81. return LZString._compress(input, 6, function(a){return keyStrUriSafe.charAt(a);});
  82. },
  83. //decompress from an output of compressToEncodedURIComponent
  84. decompressFromEncodedURIComponent:function (input) {
  85. if (input == null) return "";
  86. if (input == "") return null;
  87. input = input.replace(/ /g, "+");
  88. return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrUriSafe, input.charAt(index)); });
  89. },
  90. compress: function (uncompressed) {
  91. return LZString._compress(uncompressed, 16, function(a){return f(a);});
  92. },
  93. _compress: function (uncompressed, bitsPerChar, getCharFromInt) {
  94. if (uncompressed == null) return "";
  95. var i, value,
  96. context_dictionary= {},
  97. context_dictionaryToCreate= {},
  98. context_c="",
  99. context_wc="",
  100. context_w="",
  101. context_enlargeIn= 2, // Compensate for the first entry which should not count
  102. context_dictSize= 3,
  103. context_numBits= 2,
  104. context_data=[],
  105. context_data_val=0,
  106. context_data_position=0,
  107. ii;
  108. for (ii = 0; ii < uncompressed.length; ii += 1) {
  109. context_c = uncompressed.charAt(ii);
  110. if (!Object.prototype.hasOwnProperty.call(context_dictionary,context_c)) {
  111. context_dictionary[context_c] = context_dictSize++;
  112. context_dictionaryToCreate[context_c] = true;
  113. }
  114. context_wc = context_w + context_c;
  115. if (Object.prototype.hasOwnProperty.call(context_dictionary,context_wc)) {
  116. context_w = context_wc;
  117. } else {
  118. if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {
  119. if (context_w.charCodeAt(0)<256) {
  120. for (i=0 ; i<context_numBits ; i++) {
  121. context_data_val = (context_data_val << 1);
  122. if (context_data_position == bitsPerChar-1) {
  123. context_data_position = 0;
  124. context_data.push(getCharFromInt(context_data_val));
  125. context_data_val = 0;
  126. } else {
  127. context_data_position++;
  128. }
  129. }
  130. value = context_w.charCodeAt(0);
  131. for (i=0 ; i<8 ; i++) {
  132. context_data_val = (context_data_val << 1) | (value&1);
  133. if (context_data_position == bitsPerChar-1) {
  134. context_data_position = 0;
  135. context_data.push(getCharFromInt(context_data_val));
  136. context_data_val = 0;
  137. } else {
  138. context_data_position++;
  139. }
  140. value = value >> 1;
  141. }
  142. } else {
  143. value = 1;
  144. for (i=0 ; i<context_numBits ; i++) {
  145. context_data_val = (context_data_val << 1) | value;
  146. if (context_data_position ==bitsPerChar-1) {
  147. context_data_position = 0;
  148. context_data.push(getCharFromInt(context_data_val));
  149. context_data_val = 0;
  150. } else {
  151. context_data_position++;
  152. }
  153. value = 0;
  154. }
  155. value = context_w.charCodeAt(0);
  156. for (i=0 ; i<16 ; i++) {
  157. context_data_val = (context_data_val << 1) | (value&1);
  158. if (context_data_position == bitsPerChar-1) {
  159. context_data_position = 0;
  160. context_data.push(getCharFromInt(context_data_val));
  161. context_data_val = 0;
  162. } else {
  163. context_data_position++;
  164. }
  165. value = value >> 1;
  166. }
  167. }
  168. context_enlargeIn--;
  169. if (context_enlargeIn == 0) {
  170. context_enlargeIn = Math.pow(2, context_numBits);
  171. context_numBits++;
  172. }
  173. delete context_dictionaryToCreate[context_w];
  174. } else {
  175. value = context_dictionary[context_w];
  176. for (i=0 ; i<context_numBits ; i++) {
  177. context_data_val = (context_data_val << 1) | (value&1);
  178. if (context_data_position == bitsPerChar-1) {
  179. context_data_position = 0;
  180. context_data.push(getCharFromInt(context_data_val));
  181. context_data_val = 0;
  182. } else {
  183. context_data_position++;
  184. }
  185. value = value >> 1;
  186. }
  187. }
  188. context_enlargeIn--;
  189. if (context_enlargeIn == 0) {
  190. context_enlargeIn = Math.pow(2, context_numBits);
  191. context_numBits++;
  192. }
  193. // Add wc to the dictionary.
  194. context_dictionary[context_wc] = context_dictSize++;
  195. context_w = String(context_c);
  196. }
  197. }
  198. // Output the code for w.
  199. if (context_w !== "") {
  200. if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {
  201. if (context_w.charCodeAt(0)<256) {
  202. for (i=0 ; i<context_numBits ; i++) {
  203. context_data_val = (context_data_val << 1);
  204. if (context_data_position == bitsPerChar-1) {
  205. context_data_position = 0;
  206. context_data.push(getCharFromInt(context_data_val));
  207. context_data_val = 0;
  208. } else {
  209. context_data_position++;
  210. }
  211. }
  212. value = context_w.charCodeAt(0);
  213. for (i=0 ; i<8 ; i++) {
  214. context_data_val = (context_data_val << 1) | (value&1);
  215. if (context_data_position == bitsPerChar-1) {
  216. context_data_position = 0;
  217. context_data.push(getCharFromInt(context_data_val));
  218. context_data_val = 0;
  219. } else {
  220. context_data_position++;
  221. }
  222. value = value >> 1;
  223. }
  224. } else {
  225. value = 1;
  226. for (i=0 ; i<context_numBits ; i++) {
  227. context_data_val = (context_data_val << 1) | value;
  228. if (context_data_position == bitsPerChar-1) {
  229. context_data_position = 0;
  230. context_data.push(getCharFromInt(context_data_val));
  231. context_data_val = 0;
  232. } else {
  233. context_data_position++;
  234. }
  235. value = 0;
  236. }
  237. value = context_w.charCodeAt(0);
  238. for (i=0 ; i<16 ; i++) {
  239. context_data_val = (context_data_val << 1) | (value&1);
  240. if (context_data_position == bitsPerChar-1) {
  241. context_data_position = 0;
  242. context_data.push(getCharFromInt(context_data_val));
  243. context_data_val = 0;
  244. } else {
  245. context_data_position++;
  246. }
  247. value = value >> 1;
  248. }
  249. }
  250. context_enlargeIn--;
  251. if (context_enlargeIn == 0) {
  252. context_enlargeIn = Math.pow(2, context_numBits);
  253. context_numBits++;
  254. }
  255. delete context_dictionaryToCreate[context_w];
  256. } else {
  257. value = context_dictionary[context_w];
  258. for (i=0 ; i<context_numBits ; i++) {
  259. context_data_val = (context_data_val << 1) | (value&1);
  260. if (context_data_position == bitsPerChar-1) {
  261. context_data_position = 0;
  262. context_data.push(getCharFromInt(context_data_val));
  263. context_data_val = 0;
  264. } else {
  265. context_data_position++;
  266. }
  267. value = value >> 1;
  268. }
  269. }
  270. context_enlargeIn--;
  271. if (context_enlargeIn == 0) {
  272. context_enlargeIn = Math.pow(2, context_numBits);
  273. context_numBits++;
  274. }
  275. }
  276. // Mark the end of the stream
  277. value = 2;
  278. for (i=0 ; i<context_numBits ; i++) {
  279. context_data_val = (context_data_val << 1) | (value&1);
  280. if (context_data_position == bitsPerChar-1) {
  281. context_data_position = 0;
  282. context_data.push(getCharFromInt(context_data_val));
  283. context_data_val = 0;
  284. } else {
  285. context_data_position++;
  286. }
  287. value = value >> 1;
  288. }
  289. // Flush the last char
  290. while (true) {
  291. context_data_val = (context_data_val << 1);
  292. if (context_data_position == bitsPerChar-1) {
  293. context_data.push(getCharFromInt(context_data_val));
  294. break;
  295. }
  296. else context_data_position++;
  297. }
  298. return context_data.join('');
  299. },
  300. decompress: function (compressed) {
  301. if (compressed == null) return "";
  302. if (compressed == "") return null;
  303. return LZString._decompress(compressed.length, 32768, function(index) { return compressed.charCodeAt(index); });
  304. },
  305. _decompress: function (length, resetValue, getNextValue) {
  306. var dictionary = [],
  307. next,
  308. enlargeIn = 4,
  309. dictSize = 4,
  310. numBits = 3,
  311. entry = "",
  312. result = [],
  313. i,
  314. w,
  315. bits, resb, maxpower, power,
  316. c,
  317. data = {val:getNextValue(0), position:resetValue, index:1};
  318. for (i = 0; i < 3; i += 1) {
  319. dictionary[i] = i;
  320. }
  321. bits = 0;
  322. maxpower = Math.pow(2,2);
  323. power=1;
  324. while (power!=maxpower) {
  325. resb = data.val & data.position;
  326. data.position >>= 1;
  327. if (data.position == 0) {
  328. data.position = resetValue;
  329. data.val = getNextValue(data.index++);
  330. }
  331. bits |= (resb>0 ? 1 : 0) * power;
  332. power <<= 1;
  333. }
  334. switch (next = bits) {
  335. case 0:
  336. bits = 0;
  337. maxpower = Math.pow(2,8);
  338. power=1;
  339. while (power!=maxpower) {
  340. resb = data.val & data.position;
  341. data.position >>= 1;
  342. if (data.position == 0) {
  343. data.position = resetValue;
  344. data.val = getNextValue(data.index++);
  345. }
  346. bits |= (resb>0 ? 1 : 0) * power;
  347. power <<= 1;
  348. }
  349. c = f(bits);
  350. break;
  351. case 1:
  352. bits = 0;
  353. maxpower = Math.pow(2,16);
  354. power=1;
  355. while (power!=maxpower) {
  356. resb = data.val & data.position;
  357. data.position >>= 1;
  358. if (data.position == 0) {
  359. data.position = resetValue;
  360. data.val = getNextValue(data.index++);
  361. }
  362. bits |= (resb>0 ? 1 : 0) * power;
  363. power <<= 1;
  364. }
  365. c = f(bits);
  366. break;
  367. case 2:
  368. return "";
  369. }
  370. dictionary[3] = c;
  371. w = c;
  372. result.push(c);
  373. while (true) {
  374. if (data.index > length) {
  375. return "";
  376. }
  377. bits = 0;
  378. maxpower = Math.pow(2,numBits);
  379. power=1;
  380. while (power!=maxpower) {
  381. resb = data.val & data.position;
  382. data.position >>= 1;
  383. if (data.position == 0) {
  384. data.position = resetValue;
  385. data.val = getNextValue(data.index++);
  386. }
  387. bits |= (resb>0 ? 1 : 0) * power;
  388. power <<= 1;
  389. }
  390. switch (c = bits) {
  391. case 0:
  392. bits = 0;
  393. maxpower = Math.pow(2,8);
  394. power=1;
  395. while (power!=maxpower) {
  396. resb = data.val & data.position;
  397. data.position >>= 1;
  398. if (data.position == 0) {
  399. data.position = resetValue;
  400. data.val = getNextValue(data.index++);
  401. }
  402. bits |= (resb>0 ? 1 : 0) * power;
  403. power <<= 1;
  404. }
  405. dictionary[dictSize++] = f(bits);
  406. c = dictSize-1;
  407. enlargeIn--;
  408. break;
  409. case 1:
  410. bits = 0;
  411. maxpower = Math.pow(2,16);
  412. power=1;
  413. while (power!=maxpower) {
  414. resb = data.val & data.position;
  415. data.position >>= 1;
  416. if (data.position == 0) {
  417. data.position = resetValue;
  418. data.val = getNextValue(data.index++);
  419. }
  420. bits |= (resb>0 ? 1 : 0) * power;
  421. power <<= 1;
  422. }
  423. dictionary[dictSize++] = f(bits);
  424. c = dictSize-1;
  425. enlargeIn--;
  426. break;
  427. case 2:
  428. return result.join('');
  429. }
  430. if (enlargeIn == 0) {
  431. enlargeIn = Math.pow(2, numBits);
  432. numBits++;
  433. }
  434. if (dictionary[c]) {
  435. entry = dictionary[c];
  436. } else {
  437. if (c === dictSize) {
  438. entry = w + w.charAt(0);
  439. } else {
  440. return null;
  441. }
  442. }
  443. result.push(entry);
  444. // Add w+entry[0] to the dictionary.
  445. dictionary[dictSize++] = w + entry.charAt(0);
  446. enlargeIn--;
  447. w = entry;
  448. if (enlargeIn == 0) {
  449. enlargeIn = Math.pow(2, numBits);
  450. numBits++;
  451. }
  452. }
  453. }
  454. };
  455. return LZString;
  456. })();
  457. if (typeof define === 'function' && define.amd) {
  458. define(function () { return LZString; });
  459. } else if( typeof module !== 'undefined' && module != null ) {
  460. module.exports = LZString
  461. }