lz-string.js 17 KB

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