实现在J2ME中解压缩ZIP文件 -- 未审核 编辑文档
超级短小精悍的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文件并逐一解压缩包中的所有文件:
1. InputStream is = "".getClass().getResourceAsStream("/res/test.zip");
2. ZipMe file = new ZipMe(is);
3. is.close();
4. Vector p = file.list();
5. for (int i = 0; i < p.size(); i++) {
6. String name = (String) p.get(i);
7. byte[] bb = file.get(name);
8. System.out.println("file: " + name + " / data_len: " + (bb != null ? bb.length : -1));
9. }
10.
11.
12.
13. ====================================================
14. package net.cnjm.j2me.utils;
15.
16. import java.io.*;
17. import java.util.*;
18.
19. public class ZipMe {
20.
21. private static final int BTYPE_NONE = 0;
22. private static final int BTYPE_DYNAMIC = 2;
23. private static final int MAX_BITS = 16;
24. private static final int MAX_CODE_LITERALS = 287;
25. private static final int MAX_CODE_DISTANCES = 31;
26. private static final int MAX_CODE_LENGTHS = 18;
27. private static final int EOB_CODE = 256;
28.
29. private static final int LENGTH_EXTRA_BITS[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1,
30. 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 };
31. private static final int LENGTH_VALUES[] = { 3, 4, 5, 6, 7, 8, 9, 10, 11,
32. 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,
33. 163, 195, 227, 258, 0, 0 };
34. private static final int DISTANCE_EXTRA_BITS[] = { 0, 0, 0, 0, 1, 1, 2, 2,
35. 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12,
36. 13, 13 };
37. private static final int DISTANCE_VALUES[] = { 1, 2, 3, 4, 5, 7, 9, 13, 17,
38. 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049,
39. 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
40. private static final int DYNAMIC_LENGTH_ORDER[] = { 16, 17, 18, 0, 8, 7, 9,
41. 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
42.
43. private int curIndex, curByte, curBit;
44.
45. public final byte[] inflate(byte data[], int startIdx, int size) {
46. curIndex = startIdx;
47. byte ret[] = new byte[size];
48. int idx, bfinal, btype;
49. idx = bfinal = btype = curByte = curBit = 0;
50. do {
51. bfinal = readBits(data, 1);
52. btype = readBits(data, 2);
53. if (btype == BTYPE_NONE) {
54. curBit = 0;
55. // LEN.
56. int len = readBits(data, 16);
57. // NLEN.
58. readBits(data, 16);
59. System.arraycopy(data, curIndex, ret, idx, len);
60. curIndex += len;
61. idx += len;
62. } else {
63. int literalTree[], distanceTree[];
64. if (btype == BTYPE_DYNAMIC) {
65. int hlit = readBits(data, 5) + 257;
66. int hdist = readBits(data, 5) + 1;
67. int hclen = readBits(data, 4) + 4;
68. byte lengthBits[] = new byte[MAX_CODE_LENGTHS + 1];
69. for (int i = 0; i < hclen; i++)
70. lengthBits[DYNAMIC_LENGTH_ORDER[i]] = (byte) readBits(data, 3);
71. int lengthTree[] = huffmanTree(lengthBits, MAX_CODE_LENGTHS);
72. literalTree = huffmanTree(codeLengths(data,
73. lengthTree, hlit), hlit - 1);
74. distanceTree = huffmanTree(codeLengths(data,
75. lengthTree, hdist), hdist - 1);
76. } else {
77. byte literalBits[] = new byte[MAX_CODE_LITERALS + 1];
78. for (int i = 144; --i >= 0; literalBits[i] = 8);
79. for (int i = 256; --i >= 144; literalBits[i] = 9);
80. for (int i = 280; --i >= 256; literalBits[i] = 7);
81. for (int i = 288; --i >= 280; literalBits[i] = 8);
82. literalTree = huffmanTree(literalBits, MAX_CODE_LITERALS);
83.
84. byte distanceBits[] = new byte[MAX_CODE_DISTANCES + 1];
85. for (int i = distanceBits.length; --i >= 0; distanceBits[i] = 5);
86. distanceTree = huffmanTree(distanceBits, MAX_CODE_DISTANCES);
87. }
88. int code = 0, leb = 0, deb = 0;
89. while ((code = readCode(data, literalTree)) != EOB_CODE) {
90. if (code > EOB_CODE) {
91. code -= 257;
92. int length = LENGTH_VALUES[code];
93. if ((leb = LENGTH_EXTRA_BITS[code]) > 0)
94. length += readBits(data, leb);
95. code = readCode(data, distanceTree);
96. int distance = DISTANCE_VALUES[code];
97. if ((deb = DISTANCE_EXTRA_BITS[code]) > 0)
98. distance += readBits(data, deb);
99. int offset = idx - distance;
100. while (distance < length) {
101. System.arraycopy(ret, offset, ret, idx, distance);
102. idx += distance;
103. length -= distance;
104. distance <<= 1;
105. }
106. System.arraycopy(ret, offset, ret, idx, length);
107. idx += length;
108. } else {
109. ret[idx++] = (byte) code;
110. }
111. }
112. }
113. } while (bfinal == 0);
114. return ret;
115. }
116.
117. private final int readBits(byte bb[], int n) {
118. int data = (curBit == 0 ? (curByte = (bb[curIndex++] & 0xFF))
119. : (curByte >> curBit));
120. for (int i = (8 - curBit); i < n; i += 8) {
121. curByte = (bb[curIndex++] & 0xFF);
122. data |= (curByte << i);
123. }
124. curBit = (curBit + n) & 7;
125. return (data & ((1 << n) - 1));
126. }
127.
128. private final int readCode(byte bb[], int tree[]) {
129. int node = tree[0];
130. while (node >= 0) {
131. if (curBit == 0) curByte = (bb[curIndex++] & 0xFF);
132. node = (((curByte & (1 << curBit)) == 0) ? tree[node >> 16]
133. : tree[node & 0xFFFF]);
134. curBit = (curBit + 1) & 7;
135. }
136. return (node & 0xFFFF);
137. }
138.
139. private final byte[] codeLengths(byte bb[], int lentree[], int count) {
140. byte bits[] = new byte[count];
141. for (int i = 0, code = 0, last = 0; i < count;) {
142. code = readCode(bb, lentree);
143. if (code >= 16) {
144. int repeat = 0;
145. if (code == 16) {
146. repeat = 3 + readBits(bb, 2);
147. code = last;
148. } else {
149. if (code == 17)
150. repeat = 3 + readBits(bb, 3);
151. else
152. repeat = 11 + readBits(bb, 7);
153. code = 0;
154. }
155. while (repeat-- > 0)
156. bits[i++] = (byte) code;
157. } else {
158. bits[i++] = (byte) code;
159. }
160. last = code;
161. }
162. return bits;
163. }
164.
165. private final static int[] huffmanTree(byte bits[], int maxCode) {
166. int bl_count[] = new int[MAX_BITS + 1];
167. for (int i = 0, n = bits.length; i < n; i++)
168. bl_count[bits[i]]++;
169. int code = 0;
170. bl_count[0] = 0;
171. int next_code[] = new int[MAX_BITS + 1];
172. for (int i = 1; i <= MAX_BITS; i++)
173. next_code[i] = code = (code + bl_count[i - 1]) << 1;
174. int tree[] = new int[(maxCode << 1) + MAX_BITS];
175. int treeInsert = 1;
176. for (int i = 0; i <= maxCode; i++) {
177. int len = bits[i];
178. if (len != 0) {
179. code = next_code[len]++;
180. int node = 0;
181. for (int bit = len - 1; bit >= 0; bit--) {
182. int value = code & (1 << bit);
183. if (value == 0) {
184. int left = tree[node] >> 16;
185. if (left == 0) {
186. tree[node] |= (treeInsert << 16);
187. node = treeInsert++;
188. } else
189. node = left;
190. } else {
191. int right = tree[node] & 0xFFFF;
192. if (right == 0) {
193. tree[node] |= treeInsert;
194. node = treeInsert++;
195. } else
196. node = right;
197. }
198. }
199. tree[node] = 0x80000000 | i;
200. }
201. }
202. return tree;
203. }
204.
205. private byte[] data;
206.
207. private Hashtable htToc;
208.
209. public ZipMe(byte[] data) {
210. reset(data);
211. }
212.
213. public ZipMe(InputStream is) throws IOException {
214. byte[] bb = inputStreamToBytes(is);
215. reset(bb);
216. }
217.
218. public final ZipMe reset(byte[] data) {
219. this.data = data;
220. htToc = null;
221. return this;
222. }
223.
224. public final Vector list() {
225. Hashtable toc;
226. if ((toc = htToc) == null) {
227. toc = htToc = new Hashtable();
228. int offset, i;
229. offset = i = 0;
230. for (;;) {
231. int n = read(data, offset, 4);
232. if (n != 0x04034B50) break; // end of data section
233. offset += 8; // header,pkware_ver,global_flag
234. int method = read(data, offset, 2);
235. offset += 10; // method,date,time,crc
236. int size = read(data, offset, 4);
237. offset += 4; // compressed_size
238. int orisize = read(data, offset, 4);
239. offset += 4; // original_size
240. int filenamelen = read(data, offset, 2);
241. offset += 2;
242. int extlen = read(data, offset, 2);
243. offset += 2;
244. String filename = new String(data, offset, filenamelen);
245. offset += filenamelen + extlen;
246. toc.put(filename, new int[] { offset, size, orisize, method, i++ } );
247. offset += size;
248. }
249. }
250. Vector ret = new Vector(toc.size());
251. for (Enumeration e = toc.keys(); e.hasMoreElements();) {
252. String filename = (String) e.nextElement();
253. ret.add(filename);
254. }
255. return ret;
256. }
257.
258. public final byte[] get(String name) {
259. if (htToc == null) list();
260. int[] info = (int[]) htToc.get(name);
261. if (info == null) return null;
262. if (info[1] == 0) return new byte[0];
263. if (info[3] == 0) { // store
264. byte[] ret = new byte[info[2]];
265. System.arraycopy(data, info[0], ret, 0, info[2]);
266. return ret;
267. } else if (info[3] == 8) { // deflate
268. byte[] ret = inflate(data, info[0], info[2]);
269. return ret;
270. }
271. return null;
272. }
273.
274. private static final int read(byte[] data, int offset, int len) {
275. int ret = 0;
276. for (int i = offset, j = 0, n = offset + len; i < n; i++, j += 8) {
277. ret |= ((data[i] & 0xff) << j);
278. }
279. return ret;
280. }
281.
282. private static final byte[] inputStreamToBytes(InputStream is) throws IOException {
283. ByteArrayOutputStream bos = new ByteArrayOutputStream();
284. byte[] bb = new byte[10000];
285. for (int len = is.read(bb); len > 0; len = is.read(bb)) {
286. bos.write(bb, 0, len);
287. }
288. return bos.toByteArray();
289. }
290.
/*
* GZIP library for j2me applications.
*
* Copyright (c) 2004-2006 Carlos Araiz (caraiz@java4ever.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.java4ever.apime.io;
import java.io.*;
/**
* Clase que permite leer ficheros GZIP.
*
* @author Carlos Araiz
*
* @version 1.2.0
*/
public class GZIP
{
// M醩caras para el flag.
private static final int FTEXT_MASK = 1;
private static final int FHCRC_MASK = 2;
private static final int FEXTRA_MASK = 4;
private static final int FNAME_MASK = 8;
private static final int FCOMMENT_MASK = 16;
// Tipos de bloques.
private static final int BTYPE_NONE = 0;
private static final int BTYPE_FIXED = 1;
private static final int BTYPE_DYNAMIC = 2;
private static final int BTYPE_RESERVED = 3;
// L韒ites.
private static final int MAX_BITS = 16;
private static final int MAX_CODE_LITERALS = 287;
private static final int MAX_CODE_DISTANCES = 31;
private static final int MAX_CODE_LENGTHS = 18;
private static final int EOB_CODE = 256;
// Datos prefijados (LENGTH: 257..287 / DISTANCE: 0..29 / DYNAMIC_LENGTH_ORDER: 0..18).
private static final int LENGTH_EXTRA_BITS[] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,99,99};
private static final int LENGTH_VALUES[] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0};
private static final int DISTANCE_EXTRA_BITS[] = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
private static final int DISTANCE_VALUES[] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577};
private static final int DYNAMIC_LENGTH_ORDER[] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
/*************************************************************************/
// Variables para la lectura de datos comprimidos.
private static int gzipIndex,gzipByte,gzipBit;
/*************************************************************************/
/*************************************************************************/
/**
* Descomprime un fichero GZIP.
*
* @param gzip Array con los datos del fichero comprimido
*
* @return Array con los datos descomprimidos
*/
public static byte[] inflate(byte gzip[]) throws IOException
{
// Inicializa.
gzipIndex=gzipByte=gzipBit=0;
// Cabecera.
if (readBits(gzip,16)!=0x8B1F||readBits(gzip,8)!=8) throw new IOException("Invalid GZIP format");
// Flag.
int flg=readBits(gzip,8);
// Fecha(4) / XFL(1) / OS(1).
gzipIndex+=6;
// Comprueba los flags.
if ((flg&FEXTRA_MASK)!=0) gzipIndex+=readBits(gzip,16);
if ((flg&FNAME_MASK)!=0) while (gzip[gzipIndex++]!=0);
if ((flg&FCOMMENT_MASK)!=0) while (gzip[gzipIndex++]!=0);
if ((flg&FHCRC_MASK)!=0) gzipIndex+=2;
// Tama駉 de los datos descomprimidos.
int index=gzipIndex;
gzipIndex=gzip.length-4;
byte uncompressed[]=new byte[readBits(gzip,16)|(readBits(gzip,16)<<16)];
int uncompressedIndex=0;
gzipIndex=index;
// Bloque con datos comprimidos.
int bfinal=0,btype=0;
do
{
// Lee la cabecera del bloque.
bfinal=readBits(gzip,1);
btype=readBits(gzip,2);
// Comprueba el tipo de compresi髇.
if (btype==BTYPE_NONE)
{
// Ignora los bits dentro del byte actual.
gzipBit=0;
// LEN.
int len=readBits(gzip,16);
// NLEN.
int nlen=readBits(gzip,16);
// Lee los datos.
System.arraycopy(gzip,gzipIndex,uncompressed,uncompressedIndex,len);
gzipIndex+=len;
// Actualiza el 韓dice de los datos descomprimidos.
uncompressedIndex+=len;
}
else
{
int literalTree[],distanceTree[];
if (btype==BTYPE_DYNAMIC)
{
// N鷐ero de datos de cada tipo.
int hlit=readBits(gzip,5)+257;
int hdist=readBits(gzip,5)+1;
int hclen=readBits(gzip,4)+4;
// Lee el n鷐ero de bits para cada c骴igo de longitud.
byte lengthBits[]=new byte[MAX_CODE_LENGTHS+1];
for (int i=0;i<hclen;i++) lengthBits[DYNAMIC_LENGTH_ORDER[i]]=(byte)readBits(gzip,3);
// Crea los c骴igos para la longitud.
int lengthTree[]=createHuffmanTree(lengthBits,MAX_CODE_LENGTHS);
// Genera los 醨boles.
literalTree=createHuffmanTree(decodeCodeLengths(gzip,lengthTree,hlit),hlit-1);
distanceTree=createHuffmanTree(decodeCodeLengths(gzip,lengthTree,hdist),hdist-1);
}
else
{
byte literalBits[]=new byte[MAX_CODE_LITERALS+1];
for (int i=0;i<144;i++) literalBits[i]=8;
for (int i=144;i<256;i++) literalBits[i]=9;
for (int i=256;i<280;i++) literalBits[i]=7;
for (int i=280;i<288;i++) literalBits[i]=8;
literalTree=createHuffmanTree(literalBits,MAX_CODE_LITERALS);
//
byte distanceBits[]=new byte[MAX_CODE_DISTANCES+1];
for (int i=0;i<distanceBits.length;i++) distanceBits[i]=5;
distanceTree=createHuffmanTree(distanceBits,MAX_CODE_DISTANCES);
}
// Descomprime el bloque.
int code=0,leb=0,deb=0;
while ((code=readCode(gzip,literalTree))!=EOB_CODE)
{
if (code>EOB_CODE)
{
code-=257;
int length=LENGTH_VALUES[code];
if ((leb=LENGTH_EXTRA_BITS[code])>0) length+=readBits(gzip,leb);
code=readCode(gzip,distanceTree);
int distance=DISTANCE_VALUES[code];
if ((deb=DISTANCE_EXTRA_BITS[code])>0) distance+=readBits(gzip,deb);
// Repite la informaci髇.
int offset=uncompressedIndex-distance;
while (distance<length)
{
System.arraycopy(uncompressed,offset,uncompressed,uncompressedIndex,distance);
uncompressedIndex+=distance;
length-=distance;
distance<<=1;
}
System.arraycopy(uncompressed,offset,uncompressed,uncompressedIndex,length);
uncompressedIndex+=length;
}
else uncompressed[uncompressedIndex++]=(byte)code;
}
}
}
while (bfinal==0);
//
return uncompressed;
}
/**
* Lee un n鷐ero de bits
*
* @param n N鷐ero de bits [0..16]
*/
private static int readBits(byte gzip[],int n)
{
// Asegura que tenemos un byte.
int data=(gzipBit==0?(gzipByte=(gzip[gzipIndex++]&0xFF)):(gzipByte>>gzipBit));
// Lee hasta completar los bits.
for (int i=(8-gzipBit);i<n;i+=8)
{
gzipByte=(gzip[gzipIndex++]&0xFF);
data|=(gzipByte<<i);
}
// Ajusta la posici髇 actual.
gzipBit=(gzipBit+n)&7;
// Devuelve el dato.
return (data&((1<<n)-1));
}
/**
* Lee un c骴igo.
*/
private static int readCode(byte gzip[],int tree[])
{
int node=tree[0];
while (node>=0)
{
// Lee un byte si es necesario.
if (gzipBit==0) gzipByte=(gzip[gzipIndex++]&0xFF);
// Accede al nodo correspondiente.
node=(((gzipByte&(1<<gzipBit))==0)?tree[node>>16]:tree[node&0xFFFF]);
// Ajusta la posici髇 actual.
gzipBit=(gzipBit+1)&7;
}
return (node&0xFFFF);
}
/**
* Decodifica la longitud de c骴igos (usado en bloques comprimidos con c骴igos din醡icos).
*/
private static byte[] decodeCodeLengths(byte gzip[],int lengthTree[],int count)
{
byte bits[]=new byte[count];
for (int i=0,code=0,last=0;i<count;)
{
code=readCode(gzip,lengthTree);
if (code>=16)
{
int repeat=0;
if (code==16)
{
repeat=3+readBits(gzip,2);
code=last;
}
else
{
if (code==17) repeat=3+readBits(gzip,3);
else repeat=11+readBits(gzip,7);
code=0;
}
while (repeat-->0) bits[i++]=(byte)code;
}
else bits[i++]=(byte)code;
//
last=code;
}
return bits;
}
/**
* Crea el 醨bol para los c骴igos Huffman.
*/
private static int[] createHuffmanTree(byte bits[],int maxCode)
{
// N鷐ero de c骴igos por cada longitud de c骴igo.
int bl_count[]=new int[MAX_BITS+1];
for (int i=0;i<bits.length;i++) bl_count[bits[i]]++;
// M韓imo valor num閞ico del c骴igo para cada longitud de c骴igo.
int code=0;
bl_count[0]=0;
int next_code[]=new int[MAX_BITS+1];
for (int i=1;i<=MAX_BITS;i++) next_code[i]=code=(code+bl_count[i-1])<<1;
// Genera el 醨bol.
// Bit 31 => Nodo (0) o c骴igo (1).
// (Nodo) bit 16..30 => 韓dice del nodo de la izquierda (0 si no tiene).
// (Nodo) bit 0..15 => 韓dice del nodo de la derecha (0 si no tiene).
// (C骴igo) bit 0..15
int tree[]=new int[(maxCode<<1)+MAX_BITS];
int treeInsert=1;
for (int i=0;i<=maxCode;i++)
{
int len=bits[i];
if (len!=0)
{
code=next_code[len]++;
// Lo mete en en 醨bol.
int node=0;
for (int bit=len-1;bit>=0;bit--)
{
int value=code&(1<<bit);
// Inserta a la izquierda.
if (value==0)
{
int left=tree[node]>>16;
if (left==0)
{
tree[node]|=(treeInsert<<16);
node=treeInsert++;
}
else node=left;
}
// Inserta a la derecha.
else
{
int right=tree[node]&0xFFFF;
if (right==0)
{
tree[node]|=treeInsert;
node=treeInsert++;
}
else node=right;
}
}
// Inserta el c骴igo.
tree[node]=0x80000000|i;
}
}
return tree;
}
}