來自:http://www.cnjm.net/tech/article4729.html
超級短小精悍的ZIP解壓縮類,只有280行java代碼,混淆並壓縮後的class檔案僅4K左右,特別適用於J2ME開發。
解壓縮演算法來自網上那個著名的GZIP.java,我只添加瞭解析ZIP檔案格式的部分。
list()方法:
列出zip包中所有的檔案及目錄,列出的是包括路徑的全名,比如檔案"dir1/dir2/file.txt",或目錄"dir1/dir2/",注意路徑分隔字元是正斜杠'/',目錄的最後一個字元一定是'/'。
get(String filename)方法:
從zip包中解壓縮給定名字的檔案,返回位元組數組。
ZipMe(InputStream is):
從一個輸入資料流讀取zip檔案,可以是jar包中的檔案,也可以是通過FileConnection擷取的手機檔案系統中的檔案,或從網路上下載的zip包。
下面的例子代碼訪問jar包中的zip檔案並逐一解壓縮包中的所有檔案:
InputStream is = "".getClass().getResourceAsStream("/res/test.zip");
ZipMe file = new ZipMe(is);
is.close();
Vector p = file.list();
for (int i = 0; i < p.size(); i++) {
String name = (String) p.get(i);
byte[] bb = file.get(name);
System.out.println("file: " + name + " / data_len: " + (bb != null ? bb.length : -1));
}
====================================================
package net.cnjm.j2me.utils;</p><p>import java.io.*;<br />import java.util.*;</p><p>public class ZipMe {</p><p> private static final int BTYPE_NONE = 0;<br /> private static final int BTYPE_DYNAMIC = 2;<br /> private static final int MAX_BITS = 16;<br /> private static final int MAX_CODE_LITERALS = 287;<br /> private static final int MAX_CODE_DISTANCES = 31;<br /> private static final int MAX_CODE_LENGTHS = 18;<br /> private static final int EOB_CODE = 256;</p><p> private static final int LENGTH_EXTRA_BITS[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1,<br /> 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 };<br /> private static final int LENGTH_VALUES[] = { 3, 4, 5, 6, 7, 8, 9, 10, 11,<br /> 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,<br /> 163, 195, 227, 258, 0, 0 };<br /> private static final int DISTANCE_EXTRA_BITS[] = { 0, 0, 0, 0, 1, 1, 2, 2,<br /> 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12,<br /> 13, 13 };<br /> private static final int DISTANCE_VALUES[] = { 1, 2, 3, 4, 5, 7, 9, 13, 17,<br /> 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049,<br /> 3073, 4097, 6145, 8193, 12289, 16385, 24577 };<br /> private static final int DYNAMIC_LENGTH_ORDER[] = { 16, 17, 18, 0, 8, 7, 9,<br /> 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };</p><p> private int curIndex, curByte, curBit;</p><p> public final byte[] inflate(byte data[], int startIdx, int size) {<br /> curIndex = startIdx;<br /> byte ret[] = new byte[size];<br /> int idx, bfinal, btype;<br /> idx = bfinal = btype = curByte = curBit = 0;<br /> do {<br /> bfinal = readBits(data, 1);<br /> btype = readBits(data, 2);<br /> if (btype == BTYPE_NONE) {<br /> curBit = 0;<br /> // LEN.<br /> int len = readBits(data, 16);<br /> // NLEN.<br /> readBits(data, 16);<br /> System.arraycopy(data, curIndex, ret, idx, len);<br /> curIndex += len;<br /> idx += len;<br /> } else {<br /> int literalTree[], distanceTree[];<br /> if (btype == BTYPE_DYNAMIC) {<br /> int hlit = readBits(data, 5) + 257;<br /> int hdist = readBits(data, 5) + 1;<br /> int hclen = readBits(data, 4) + 4;<br /> byte lengthBits[] = new byte[MAX_CODE_LENGTHS + 1];<br /> for (int i = 0; i < hclen; i++)<br /> lengthBits[DYNAMIC_LENGTH_ORDER[i]] = (byte) readBits(data, 3);<br /> int lengthTree[] = huffmanTree(lengthBits, MAX_CODE_LENGTHS);<br /> literalTree = huffmanTree(codeLengths(data,<br /> lengthTree, hlit), hlit - 1);<br /> distanceTree = huffmanTree(codeLengths(data,<br /> lengthTree, hdist), hdist - 1);<br /> } else {<br /> byte literalBits[] = new byte[MAX_CODE_LITERALS + 1];<br /> for (int i = 144; --i >= 0; literalBits[i] = 8);<br /> for (int i = 256; --i >= 144; literalBits[i] = 9);<br /> for (int i = 280; --i >= 256; literalBits[i] = 7);<br /> for (int i = 288; --i >= 280; literalBits[i] = 8);<br /> literalTree = huffmanTree(literalBits, MAX_CODE_LITERALS);</p><p> byte distanceBits[] = new byte[MAX_CODE_DISTANCES + 1];<br /> for (int i = distanceBits.length; --i >= 0; distanceBits[i] = 5);<br /> distanceTree = huffmanTree(distanceBits, MAX_CODE_DISTANCES);<br /> }<br /> int code = 0, leb = 0, deb = 0;<br /> while ((code = readCode(data, literalTree)) != EOB_CODE) {<br /> if (code > EOB_CODE) {<br /> code -= 257;<br /> int length = LENGTH_VALUES[code];<br /> if ((leb = LENGTH_EXTRA_BITS[code]) > 0)<br /> length += readBits(data, leb);<br /> code = readCode(data, distanceTree);<br /> int distance = DISTANCE_VALUES[code];<br /> if ((deb = DISTANCE_EXTRA_BITS[code]) > 0)<br /> distance += readBits(data, deb);<br /> int offset = idx - distance;<br /> while (distance < length) {<br /> System.arraycopy(ret, offset, ret, idx, distance);<br /> idx += distance;<br /> length -= distance;<br /> distance <<= 1;<br /> }<br /> System.arraycopy(ret, offset, ret, idx, length);<br /> idx += length;<br /> } else {<br /> ret[idx++] = (byte) code;<br /> }<br /> }<br /> }<br /> } while (bfinal == 0);<br /> return ret;<br /> }</p><p> private final int readBits(byte bb[], int n) {<br /> int data = (curBit == 0 ? (curByte = (bb[curIndex++] & 0xFF))<br /> : (curByte >> curBit));<br /> for (int i = (8 - curBit); i < n; i += 8) {<br /> curByte = (bb[curIndex++] & 0xFF);<br /> data |= (curByte << i);<br /> }<br /> curBit = (curBit + n) & 7;<br /> return (data & ((1 << n) - 1));<br /> }</p><p> private final int readCode(byte bb[], int tree[]) {<br /> int node = tree[0];<br /> while (node >= 0) {<br /> if (curBit == 0) curByte = (bb[curIndex++] & 0xFF);<br /> node = (((curByte & (1 << curBit)) == 0) ? tree[node >> 16]<br /> : tree[node & 0xFFFF]);<br /> curBit = (curBit + 1) & 7;<br /> }<br /> return (node & 0xFFFF);<br /> }</p><p> private final byte[] codeLengths(byte bb[], int lentree[], int count) {<br /> byte bits[] = new byte[count];<br /> for (int i = 0, code = 0, last = 0; i < count;) {<br /> code = readCode(bb, lentree);<br /> if (code >= 16) {<br /> int repeat = 0;<br /> if (code == 16) {<br /> repeat = 3 + readBits(bb, 2);<br /> code = last;<br /> } else {<br /> if (code == 17)<br /> repeat = 3 + readBits(bb, 3);<br /> else<br /> repeat = 11 + readBits(bb, 7);<br /> code = 0;<br /> }<br /> while (repeat-- > 0)<br /> bits[i++] = (byte) code;<br /> } else {<br /> bits[i++] = (byte) code;<br /> }<br /> last = code;<br /> }<br /> return bits;<br /> }</p><p> private final static int[] huffmanTree(byte bits[], int maxCode) {<br /> int bl_count[] = new int[MAX_BITS + 1];<br /> for (int i = 0, n = bits.length; i < n; i++)<br /> bl_count[bits[i]]++;<br /> int code = 0;<br /> bl_count[0] = 0;<br /> int next_code[] = new int[MAX_BITS + 1];<br /> for (int i = 1; i <= MAX_BITS; i++)<br /> next_code[i] = code = (code + bl_count[i - 1]) << 1;<br /> int tree[] = new int[(maxCode << 1) + MAX_BITS];<br /> int treeInsert = 1;<br /> for (int i = 0; i <= maxCode; i++) {<br /> int len = bits[i];<br /> if (len != 0) {<br /> code = next_code[len]++;<br /> int node = 0;<br /> for (int bit = len - 1; bit >= 0; bit--) {<br /> int value = code & (1 << bit);<br /> if (value == 0) {<br /> int left = tree[node] >> 16;<br /> if (left == 0) {<br /> tree[node] |= (treeInsert << 16);<br /> node = treeInsert++;<br /> } else<br /> node = left;<br /> } else {<br /> int right = tree[node] & 0xFFFF;<br /> if (right == 0) {<br /> tree[node] |= treeInsert;<br /> node = treeInsert++;<br /> } else<br /> node = right;<br /> }<br /> }<br /> tree[node] = 0x80000000 | i;<br /> }<br /> }<br /> return tree;<br /> }</p><p> private byte[] data;</p><p> private Hashtable htToc;</p><p> public ZipMe(byte[] data) {<br /> reset(data);<br /> }</p><p> public ZipMe(InputStream is) throws IOException {<br /> byte[] bb = inputStreamToBytes(is);<br /> reset(bb);<br /> }</p><p> public final ZipMe reset(byte[] data) {<br /> this.data = data;<br /> htToc = null;<br /> return this;<br /> }</p><p> public final Vector list() {<br /> Hashtable toc;<br /> if ((toc = htToc) == null) {<br /> toc = htToc = new Hashtable();<br /> int offset, i;<br /> offset = i = 0;<br /> for (;;) {<br /> int n = read(data, offset, 4);<br /> if (n != 0x04034B50) break; // end of data section<br /> offset += 8; // header,pkware_ver,global_flag<br /> int method = read(data, offset, 2);<br /> offset += 10; // method,date,time,crc<br /> int size = read(data, offset, 4);<br /> offset += 4; // compressed_size<br /> int orisize = read(data, offset, 4);<br /> offset += 4; // original_size<br /> int filenamelen = read(data, offset, 2);<br /> offset += 2;<br /> int extlen = read(data, offset, 2);<br /> offset += 2;<br /> String filename = new String(data, offset, filenamelen);<br /> offset += filenamelen + extlen;<br /> toc.put(filename, new int[] { offset, size, orisize, method, i++ } );<br /> offset += size;<br /> }<br /> }<br /> Vector ret = new Vector(toc.size());<br /> for (Enumeration e = toc.keys(); e.hasMoreElements();) {<br /> String filename = (String) e.nextElement();<br /> ret.add(filename);<br /> }<br /> return ret;<br /> }</p><p> public final byte[] get(String name) {<br /> if (htToc == null) list();<br /> int[] info = (int[]) htToc.get(name);<br /> if (info == null) return null;<br /> if (info[1] == 0) return new byte[0];<br /> if (info[3] == 0) { // store<br /> byte[] ret = new byte[info[2]];<br /> System.arraycopy(data, info[0], ret, 0, info[2]);<br /> return ret;<br /> } else if (info[3] == 8) { // deflate<br /> byte[] ret = inflate(data, info[0], info[2]);<br /> return ret;<br /> }<br /> return null;<br /> }</p><p> private static final int read(byte[] data, int offset, int len) {<br /> int ret = 0;<br /> for (int i = offset, j = 0, n = offset + len; i < n; i++, j += 8) {<br /> ret |= ((data[i] & 0xff) << j);<br /> }<br /> return ret;<br /> }</p><p> private static final byte[] inputStreamToBytes(InputStream is) throws IOException {<br /> ByteArrayOutputStream bos = new ByteArrayOutputStream();<br /> byte[] bb = new byte[10000];<br /> for (int len = is.read(bb); len > 0; len = is.read(bb)) {<br /> bos.write(bb, 0, len);<br /> }<br /> return bos.toByteArray();<br /> }</p><p>}<br />