Source Code Cross Referenced for ZipOutputStream.java in  » Build » ANT » org » apache » tools » zip » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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 geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Build » ANT » org.apache.tools.zip 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
003:         *  contributor license agreements.  See the NOTICE file distributed with
004:         *  this work for additional information regarding copyright ownership.
005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
006:         *  (the "License"); you may not use this file except in compliance with
007:         *  the License.  You may obtain a copy of the License at
008:         *
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         *  Unless required by applicable law or agreed to in writing, software
012:         *  distributed under the License is distributed on an "AS IS" BASIS,
013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         *  See the License for the specific language governing permissions and
015:         *  limitations under the License.
016:         *
017:         */
018:
019:        package org.apache.tools.zip;
020:
021:        import java.io.File;
022:        import java.io.FileOutputStream;
023:        import java.io.FilterOutputStream;
024:        import java.io.IOException;
025:        import java.io.OutputStream;
026:        import java.io.RandomAccessFile;
027:        import java.io.UnsupportedEncodingException;
028:        import java.util.Date;
029:        import java.util.Hashtable;
030:        import java.util.Vector;
031:        import java.util.zip.CRC32;
032:        import java.util.zip.Deflater;
033:        import java.util.zip.ZipException;
034:
035:        /**
036:         * Reimplementation of {@link java.util.zip.ZipOutputStream
037:         * java.util.zip.ZipOutputStream} that does handle the extended
038:         * functionality of this package, especially internal/external file
039:         * attributes and extra fields with different layouts for local file
040:         * data and central directory entries.
041:         *
042:         * <p>This class will try to use {@link java.io.RandomAccessFile
043:         * RandomAccessFile} when you know that the output is going to go to a
044:         * file.</p>
045:         *
046:         * <p>If RandomAccessFile cannot be used, this implementation will use
047:         * a Data Descriptor to store size and CRC information for {@link
048:         * #DEFLATED DEFLATED} entries, this means, you don't need to
049:         * calculate them yourself.  Unfortunately this is not possible for
050:         * the {@link #STORED STORED} method, here setting the CRC and
051:         * uncompressed size information is required before {@link
052:         * #putNextEntry putNextEntry} can be called.</p>
053:         *
054:         */
055:        public class ZipOutputStream extends FilterOutputStream {
056:
057:            /**
058:             * Compression method for deflated entries.
059:             *
060:             * @since 1.1
061:             */
062:            public static final int DEFLATED = java.util.zip.ZipEntry.DEFLATED;
063:
064:            /**
065:             * Default compression level for deflated entries.
066:             *
067:             * @since Ant 1.7
068:             */
069:            public static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION;
070:
071:            /**
072:             * Compression method for stored entries.
073:             *
074:             * @since 1.1
075:             */
076:            public static final int STORED = java.util.zip.ZipEntry.STORED;
077:
078:            /**
079:             * Current entry.
080:             *
081:             * @since 1.1
082:             */
083:            private ZipEntry entry;
084:
085:            /**
086:             * The file comment.
087:             *
088:             * @since 1.1
089:             */
090:            private String comment = "";
091:
092:            /**
093:             * Compression level for next entry.
094:             *
095:             * @since 1.1
096:             */
097:            private int level = DEFAULT_COMPRESSION;
098:
099:            /**
100:             * Has the compression level changed when compared to the last
101:             * entry?
102:             *
103:             * @since 1.5
104:             */
105:            private boolean hasCompressionLevelChanged = false;
106:
107:            /**
108:             * Default compression method for next entry.
109:             *
110:             * @since 1.1
111:             */
112:            private int method = java.util.zip.ZipEntry.DEFLATED;
113:
114:            /**
115:             * List of ZipEntries written so far.
116:             *
117:             * @since 1.1
118:             */
119:            private Vector entries = new Vector();
120:
121:            /**
122:             * CRC instance to avoid parsing DEFLATED data twice.
123:             *
124:             * @since 1.1
125:             */
126:            private CRC32 crc = new CRC32();
127:
128:            /**
129:             * Count the bytes written to out.
130:             *
131:             * @since 1.1
132:             */
133:            private long written = 0;
134:
135:            /**
136:             * Data for local header data
137:             *
138:             * @since 1.1
139:             */
140:            private long dataStart = 0;
141:
142:            /**
143:             * Offset for CRC entry in the local file header data for the
144:             * current entry starts here.
145:             *
146:             * @since 1.15
147:             */
148:            private long localDataStart = 0;
149:
150:            /**
151:             * Start of central directory.
152:             *
153:             * @since 1.1
154:             */
155:            private long cdOffset = 0;
156:
157:            /**
158:             * Length of central directory.
159:             *
160:             * @since 1.1
161:             */
162:            private long cdLength = 0;
163:
164:            /**
165:             * Helper, a 0 as ZipShort.
166:             *
167:             * @since 1.1
168:             */
169:            private static final byte[] ZERO = { 0, 0 };
170:
171:            /**
172:             * Helper, a 0 as ZipLong.
173:             *
174:             * @since 1.1
175:             */
176:            private static final byte[] LZERO = { 0, 0, 0, 0 };
177:
178:            /**
179:             * Holds the offsets of the LFH starts for each entry.
180:             *
181:             * @since 1.1
182:             */
183:            private Hashtable offsets = new Hashtable();
184:
185:            /**
186:             * The encoding to use for filenames and the file comment.
187:             *
188:             * <p>For a list of possible values see <a
189:             * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
190:             * Defaults to the platform's default character encoding.</p>
191:             *
192:             * @since 1.3
193:             */
194:            private String encoding = null;
195:
196:            // CheckStyle:VisibilityModifier OFF - bc
197:
198:            /**
199:             * This Deflater object is used for output.
200:             *
201:             * <p>This attribute is only protected to provide a level of API
202:             * backwards compatibility.  This class used to extend {@link
203:             * java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to
204:             * Revision 1.13.</p>
205:             *
206:             * @since 1.14
207:             */
208:            protected Deflater def = new Deflater(level, true);
209:
210:            /**
211:             * This buffer servers as a Deflater.
212:             *
213:             * <p>This attribute is only protected to provide a level of API
214:             * backwards compatibility.  This class used to extend {@link
215:             * java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to
216:             * Revision 1.13.</p>
217:             *
218:             * @since 1.14
219:             */
220:            protected byte[] buf = new byte[512];
221:
222:            // CheckStyle:VisibilityModifier ON
223:
224:            /**
225:             * Optional random access output.
226:             *
227:             * @since 1.14
228:             */
229:            private RandomAccessFile raf = null;
230:
231:            /**
232:             * Creates a new ZIP OutputStream filtering the underlying stream.
233:             * @param out the outputstream to zip
234:             * @since 1.1
235:             */
236:            public ZipOutputStream(OutputStream out) {
237:                super (out);
238:            }
239:
240:            /**
241:             * Creates a new ZIP OutputStream writing to a File.  Will use
242:             * random access if possible.
243:             * @param file the file to zip to
244:             * @since 1.14
245:             * @throws IOException on error
246:             */
247:            public ZipOutputStream(File file) throws IOException {
248:                super (null);
249:
250:                try {
251:                    raf = new RandomAccessFile(file, "rw");
252:                    raf.setLength(0);
253:                } catch (IOException e) {
254:                    if (raf != null) {
255:                        try {
256:                            raf.close();
257:                        } catch (IOException inner) {
258:                            // ignore
259:                        }
260:                        raf = null;
261:                    }
262:                    out = new FileOutputStream(file);
263:                }
264:            }
265:
266:            /**
267:             * This method indicates whether this archive is writing to a seekable stream (i.e., to a random
268:             * access file).
269:             *
270:             * <p>For seekable streams, you don't need to calculate the CRC or
271:             * uncompressed size for {@link #STORED} entries before
272:             * invoking {@link #putNextEntry}.
273:             * @return true if seekable
274:             * @since 1.17
275:             */
276:            public boolean isSeekable() {
277:                return raf != null;
278:            }
279:
280:            /**
281:             * The encoding to use for filenames and the file comment.
282:             *
283:             * <p>For a list of possible values see <a
284:             * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
285:             * Defaults to the platform's default character encoding.</p>
286:             * @param encoding the encoding value
287:             * @since 1.3
288:             */
289:            public void setEncoding(String encoding) {
290:                this .encoding = encoding;
291:            }
292:
293:            /**
294:             * The encoding to use for filenames and the file comment.
295:             *
296:             * @return null if using the platform's default character encoding.
297:             *
298:             * @since 1.3
299:             */
300:            public String getEncoding() {
301:                return encoding;
302:            }
303:
304:            /**
305:             * Finishs writing the contents and closes this as well as the
306:             * underlying stream.
307:             *
308:             * @since 1.1
309:             * @throws IOException on error
310:             */
311:            public void finish() throws IOException {
312:                closeEntry();
313:                cdOffset = written;
314:                for (int i = 0, entriesSize = entries.size(); i < entriesSize; i++) {
315:                    writeCentralFileHeader((ZipEntry) entries.elementAt(i));
316:                }
317:                cdLength = written - cdOffset;
318:                writeCentralDirectoryEnd();
319:                offsets.clear();
320:                entries.removeAllElements();
321:            }
322:
323:            /**
324:             * Writes all necessary data for this entry.
325:             *
326:             * @since 1.1
327:             * @throws IOException on error
328:             */
329:            public void closeEntry() throws IOException {
330:                if (entry == null) {
331:                    return;
332:                }
333:
334:                long realCrc = crc.getValue();
335:                crc.reset();
336:
337:                if (entry.getMethod() == DEFLATED) {
338:                    def.finish();
339:                    while (!def.finished()) {
340:                        deflate();
341:                    }
342:
343:                    entry.setSize(adjustToLong(def.getTotalIn()));
344:                    entry.setCompressedSize(adjustToLong(def.getTotalOut()));
345:                    entry.setCrc(realCrc);
346:
347:                    def.reset();
348:
349:                    written += entry.getCompressedSize();
350:                } else if (raf == null) {
351:                    if (entry.getCrc() != realCrc) {
352:                        throw new ZipException("bad CRC checksum for entry "
353:                                + entry.getName() + ": "
354:                                + Long.toHexString(entry.getCrc())
355:                                + " instead of " + Long.toHexString(realCrc));
356:                    }
357:
358:                    if (entry.getSize() != written - dataStart) {
359:                        throw new ZipException("bad size for entry "
360:                                + entry.getName() + ": " + entry.getSize()
361:                                + " instead of " + (written - dataStart));
362:                    }
363:                } else { /* method is STORED and we used RandomAccessFile */
364:                    long size = written - dataStart;
365:
366:                    entry.setSize(size);
367:                    entry.setCompressedSize(size);
368:                    entry.setCrc(realCrc);
369:                }
370:
371:                // If random access output, write the local file header containing
372:                // the correct CRC and compressed/uncompressed sizes
373:                if (raf != null) {
374:                    long save = raf.getFilePointer();
375:
376:                    raf.seek(localDataStart);
377:                    writeOut(ZipLong.getBytes(entry.getCrc()));
378:                    writeOut(ZipLong.getBytes(entry.getCompressedSize()));
379:                    writeOut(ZipLong.getBytes(entry.getSize()));
380:                    raf.seek(save);
381:                }
382:
383:                writeDataDescriptor(entry);
384:                entry = null;
385:            }
386:
387:            /**
388:             * Begin writing next entry.
389:             * @param ze the entry to write
390:             * @since 1.1
391:             * @throws IOException on error
392:             */
393:            public void putNextEntry(ZipEntry ze) throws IOException {
394:                closeEntry();
395:
396:                entry = ze;
397:                entries.addElement(entry);
398:
399:                if (entry.getMethod() == -1) { // not specified
400:                    entry.setMethod(method);
401:                }
402:
403:                if (entry.getTime() == -1) { // not specified
404:                    entry.setTime(System.currentTimeMillis());
405:                }
406:
407:                // Size/CRC not required if RandomAccessFile is used
408:                if (entry.getMethod() == STORED && raf == null) {
409:                    if (entry.getSize() == -1) {
410:                        throw new ZipException(
411:                                "uncompressed size is required for"
412:                                        + " STORED method when not writing to a"
413:                                        + " file");
414:                    }
415:                    if (entry.getCrc() == -1) {
416:                        throw new ZipException(
417:                                "crc checksum is required for STORED"
418:                                        + " method when not writing to a file");
419:                    }
420:                    entry.setCompressedSize(entry.getSize());
421:                }
422:
423:                if (entry.getMethod() == DEFLATED && hasCompressionLevelChanged) {
424:                    def.setLevel(level);
425:                    hasCompressionLevelChanged = false;
426:                }
427:                writeLocalFileHeader(entry);
428:            }
429:
430:            /**
431:             * Set the file comment.
432:             * @param comment the comment
433:             * @since 1.1
434:             */
435:            public void setComment(String comment) {
436:                this .comment = comment;
437:            }
438:
439:            /**
440:             * Sets the compression level for subsequent entries.
441:             *
442:             * <p>Default is Deflater.DEFAULT_COMPRESSION.</p>
443:             * @param level the compression level.
444:             * @throws IllegalArgumentException if an invalid compression level is specified.
445:             * @since 1.1
446:             */
447:            public void setLevel(int level) {
448:                if (level < Deflater.DEFAULT_COMPRESSION
449:                        || level > Deflater.BEST_COMPRESSION) {
450:                    throw new IllegalArgumentException(
451:                            "Invalid compression level: " + level);
452:                }
453:                hasCompressionLevelChanged = (this .level != level);
454:                this .level = level;
455:            }
456:
457:            /**
458:             * Sets the default compression method for subsequent entries.
459:             *
460:             * <p>Default is DEFLATED.</p>
461:             * @param method an <code>int</code> from java.util.zip.ZipEntry
462:             * @since 1.1
463:             */
464:            public void setMethod(int method) {
465:                this .method = method;
466:            }
467:
468:            /**
469:             * Writes bytes to ZIP entry.
470:             * @param b the byte array to write
471:             * @param offset the start position to write from
472:             * @param length the number of bytes to write
473:             * @throws IOException on error
474:             */
475:            public void write(byte[] b, int offset, int length)
476:                    throws IOException {
477:                if (entry.getMethod() == DEFLATED) {
478:                    if (length > 0) {
479:                        if (!def.finished()) {
480:                            def.setInput(b, offset, length);
481:                            while (!def.needsInput()) {
482:                                deflate();
483:                            }
484:                        }
485:                    }
486:                } else {
487:                    writeOut(b, offset, length);
488:                    written += length;
489:                }
490:                crc.update(b, offset, length);
491:            }
492:
493:            /**
494:             * Writes a single byte to ZIP entry.
495:             *
496:             * <p>Delegates to the three arg method.</p>
497:             * @param b the byte to write
498:             * @since 1.14
499:             * @throws IOException on error
500:             */
501:            public void write(int b) throws IOException {
502:                byte[] buff = new byte[1];
503:                buff[0] = (byte) (b & 0xff);
504:                write(buff, 0, 1);
505:            }
506:
507:            /**
508:             * Closes this output stream and releases any system resources
509:             * associated with the stream.
510:             *
511:             * @exception  IOException  if an I/O error occurs.
512:             * @since 1.14
513:             */
514:            public void close() throws IOException {
515:                finish();
516:
517:                if (raf != null) {
518:                    raf.close();
519:                }
520:                if (out != null) {
521:                    out.close();
522:                }
523:            }
524:
525:            /**
526:             * Flushes this output stream and forces any buffered output bytes
527:             * to be written out to the stream.
528:             *
529:             * @exception  IOException  if an I/O error occurs.
530:             * @since 1.14
531:             */
532:            public void flush() throws IOException {
533:                if (out != null) {
534:                    out.flush();
535:                }
536:            }
537:
538:            /*
539:             * Various ZIP constants
540:             */
541:            /**
542:             * local file header signature
543:             *
544:             * @since 1.1
545:             */
546:            protected static final byte[] LFH_SIG = ZipLong
547:                    .getBytes(0X04034B50L);
548:            /**
549:             * data descriptor signature
550:             *
551:             * @since 1.1
552:             */
553:            protected static final byte[] DD_SIG = ZipLong
554:                    .getBytes(0X08074B50L);
555:            /**
556:             * central file header signature
557:             *
558:             * @since 1.1
559:             */
560:            protected static final byte[] CFH_SIG = ZipLong
561:                    .getBytes(0X02014B50L);
562:            /**
563:             * end of central dir signature
564:             *
565:             * @since 1.1
566:             */
567:            protected static final byte[] EOCD_SIG = ZipLong
568:                    .getBytes(0X06054B50L);
569:
570:            /**
571:             * Writes next block of compressed data to the output stream.
572:             * @throws IOException on error
573:             *
574:             * @since 1.14
575:             */
576:            protected final void deflate() throws IOException {
577:                int len = def.deflate(buf, 0, buf.length);
578:                if (len > 0) {
579:                    writeOut(buf, 0, len);
580:                }
581:            }
582:
583:            /**
584:             * Writes the local file header entry
585:             * @param ze the entry to write
586:             * @throws IOException on error
587:             *
588:             * @since 1.1
589:             */
590:            protected void writeLocalFileHeader(ZipEntry ze) throws IOException {
591:                offsets.put(ze, ZipLong.getBytes(written));
592:
593:                writeOut(LFH_SIG);
594:                written += 4;
595:
596:                //store method in local variable to prevent multiple method calls
597:                final int zipMethod = ze.getMethod();
598:
599:                // version needed to extract
600:                // general purpose bit flag
601:                if (zipMethod == DEFLATED && raf == null) {
602:                    // requires version 2 as we are going to store length info
603:                    // in the data descriptor
604:                    writeOut(ZipShort.getBytes(20));
605:
606:                    // bit3 set to signal, we use a data descriptor
607:                    writeOut(ZipShort.getBytes(8));
608:                } else {
609:                    writeOut(ZipShort.getBytes(10));
610:                    writeOut(ZERO);
611:                }
612:                written += 4;
613:
614:                // compression method
615:                writeOut(ZipShort.getBytes(zipMethod));
616:                written += 2;
617:
618:                // last mod. time and date
619:                writeOut(toDosTime(ze.getTime()));
620:                written += 4;
621:
622:                // CRC
623:                // compressed length
624:                // uncompressed length
625:                localDataStart = written;
626:                if (zipMethod == DEFLATED || raf != null) {
627:                    writeOut(LZERO);
628:                    writeOut(LZERO);
629:                    writeOut(LZERO);
630:                } else {
631:                    writeOut(ZipLong.getBytes(ze.getCrc()));
632:                    writeOut(ZipLong.getBytes(ze.getSize()));
633:                    writeOut(ZipLong.getBytes(ze.getSize()));
634:                }
635:                written += 12;
636:
637:                // file name length
638:                byte[] name = getBytes(ze.getName());
639:                writeOut(ZipShort.getBytes(name.length));
640:                written += 2;
641:
642:                // extra field length
643:                byte[] extra = ze.getLocalFileDataExtra();
644:                writeOut(ZipShort.getBytes(extra.length));
645:                written += 2;
646:
647:                // file name
648:                writeOut(name);
649:                written += name.length;
650:
651:                // extra field
652:                writeOut(extra);
653:                written += extra.length;
654:
655:                dataStart = written;
656:            }
657:
658:            /**
659:             * Writes the data descriptor entry.
660:             * @param ze the entry to write
661:             * @throws IOException on error
662:             *
663:             * @since 1.1
664:             */
665:            protected void writeDataDescriptor(ZipEntry ze) throws IOException {
666:                if (ze.getMethod() != DEFLATED || raf != null) {
667:                    return;
668:                }
669:                writeOut(DD_SIG);
670:                writeOut(ZipLong.getBytes(entry.getCrc()));
671:                writeOut(ZipLong.getBytes(entry.getCompressedSize()));
672:                writeOut(ZipLong.getBytes(entry.getSize()));
673:                written += 16;
674:            }
675:
676:            /**
677:             * Writes the central file header entry.
678:             * @param ze the entry to write
679:             * @throws IOException on error
680:             *
681:             * @since 1.1
682:             */
683:            protected void writeCentralFileHeader(ZipEntry ze)
684:                    throws IOException {
685:                writeOut(CFH_SIG);
686:                written += 4;
687:
688:                // version made by
689:                writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 20));
690:                written += 2;
691:
692:                // version needed to extract
693:                // general purpose bit flag
694:                if (ze.getMethod() == DEFLATED && raf == null) {
695:                    // requires version 2 as we are going to store length info
696:                    // in the data descriptor
697:                    writeOut(ZipShort.getBytes(20));
698:
699:                    // bit3 set to signal, we use a data descriptor
700:                    writeOut(ZipShort.getBytes(8));
701:                } else {
702:                    writeOut(ZipShort.getBytes(10));
703:                    writeOut(ZERO);
704:                }
705:                written += 4;
706:
707:                // compression method
708:                writeOut(ZipShort.getBytes(ze.getMethod()));
709:                written += 2;
710:
711:                // last mod. time and date
712:                writeOut(toDosTime(ze.getTime()));
713:                written += 4;
714:
715:                // CRC
716:                // compressed length
717:                // uncompressed length
718:                writeOut(ZipLong.getBytes(ze.getCrc()));
719:                writeOut(ZipLong.getBytes(ze.getCompressedSize()));
720:                writeOut(ZipLong.getBytes(ze.getSize()));
721:                written += 12;
722:
723:                // file name length
724:                byte[] name = getBytes(ze.getName());
725:                writeOut(ZipShort.getBytes(name.length));
726:                written += 2;
727:
728:                // extra field length
729:                byte[] extra = ze.getCentralDirectoryExtra();
730:                writeOut(ZipShort.getBytes(extra.length));
731:                written += 2;
732:
733:                // file comment length
734:                String comm = ze.getComment();
735:                if (comm == null) {
736:                    comm = "";
737:                }
738:                byte[] commentB = getBytes(comm);
739:                writeOut(ZipShort.getBytes(commentB.length));
740:                written += 2;
741:
742:                // disk number start
743:                writeOut(ZERO);
744:                written += 2;
745:
746:                // internal file attributes
747:                writeOut(ZipShort.getBytes(ze.getInternalAttributes()));
748:                written += 2;
749:
750:                // external file attributes
751:                writeOut(ZipLong.getBytes(ze.getExternalAttributes()));
752:                written += 4;
753:
754:                // relative offset of LFH
755:                writeOut((byte[]) offsets.get(ze));
756:                written += 4;
757:
758:                // file name
759:                writeOut(name);
760:                written += name.length;
761:
762:                // extra field
763:                writeOut(extra);
764:                written += extra.length;
765:
766:                // file comment
767:                writeOut(commentB);
768:                written += commentB.length;
769:            }
770:
771:            /**
772:             * Writes the &quot;End of central dir record&quot;.
773:             * @throws IOException on error
774:             *
775:             * @since 1.1
776:             */
777:            protected void writeCentralDirectoryEnd() throws IOException {
778:                writeOut(EOCD_SIG);
779:
780:                // disk numbers
781:                writeOut(ZERO);
782:                writeOut(ZERO);
783:
784:                // number of entries
785:                byte[] num = ZipShort.getBytes(entries.size());
786:                writeOut(num);
787:                writeOut(num);
788:
789:                // length and location of CD
790:                writeOut(ZipLong.getBytes(cdLength));
791:                writeOut(ZipLong.getBytes(cdOffset));
792:
793:                // ZIP file comment
794:                byte[] data = getBytes(comment);
795:                writeOut(ZipShort.getBytes(data.length));
796:                writeOut(data);
797:            }
798:
799:            /**
800:             * Smallest date/time ZIP can handle.
801:             *
802:             * @since 1.1
803:             */
804:            private static final byte[] DOS_TIME_MIN = ZipLong
805:                    .getBytes(0x00002100L);
806:
807:            /**
808:             * Convert a Date object to a DOS date/time field.
809:             * @param time the <code>Date</code> to convert
810:             * @return the date as a <code>ZipLong</code>
811:             * @since 1.1
812:             */
813:            protected static ZipLong toDosTime(Date time) {
814:                return new ZipLong(toDosTime(time.getTime()));
815:            }
816:
817:            /**
818:             * Convert a Date object to a DOS date/time field.
819:             *
820:             * <p>Stolen from InfoZip's <code>fileio.c</code></p>
821:             * @param t number of milliseconds since the epoch
822:             * @return the date as a byte array
823:             * @since 1.26
824:             */
825:            protected static byte[] toDosTime(long t) {
826:                Date time = new Date(t);
827:                int year = time.getYear() + 1900;
828:                if (year < 1980) {
829:                    return DOS_TIME_MIN;
830:                }
831:                int month = time.getMonth() + 1;
832:                long value = ((year - 1980) << 25) | (month << 21)
833:                        | (time.getDate() << 16) | (time.getHours() << 11)
834:                        | (time.getMinutes() << 5) | (time.getSeconds() >> 1);
835:                return ZipLong.getBytes(value);
836:            }
837:
838:            /**
839:             * Retrieve the bytes for the given String in the encoding set for
840:             * this Stream.
841:             * @param name the string to get bytes from
842:             * @return the bytes as a byte array
843:             * @throws ZipException on error
844:             *
845:             * @since 1.3
846:             */
847:            protected byte[] getBytes(String name) throws ZipException {
848:                if (encoding == null) {
849:                    return name.getBytes();
850:                } else {
851:                    try {
852:                        return name.getBytes(encoding);
853:                    } catch (UnsupportedEncodingException uee) {
854:                        throw new ZipException(uee.getMessage());
855:                    }
856:                }
857:            }
858:
859:            /**
860:             * Write bytes to output or random access file.
861:             * @param data the byte array to write
862:             * @throws IOException on error
863:             *
864:             * @since 1.14
865:             */
866:            protected final void writeOut(byte[] data) throws IOException {
867:                writeOut(data, 0, data.length);
868:            }
869:
870:            /**
871:             * Write bytes to output or random access file.
872:             * @param data the byte array to write
873:             * @param offset the start position to write from
874:             * @param length the number of bytes to write
875:             * @throws IOException on error
876:             *
877:             * @since 1.14
878:             */
879:            protected final void writeOut(byte[] data, int offset, int length)
880:                    throws IOException {
881:                if (raf != null) {
882:                    raf.write(data, offset, length);
883:                } else {
884:                    out.write(data, offset, length);
885:                }
886:            }
887:
888:            /**
889:             * Assumes a negative integer really is a positive integer that
890:             * has wrapped around and re-creates the original value.
891:             * @param i the value to treat as unsigned int.
892:             * @return the unsigned int as a long.
893:             * @since 1.34
894:             */
895:            protected static long adjustToLong(int i) {
896:                if (i < 0) {
897:                    return 2 * ((long) Integer.MAX_VALUE) + 2 + i;
898:                } else {
899:                    return i;
900:                }
901:            }
902:
903:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.