PageRenderTime 49ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/xbird-open/main/src/java/xbird/util/compress/LZFCodec.java

http://xbird.googlecode.com/
Java | 279 lines | 216 code | 16 blank | 47 comment | 43 complexity | f9b9efda1e85d85bb57d847438fa6e20 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-2-Clause, GPL-2.0, LGPL-2.0, BSD-3-Clause, LGPL-2.1, AGPL-3.0
  1. /*
  2. * Copyright (c) 2005-2006 Makoto YUI
  3. * Copyright (c) 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
  4. * Copyright (c) 2000-2005 Marc Alexander Lehmann <schmorp@schmorp.de>
  5. * Copyright (c) 2005 Oren J. Maurice <oymaurice@hazorea.org.il>
  6. *
  7. * Redistribution and use in source and binary forms, with or without modifica-
  8. * tion, are permitted provided that the following conditions are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * 3. The name of the author may not be used to endorse or promote products
  18. * derived from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  21. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
  22. * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  23. * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
  24. * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  26. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  27. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
  28. * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  29. * OF THE POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. * Contributors:
  32. * Makoto YUI - some modification and bug fixes
  33. */
  34. package xbird.util.compress;
  35. import xbird.util.primitive.Primitives;
  36. /**
  37. *
  38. * <DIV lang="en"></DIV>
  39. * <DIV lang="ja"></DIV>
  40. *
  41. * @author Makoto YUI (yuin405+xbird@gmail.com)
  42. * @link http://www.goof.com/pcg/marc/liblzf.html
  43. */
  44. public final class LZFCodec implements CompressionCodec {
  45. private static final int HASH_SIZE = (1 << 14);
  46. private static final int MAX_LITERAL = (1 << 5);
  47. private static final int MAX_OFF = (1 << 13);
  48. private static final int MAX_REF = ((1 << 8) + (1 << 3));
  49. public LZFCodec() {}
  50. public byte[] compress(final byte[] in) {
  51. return compress(in, in.length);
  52. }
  53. public byte[] compress(final byte[] in, final int inLength) {
  54. final byte[] out = new byte[inLength * 3 >> 1];
  55. final int size = compress(in, inLength, out, 0);
  56. final byte[] dst = new byte[size + 3];
  57. dst[0] = (byte) inLength;
  58. dst[1] = (byte) (inLength >> 8);
  59. dst[2] = (byte) (inLength >> 16);
  60. System.arraycopy(out, 0, dst, 3, size);
  61. return dst;
  62. }
  63. public static int compress(final byte[] in, final int inLen, final byte[] out, int outPos) {
  64. int inPos = 0;
  65. final int[] hashTab = new int[HASH_SIZE];
  66. int literals = 0;
  67. int hval = first(in, inPos);
  68. while(true) {
  69. if(inPos < inLen - 4) {
  70. hval = next(hval, in, inPos);
  71. int off = hash(hval);
  72. int ref = hashTab[off];
  73. hashTab[off] = inPos;
  74. off = inPos - ref - 1;
  75. if(off < MAX_OFF && ref > 0 && in[ref + 2] == in[inPos + 2]
  76. && in[ref + 1] == in[inPos + 1] && in[ref] == in[inPos]) {
  77. int maxlen = inLen - inPos - 2;
  78. maxlen = maxlen > MAX_REF ? MAX_REF : maxlen;
  79. int len = 3;
  80. while(len < maxlen && in[ref + len] == in[inPos + len]) {
  81. len++;
  82. }
  83. len -= 2;
  84. if(literals != 0) {
  85. out[outPos++] = (byte) (literals - 1);
  86. literals = -literals;
  87. do {
  88. out[outPos++] = in[inPos + literals++];
  89. } while(literals != 0);
  90. }
  91. if(len < 7) {
  92. out[outPos++] = (byte) ((off >> 8) + (len << 5));
  93. } else {
  94. out[outPos++] = (byte) ((off >> 8) + (7 << 5));
  95. out[outPos++] = (byte) (len - 7);
  96. }
  97. out[outPos++] = (byte) off;
  98. inPos += len;
  99. hval = first(in, inPos);
  100. hval = next(hval, in, inPos);
  101. hashTab[hash(hval)] = inPos++;
  102. hval = next(hval, in, inPos);
  103. hashTab[hash(hval)] = inPos++;
  104. continue;
  105. }
  106. } else if(inPos == inLen) {
  107. break;
  108. }
  109. inPos++;
  110. literals++;
  111. if(literals == MAX_LITERAL) {
  112. out[outPos++] = (byte) (literals - 1);
  113. literals = -literals;
  114. do {
  115. out[outPos++] = in[inPos + literals++];
  116. } while(literals != 0);
  117. }
  118. }
  119. if(literals != 0) {
  120. out[outPos++] = (byte) (literals - 1);
  121. for(int i = inPos - literals; i != inPos; i++) {
  122. out[outPos++] = in[i];
  123. }
  124. }
  125. return outPos;
  126. }
  127. public byte[] decompress(final byte[] in) {
  128. final int size = ((in[2] & 0xff) << 16) + ((in[1] & 0xff) << 8) + (in[0] & 0xff);
  129. final byte[] dst = new byte[size];
  130. decompress(in, 3, dst, 0, size);
  131. return dst;
  132. }
  133. public char[] decompressAsChars(final byte[] in) {
  134. final int size = ((in[2] & 0xff) << 16) + ((in[1] & 0xff) << 8) + (in[0] & 0xff);
  135. final byte[] dst = new byte[size];
  136. decompress(in, 3, dst, 0, size);
  137. return Primitives.toChars(dst, 0, size);
  138. }
  139. public static void decompress(final byte[] in, int inPos, final byte[] out, int outPos, final int outLength) {
  140. do {
  141. final int ctrl = in[inPos++] & 255;
  142. if(ctrl < MAX_LITERAL) {
  143. // literal run
  144. for(int i = 0; i <= ctrl; i++) {
  145. out[outPos++] = in[inPos++];
  146. }
  147. } else {
  148. // back reference
  149. int len = ctrl >> 5;
  150. int ref = outPos - ((ctrl & 0x1f) << 8) - 1;
  151. if(len == 7) {
  152. len += in[inPos++] & 255;
  153. }
  154. ref -= in[inPos++] & 255;
  155. len += outPos + 2;
  156. out[outPos++] = out[ref++];
  157. out[outPos++] = out[ref++];
  158. while(outPos < len) {
  159. out[outPos++] = out[ref++];
  160. }
  161. }
  162. } while(outPos < outLength);
  163. }
  164. @Deprecated
  165. public static void decompress2(final byte[] in, final int inPos_, final byte[] out, final int outPos_, final int outLength) {
  166. int inPos = inPos_;
  167. int outPos = outPos_;
  168. do {
  169. final int ctrl = in[inPos++] & 255;
  170. if(ctrl < MAX_LITERAL) {
  171. // literal run
  172. final int rounds = ctrl + 1;
  173. for(int i = 0; i < rounds; i++) {
  174. out[outPos + i] = in[inPos + i];
  175. }
  176. outPos += rounds;
  177. inPos += rounds;
  178. } else {
  179. // back reference
  180. int len = ctrl >> 5;
  181. int ref = outPos - ((ctrl & 0x1f) << 8) - 1;
  182. if(len == 7) {
  183. len += in[inPos++] & 255;
  184. }
  185. ref -= in[inPos++] & 255;
  186. out[outPos] = out[ref];
  187. out[outPos + 1] = out[ref + 1];
  188. final int rounds = len + 2;
  189. for(int i = 2; i < rounds; i++) {
  190. out[outPos + i] = out[ref + i];
  191. }
  192. outPos += rounds;
  193. ref += rounds;
  194. }
  195. } while(outPos < outLength);
  196. }
  197. @Deprecated
  198. public static void decompressVectorized(final byte[] in, int inPos, final byte[] out, int outPos, final int outLength) {
  199. do {
  200. final int ctrl = in[inPos++] & 255;
  201. if(ctrl < MAX_LITERAL) {
  202. // literal run
  203. int i = 0;
  204. final int limit = ctrl - 7;
  205. while(i < limit) {
  206. out[outPos] = in[inPos];
  207. out[outPos + 1] = in[inPos + 1];
  208. out[outPos + 2] = in[inPos + 2];
  209. out[outPos + 3] = in[inPos + 3];
  210. out[outPos + 4] = in[inPos + 4];
  211. out[outPos + 5] = in[inPos + 5];
  212. out[outPos + 6] = in[inPos + 6];
  213. out[outPos + 7] = in[inPos + 7];
  214. outPos += 8;
  215. inPos += 8;
  216. i += 8;
  217. }
  218. for(; i <= ctrl; i++) {
  219. out[outPos++] = in[inPos++];
  220. }
  221. } else {
  222. // back reference
  223. int len = ctrl >> 5;
  224. int ref = outPos - ((ctrl & 0x1f) << 8) - 1;
  225. if(len == 7) {
  226. len += in[inPos++] & 255;
  227. }
  228. ref -= in[inPos++] & 255;
  229. len += outPos + 2;
  230. out[outPos++] = out[ref++];
  231. out[outPos++] = out[ref++];
  232. final int rounds = len - outPos;
  233. final int limit = rounds - 7;
  234. int j = 0;
  235. while(j < limit) {
  236. out[outPos] = out[ref];
  237. out[outPos + 1] = out[ref + 1];
  238. out[outPos + 2] = out[ref + 2];
  239. out[outPos + 3] = out[ref + 3];
  240. out[outPos + 4] = out[ref + 4];
  241. out[outPos + 5] = out[ref + 5];
  242. out[outPos + 6] = out[ref + 6];
  243. out[outPos + 7] = out[ref + 7];
  244. outPos += 8;
  245. ref += 8;
  246. j += 8;
  247. }
  248. for(; j < rounds; j++) {
  249. out[outPos++] = out[ref++];
  250. }
  251. }
  252. } while(outPos < outLength);
  253. }
  254. private static int first(final byte[] in, final int inPos) {
  255. return (in[inPos] << 8) + (in[inPos + 1] & 255);
  256. }
  257. private static int next(final int v, final byte[] in, final int inPos) {
  258. return (v << 8) + (in[inPos + 2] & 255);
  259. }
  260. private static int hash(final int h) {
  261. return ((h * 184117) >> 9) & (HASH_SIZE - 1);
  262. }
  263. }