1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45:
46:
58: public class ZipOutputStream extends DeflaterOutputStream implements ZipConstants
59: {
60: private Vector entries = new Vector();
61: private CRC32 crc = new CRC32();
62: private ZipEntry curEntry = null;
63:
64: private int curMethod;
65: private int size;
66: private int offset = 0;
67:
68: private byte[] zipComment = new byte[0];
69: private int defaultMethod = DEFLATED;
70:
71:
74: private static final int ZIP_STORED_VERSION = 10;
75: private static final int ZIP_DEFLATED_VERSION = 20;
76:
77:
80: public static final int STORED = 0;
81:
82:
85: public static final int DEFLATED = 8;
86:
87:
91: public ZipOutputStream(OutputStream out)
92: {
93: super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
94: }
95:
96:
102: public void setComment(String comment)
103: {
104: byte[] commentBytes;
105: commentBytes = comment.getBytes();
106: if (commentBytes.length > 0xffff)
107: throw new IllegalArgumentException("Comment too long.");
108: zipComment = commentBytes;
109: }
110:
111:
119: public void setMethod(int method)
120: {
121: if (method != STORED && method != DEFLATED)
122: throw new IllegalArgumentException("Method not supported.");
123: defaultMethod = method;
124: }
125:
126:
132: public void setLevel(int level)
133: {
134: def.setLevel(level);
135: }
136:
137:
140: private void writeLeShort(int value) throws IOException
141: {
142: out.write(value & 0xff);
143: out.write((value >> 8) & 0xff);
144: }
145:
146:
149: private void writeLeInt(int value) throws IOException
150: {
151: writeLeShort(value);
152: writeLeShort(value >> 16);
153: }
154:
155:
165: public void putNextEntry(ZipEntry entry) throws IOException
166: {
167: if (entries == null)
168: throw new ZipException("ZipOutputStream was finished");
169:
170: int method = entry.getMethod();
171: int flags = 0;
172: if (method == -1)
173: method = defaultMethod;
174:
175: if (method == STORED)
176: {
177: if (entry.getCompressedSize() >= 0)
178: {
179: if (entry.getSize() < 0)
180: entry.setSize(entry.getCompressedSize());
181: else if (entry.getSize() != entry.getCompressedSize())
182: throw new ZipException
183: ("Method STORED, but compressed size != size");
184: }
185: else
186: entry.setCompressedSize(entry.getSize());
187:
188: if (entry.getSize() < 0)
189: throw new ZipException("Method STORED, but size not set");
190: if (entry.getCrc() < 0)
191: throw new ZipException("Method STORED, but crc not set");
192: }
193: else if (method == DEFLATED)
194: {
195: if (entry.getCompressedSize() < 0
196: || entry.getSize() < 0 || entry.getCrc() < 0)
197: flags |= 8;
198: }
199:
200: if (curEntry != null)
201: closeEntry();
202:
203: if (entry.getTime() < 0)
204: entry.setTime(System.currentTimeMillis());
205:
206: entry.flags = flags;
207: entry.offset = offset;
208: entry.setMethod(method);
209: curMethod = method;
210:
211: writeLeInt(LOCSIG);
212: writeLeShort(method == STORED
213: ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
214: writeLeShort(flags);
215: writeLeShort(method);
216: writeLeInt(entry.getDOSTime());
217: if ((flags & 8) == 0)
218: {
219: writeLeInt((int)entry.getCrc());
220: writeLeInt((int)entry.getCompressedSize());
221: writeLeInt((int)entry.getSize());
222: }
223: else
224: {
225: writeLeInt(0);
226: writeLeInt(0);
227: writeLeInt(0);
228: }
229: byte[] name = entry.getName().getBytes();
230: if (name.length > 0xffff)
231: throw new ZipException("Name too long.");
232: byte[] extra = entry.getExtra();
233: if (extra == null)
234: extra = new byte[0];
235: writeLeShort(name.length);
236: writeLeShort(extra.length);
237: out.write(name);
238: out.write(extra);
239:
240: offset += LOCHDR + name.length + extra.length;
241:
242:
243:
244: curEntry = entry;
245: crc.reset();
246: if (method == DEFLATED)
247: def.reset();
248: size = 0;
249: }
250:
251:
256: public void closeEntry() throws IOException
257: {
258: if (curEntry == null)
259: throw new ZipException("No open entry");
260:
261:
262: if (curMethod == DEFLATED)
263: super.finish();
264:
265: int csize = curMethod == DEFLATED ? def.getTotalOut() : size;
266:
267: if (curEntry.getSize() < 0)
268: curEntry.setSize(size);
269: else if (curEntry.getSize() != size)
270: throw new ZipException("size was "+size
271: +", but I expected "+curEntry.getSize());
272:
273: if (curEntry.getCompressedSize() < 0)
274: curEntry.setCompressedSize(csize);
275: else if (curEntry.getCompressedSize() != csize)
276: throw new ZipException("compressed size was "+csize
277: +", but I expected "+curEntry.getSize());
278:
279: if (curEntry.getCrc() < 0)
280: curEntry.setCrc(crc.getValue());
281: else if (curEntry.getCrc() != crc.getValue())
282: throw new ZipException("crc was " + Long.toHexString(crc.getValue())
283: + ", but I expected "
284: + Long.toHexString(curEntry.getCrc()));
285:
286: offset += csize;
287:
288:
289: if (curMethod == DEFLATED && (curEntry.flags & 8) != 0)
290: {
291: writeLeInt(EXTSIG);
292: writeLeInt((int)curEntry.getCrc());
293: writeLeInt((int)curEntry.getCompressedSize());
294: writeLeInt((int)curEntry.getSize());
295: offset += EXTHDR;
296: }
297:
298: entries.addElement(curEntry);
299: curEntry = null;
300: }
301:
302:
307: public void write(byte[] b, int off, int len) throws IOException
308: {
309: if (curEntry == null)
310: throw new ZipException("No open entry.");
311:
312: switch (curMethod)
313: {
314: case DEFLATED:
315: super.write(b, off, len);
316: break;
317:
318: case STORED:
319: out.write(b, off, len);
320: break;
321: }
322:
323: crc.update(b, off, len);
324: size += len;
325: }
326:
327:
332: public void finish() throws IOException
333: {
334: if (entries == null)
335: return;
336: if (curEntry != null)
337: closeEntry();
338:
339: int numEntries = 0;
340: int sizeEntries = 0;
341:
342: Enumeration e = entries.elements();
343: while (e.hasMoreElements())
344: {
345: ZipEntry entry = (ZipEntry) e.nextElement();
346:
347: int method = entry.getMethod();
348: writeLeInt(CENSIG);
349: writeLeShort(method == STORED
350: ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
351: writeLeShort(method == STORED
352: ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
353: writeLeShort(entry.flags);
354: writeLeShort(method);
355: writeLeInt(entry.getDOSTime());
356: writeLeInt((int)entry.getCrc());
357: writeLeInt((int)entry.getCompressedSize());
358: writeLeInt((int)entry.getSize());
359:
360: byte[] name = entry.getName().getBytes();
361: if (name.length > 0xffff)
362: throw new ZipException("Name too long.");
363: byte[] extra = entry.getExtra();
364: if (extra == null)
365: extra = new byte[0];
366: String strComment = entry.getComment();
367: byte[] comment = strComment != null
368: ? strComment.getBytes() : new byte[0];
369: if (comment.length > 0xffff)
370: throw new ZipException("Comment too long.");
371:
372: writeLeShort(name.length);
373: writeLeShort(extra.length);
374: writeLeShort(comment.length);
375: writeLeShort(0);
376: writeLeShort(0);
377: writeLeInt(0);
378: writeLeInt(entry.offset);
379:
380: out.write(name);
381: out.write(extra);
382: out.write(comment);
383: numEntries++;
384: sizeEntries += CENHDR + name.length + extra.length + comment.length;
385: }
386:
387: writeLeInt(ENDSIG);
388: writeLeShort(0);
389: writeLeShort(0);
390: writeLeShort(numEntries);
391: writeLeShort(numEntries);
392: writeLeInt(sizeEntries);
393: writeLeInt(offset);
394: writeLeShort(zipComment.length);
395: out.write(zipComment);
396: out.flush();
397: entries = null;
398: }
399: }