Source Code Cross Referenced for ZipOutputStream.java in  » 6.0-JDK-Core » Collections-Jar-Zip-Logging-regex » java » util » zip » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » Collections Jar Zip Logging regex » java.util.zip 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 1996-2006 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025
026        package java.util.zip;
027
028        import java.io.OutputStream;
029        import java.io.IOException;
030        import java.util.Vector;
031        import java.util.HashSet;
032
033        /**
034         * This class implements an output stream filter for writing files in the
035         * ZIP file format. Includes support for both compressed and uncompressed
036         * entries.
037         *
038         * @author	David Connelly
039         * @version	1.41, 05/05/07
040         */
041        public class ZipOutputStream extends DeflaterOutputStream implements 
042                ZipConstants {
043
044            private static class XEntry {
045                public final ZipEntry entry;
046                public final long offset;
047                public final int flag;
048
049                public XEntry(ZipEntry entry, long offset) {
050                    this .entry = entry;
051                    this .offset = offset;
052                    this .flag = (entry.method == DEFLATED && (entry.size == -1
053                            || entry.csize == -1 || entry.crc == -1))
054                    // store size, compressed size, and crc-32 in data descriptor
055                    // immediately following the compressed entry data
056                    ? 8
057                            // store size, compressed size, and crc-32 in LOC header
058                            : 0;
059                }
060            }
061
062            private XEntry current;
063            private Vector<XEntry> xentries = new Vector<XEntry>();
064            private HashSet<String> names = new HashSet<String>();
065            private CRC32 crc = new CRC32();
066            private long written = 0;
067            private long locoff = 0;
068            private String comment;
069            private int method = DEFLATED;
070            private boolean finished;
071
072            private boolean closed = false;
073
074            private static int version(ZipEntry e) throws ZipException {
075                switch (e.method) {
076                case DEFLATED:
077                    return 20;
078                case STORED:
079                    return 10;
080                default:
081                    throw new ZipException("unsupported compression method");
082                }
083            }
084
085            /**
086             * Checks to make sure that this stream has not been closed.
087             */
088            private void ensureOpen() throws IOException {
089                if (closed) {
090                    throw new IOException("Stream closed");
091                }
092            }
093
094            /**
095             * Compression method for uncompressed (STORED) entries.
096             */
097            public static final int STORED = ZipEntry.STORED;
098
099            /**
100             * Compression method for compressed (DEFLATED) entries.
101             */
102            public static final int DEFLATED = ZipEntry.DEFLATED;
103
104            /**
105             * Creates a new ZIP output stream.
106             * @param out the actual output stream
107             */
108            public ZipOutputStream(OutputStream out) {
109                super (out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
110                usesDefaultDeflater = true;
111            }
112
113            /**
114             * Sets the ZIP file comment.
115             * @param comment the comment string
116             * @exception IllegalArgumentException if the length of the specified
117             *		  ZIP file comment is greater than 0xFFFF bytes
118             */
119            public void setComment(String comment) {
120                if (comment != null && comment.length() > 0xffff / 3
121                        && getUTF8Length(comment) > 0xffff) {
122                    throw new IllegalArgumentException(
123                            "ZIP file comment too long.");
124                }
125                this .comment = comment;
126            }
127
128            /**
129             * Sets the default compression method for subsequent entries. This
130             * default will be used whenever the compression method is not specified
131             * for an individual ZIP file entry, and is initially set to DEFLATED.
132             * @param method the default compression method
133             * @exception IllegalArgumentException if the specified compression method
134             *		  is invalid
135             */
136            public void setMethod(int method) {
137                if (method != DEFLATED && method != STORED) {
138                    throw new IllegalArgumentException(
139                            "invalid compression method");
140                }
141                this .method = method;
142            }
143
144            /**
145             * Sets the compression level for subsequent entries which are DEFLATED.
146             * The default setting is DEFAULT_COMPRESSION.
147             * @param level the compression level (0-9)
148             * @exception IllegalArgumentException if the compression level is invalid
149             */
150            public void setLevel(int level) {
151                def.setLevel(level);
152            }
153
154            /**
155             * Begins writing a new ZIP file entry and positions the stream to the
156             * start of the entry data. Closes the current entry if still active.
157             * The default compression method will be used if no compression method
158             * was specified for the entry, and the current time will be used if
159             * the entry has no set modification time.
160             * @param e the ZIP entry to be written
161             * @exception ZipException if a ZIP format error has occurred
162             * @exception IOException if an I/O error has occurred
163             */
164            public void putNextEntry(ZipEntry e) throws IOException {
165                ensureOpen();
166                if (current != null) {
167                    closeEntry(); // close previous entry
168                }
169                if (e.time == -1) {
170                    e.setTime(System.currentTimeMillis());
171                }
172                if (e.method == -1) {
173                    e.method = method; // use default method
174                }
175                switch (e.method) {
176                case DEFLATED:
177                    break;
178                case STORED:
179                    // compressed size, uncompressed size, and crc-32 must all be
180                    // set for entries using STORED compression method
181                    if (e.size == -1) {
182                        e.size = e.csize;
183                    } else if (e.csize == -1) {
184                        e.csize = e.size;
185                    } else if (e.size != e.csize) {
186                        throw new ZipException(
187                                "STORED entry where compressed != uncompressed size");
188                    }
189                    if (e.size == -1 || e.crc == -1) {
190                        throw new ZipException(
191                                "STORED entry missing size, compressed size, or crc-32");
192                    }
193                    break;
194                default:
195                    throw new ZipException("unsupported compression method");
196                }
197                if (!names.add(e.name)) {
198                    throw new ZipException("duplicate entry: " + e.name);
199                }
200                current = new XEntry(e, written);
201                xentries.add(current);
202                writeLOC(current);
203            }
204
205            /**
206             * Closes the current ZIP entry and positions the stream for writing
207             * the next entry.
208             * @exception ZipException if a ZIP format error has occurred
209             * @exception IOException if an I/O error has occurred
210             */
211            public void closeEntry() throws IOException {
212                ensureOpen();
213                if (current != null) {
214                    ZipEntry e = current.entry;
215                    switch (e.method) {
216                    case DEFLATED:
217                        def.finish();
218                        while (!def.finished()) {
219                            deflate();
220                        }
221                        if ((current.flag & 8) == 0) {
222                            // verify size, compressed size, and crc-32 settings
223                            if (e.size != def.getBytesRead()) {
224                                throw new ZipException(
225                                        "invalid entry size (expected "
226                                                + e.size + " but got "
227                                                + def.getBytesRead()
228                                                + " bytes)");
229                            }
230                            if (e.csize != def.getBytesWritten()) {
231                                throw new ZipException(
232                                        "invalid entry compressed size (expected "
233                                                + e.csize + " but got "
234                                                + def.getBytesWritten()
235                                                + " bytes)");
236                            }
237                            if (e.crc != crc.getValue()) {
238                                throw new ZipException(
239                                        "invalid entry CRC-32 (expected 0x"
240                                                + Long.toHexString(e.crc)
241                                                + " but got 0x"
242                                                + Long.toHexString(crc
243                                                        .getValue()) + ")");
244                            }
245                        } else {
246                            e.size = def.getBytesRead();
247                            e.csize = def.getBytesWritten();
248                            e.crc = crc.getValue();
249                            writeEXT(e);
250                        }
251                        def.reset();
252                        written += e.csize;
253                        break;
254                    case STORED:
255                        // we already know that both e.size and e.csize are the same
256                        if (e.size != written - locoff) {
257                            throw new ZipException(
258                                    "invalid entry size (expected " + e.size
259                                            + " but got " + (written - locoff)
260                                            + " bytes)");
261                        }
262                        if (e.crc != crc.getValue()) {
263                            throw new ZipException(
264                                    "invalid entry crc-32 (expected 0x"
265                                            + Long.toHexString(e.crc)
266                                            + " but got 0x"
267                                            + Long.toHexString(crc.getValue())
268                                            + ")");
269                        }
270                        break;
271                    default:
272                        throw new ZipException("invalid compression method");
273                    }
274                    crc.reset();
275                    current = null;
276                }
277            }
278
279            /**
280             * Writes an array of bytes to the current ZIP entry data. This method
281             * will block until all the bytes are written.
282             * @param b the data to be written
283             * @param off the start offset in the data
284             * @param len the number of bytes that are written
285             * @exception ZipException if a ZIP file error has occurred
286             * @exception IOException if an I/O error has occurred
287             */
288            public synchronized void write(byte[] b, int off, int len)
289                    throws IOException {
290                ensureOpen();
291                if (off < 0 || len < 0 || off > b.length - len) {
292                    throw new IndexOutOfBoundsException();
293                } else if (len == 0) {
294                    return;
295                }
296
297                if (current == null) {
298                    throw new ZipException("no current ZIP entry");
299                }
300                ZipEntry entry = current.entry;
301                switch (entry.method) {
302                case DEFLATED:
303                    super .write(b, off, len);
304                    break;
305                case STORED:
306                    written += len;
307                    if (written - locoff > entry.size) {
308                        throw new ZipException(
309                                "attempt to write past end of STORED entry");
310                    }
311                    out.write(b, off, len);
312                    break;
313                default:
314                    throw new ZipException("invalid compression method");
315                }
316                crc.update(b, off, len);
317            }
318
319            /**
320             * Finishes writing the contents of the ZIP output stream without closing
321             * the underlying stream. Use this method when applying multiple filters
322             * in succession to the same output stream.
323             * @exception ZipException if a ZIP file error has occurred
324             * @exception IOException if an I/O exception has occurred
325             */
326            public void finish() throws IOException {
327                ensureOpen();
328                if (finished) {
329                    return;
330                }
331                if (current != null) {
332                    closeEntry();
333                }
334                if (xentries.size() < 1) {
335                    throw new ZipException(
336                            "ZIP file must have at least one entry");
337                }
338                // write central directory
339                long off = written;
340                for (XEntry xentry : xentries)
341                    writeCEN(xentry);
342                writeEND(off, written - off);
343                finished = true;
344            }
345
346            /**
347             * Closes the ZIP output stream as well as the stream being filtered.
348             * @exception ZipException if a ZIP file error has occurred
349             * @exception IOException if an I/O error has occurred
350             */
351            public void close() throws IOException {
352                if (!closed) {
353                    super .close();
354                    closed = true;
355                }
356            }
357
358            /*
359             * Writes local file (LOC) header for specified entry.
360             */
361            private void writeLOC(XEntry xentry) throws IOException {
362                ZipEntry e = xentry.entry;
363                int flag = xentry.flag;
364                writeInt(LOCSIG); // LOC header signature
365                writeShort(version(e)); // version needed to extract
366                writeShort(flag); // general purpose bit flag
367                writeShort(e.method); // compression method
368                writeInt(e.time); // last modification time
369                if ((flag & 8) == 8) {
370                    // store size, uncompressed size, and crc-32 in data descriptor
371                    // immediately following compressed entry data
372                    writeInt(0);
373                    writeInt(0);
374                    writeInt(0);
375                } else {
376                    writeInt(e.crc); // crc-32
377                    writeInt(e.csize); // compressed size
378                    writeInt(e.size); // uncompressed size
379                }
380                byte[] nameBytes = getUTF8Bytes(e.name);
381                writeShort(nameBytes.length);
382                writeShort(e.extra != null ? e.extra.length : 0);
383                writeBytes(nameBytes, 0, nameBytes.length);
384                if (e.extra != null) {
385                    writeBytes(e.extra, 0, e.extra.length);
386                }
387                locoff = written;
388            }
389
390            /*
391             * Writes extra data descriptor (EXT) for specified entry.
392             */
393            private void writeEXT(ZipEntry e) throws IOException {
394                writeInt(EXTSIG); // EXT header signature
395                writeInt(e.crc); // crc-32
396                writeInt(e.csize); // compressed size
397                writeInt(e.size); // uncompressed size
398            }
399
400            /*
401             * Write central directory (CEN) header for specified entry.
402             * REMIND: add support for file attributes
403             */
404            private void writeCEN(XEntry xentry) throws IOException {
405                ZipEntry e = xentry.entry;
406                int flag = xentry.flag;
407                int version = version(e);
408                writeInt(CENSIG); // CEN header signature
409                writeShort(version); // version made by
410                writeShort(version); // version needed to extract
411                writeShort(flag); // general purpose bit flag
412                writeShort(e.method); // compression method
413                writeInt(e.time); // last modification time
414                writeInt(e.crc); // crc-32
415                writeInt(e.csize); // compressed size
416                writeInt(e.size); // uncompressed size
417                byte[] nameBytes = getUTF8Bytes(e.name);
418                writeShort(nameBytes.length);
419                writeShort(e.extra != null ? e.extra.length : 0);
420                byte[] commentBytes;
421                if (e.comment != null) {
422                    commentBytes = getUTF8Bytes(e.comment);
423                    writeShort(commentBytes.length);
424                } else {
425                    commentBytes = null;
426                    writeShort(0);
427                }
428                writeShort(0); // starting disk number
429                writeShort(0); // internal file attributes (unused)
430                writeInt(0); // external file attributes (unused)
431                writeInt(xentry.offset); // relative offset of local header
432                writeBytes(nameBytes, 0, nameBytes.length);
433                if (e.extra != null) {
434                    writeBytes(e.extra, 0, e.extra.length);
435                }
436                if (commentBytes != null) {
437                    writeBytes(commentBytes, 0, commentBytes.length);
438                }
439            }
440
441            /*
442             * Writes end of central directory (END) header.
443             */
444            private void writeEND(long off, long len) throws IOException {
445                int count = xentries.size();
446                writeInt(ENDSIG); // END record signature
447                writeShort(0); // number of this disk
448                writeShort(0); // central directory start disk
449                writeShort(count); // number of directory entries on disk
450                writeShort(count); // total number of directory entries
451                writeInt(len); // length of central directory
452                writeInt(off); // offset of central directory
453                if (comment != null) { // zip file comment
454                    byte[] b = getUTF8Bytes(comment);
455                    writeShort(b.length);
456                    writeBytes(b, 0, b.length);
457                } else {
458                    writeShort(0);
459                }
460            }
461
462            /*
463             * Writes a 16-bit short to the output stream in little-endian byte order.
464             */
465            private void writeShort(int v) throws IOException {
466                OutputStream out = this .out;
467                out.write((v >>> 0) & 0xff);
468                out.write((v >>> 8) & 0xff);
469                written += 2;
470            }
471
472            /*
473             * Writes a 32-bit int to the output stream in little-endian byte order.
474             */
475            private void writeInt(long v) throws IOException {
476                OutputStream out = this .out;
477                out.write((int) ((v >>> 0) & 0xff));
478                out.write((int) ((v >>> 8) & 0xff));
479                out.write((int) ((v >>> 16) & 0xff));
480                out.write((int) ((v >>> 24) & 0xff));
481                written += 4;
482            }
483
484            /*
485             * Writes an array of bytes to the output stream.
486             */
487            private void writeBytes(byte[] b, int off, int len)
488                    throws IOException {
489                super .out.write(b, off, len);
490                written += len;
491            }
492
493            /*
494             * Returns the length of String's UTF8 encoding.
495             */
496            static int getUTF8Length(String s) {
497                int count = 0;
498                for (int i = 0; i < s.length(); i++) {
499                    char ch = s.charAt(i);
500                    if (ch <= 0x7f) {
501                        count++;
502                    } else if (ch <= 0x7ff) {
503                        count += 2;
504                    } else {
505                        count += 3;
506                    }
507                }
508                return count;
509            }
510
511            /*
512             * Returns an array of bytes representing the UTF8 encoding
513             * of the specified String.
514             */
515            private static byte[] getUTF8Bytes(String s) {
516                char[] c = s.toCharArray();
517                int len = c.length;
518                // Count the number of encoded bytes...
519                int count = 0;
520                for (int i = 0; i < len; i++) {
521                    int ch = c[i];
522                    if (ch <= 0x7f) {
523                        count++;
524                    } else if (ch <= 0x7ff) {
525                        count += 2;
526                    } else {
527                        count += 3;
528                    }
529                }
530                // Now return the encoded bytes...
531                byte[] b = new byte[count];
532                int off = 0;
533                for (int i = 0; i < len; i++) {
534                    int ch = c[i];
535                    if (ch <= 0x7f) {
536                        b[off++] = (byte) ch;
537                    } else if (ch <= 0x7ff) {
538                        b[off++] = (byte) ((ch >> 6) | 0xc0);
539                        b[off++] = (byte) ((ch & 0x3f) | 0x80);
540                    } else {
541                        b[off++] = (byte) ((ch >> 12) | 0xe0);
542                        b[off++] = (byte) (((ch >> 6) & 0x3f) | 0x80);
543                        b[off++] = (byte) ((ch & 0x3f) | 0x80);
544                    }
545                }
546                return b;
547            }
548        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.