KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > zip > ZipOutputStream


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.zip;
20
21 import java.io.File JavaDoc;
22 import java.io.FileOutputStream JavaDoc;
23 import java.io.FilterOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.OutputStream JavaDoc;
26 import java.io.RandomAccessFile JavaDoc;
27 import java.io.UnsupportedEncodingException JavaDoc;
28 import java.util.Date JavaDoc;
29 import java.util.Hashtable JavaDoc;
30 import java.util.Vector JavaDoc;
31 import java.util.zip.CRC32 JavaDoc;
32 import java.util.zip.Deflater JavaDoc;
33 import java.util.zip.ZipException JavaDoc;
34
35 /**
36  * Reimplementation of {@link java.util.zip.ZipOutputStream
37  * java.util.zip.ZipOutputStream} that does handle the extended
38  * functionality of this package, especially internal/external file
39  * attributes and extra fields with different layouts for local file
40  * data and central directory entries.
41  *
42  * <p>This class will try to use {@link java.io.RandomAccessFile
43  * RandomAccessFile} when you know that the output is going to go to a
44  * file.</p>
45  *
46  * <p>If RandomAccessFile cannot be used, this implementation will use
47  * a Data Descriptor to store size and CRC information for {@link
48  * #DEFLATED DEFLATED} entries, this means, you don't need to
49  * calculate them yourself. Unfortunately this is not possible for
50  * the {@link #STORED STORED} method, here setting the CRC and
51  * uncompressed size information is required before {@link
52  * #putNextEntry putNextEntry} can be called.</p>
53  *
54  */

55 public class ZipOutputStream extends FilterOutputStream JavaDoc {
56
57     /**
58      * Compression method for deflated entries.
59      *
60      * @since 1.1
61      */

62     public static final int DEFLATED = java.util.zip.ZipEntry.DEFLATED;
63
64     /**
65      * Default compression level for deflated entries.
66      *
67      * @since Ant 1.7
68      */

69     public static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION;
70
71     /**
72      * Compression method for stored entries.
73      *
74      * @since 1.1
75      */

76     public static final int STORED = java.util.zip.ZipEntry.STORED;
77
78     /**
79      * Current entry.
80      *
81      * @since 1.1
82      */

83     private ZipEntry entry;
84
85     /**
86      * The file comment.
87      *
88      * @since 1.1
89      */

90     private String JavaDoc comment = "";
91
92     /**
93      * Compression level for next entry.
94      *
95      * @since 1.1
96      */

97     private int level = DEFAULT_COMPRESSION;
98
99     /**
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 JavaDoc entries = new Vector JavaDoc();
120
121     /**
122      * CRC instance to avoid parsing DEFLATED data twice.
123      *
124      * @since 1.1
125      */

126     private CRC32 JavaDoc crc = new CRC32 JavaDoc();
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 JavaDoc offsets = new Hashtable JavaDoc();
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 JavaDoc 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 JavaDoc def = new Deflater JavaDoc(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 JavaDoc 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 JavaDoc 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 JavaDoc file) throws IOException JavaDoc {
248         super(null);
249
250         try {
251             raf = new RandomAccessFile JavaDoc(file, "rw");
252             raf.setLength(0);
253         } catch (IOException JavaDoc e) {
254             if (raf != null) {
255                 try {
256                     raf.close();
257                 } catch (IOException JavaDoc inner) {
258                     // ignore
259
}
260                 raf = null;
261             }
262             out = new FileOutputStream JavaDoc(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 JavaDoc 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 JavaDoc 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 JavaDoc {
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 JavaDoc {
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 JavaDoc("bad CRC checksum for entry "
353                                        + entry.getName() + ": "
354                                        + Long.toHexString(entry.getCrc())
355                                        + " instead of "
356                                        + Long.toHexString(realCrc));
357             }
358
359             if (entry.getSize() != written - dataStart) {
360                 throw new ZipException JavaDoc("bad size for entry "
361                                        + entry.getName() + ": "
362                                        + entry.getSize()
363                                        + " instead of "
364                                        + (written - dataStart));
365             }
366         } else { /* method is STORED and we used RandomAccessFile */
367             long size = written - dataStart;
368
369             entry.setSize(size);
370             entry.setCompressedSize(size);
371             entry.setCrc(realCrc);
372         }
373
374         // If random access output, write the local file header containing
375
// the correct CRC and compressed/uncompressed sizes
376
if (raf != null) {
377             long save = raf.getFilePointer();
378
379             raf.seek(localDataStart);
380             writeOut(ZipLong.getBytes(entry.getCrc()));
381             writeOut(ZipLong.getBytes(entry.getCompressedSize()));
382             writeOut(ZipLong.getBytes(entry.getSize()));
383             raf.seek(save);
384         }
385
386         writeDataDescriptor(entry);
387         entry = null;
388     }
389
390     /**
391      * Begin writing next entry.
392      * @param ze the entry to write
393      * @since 1.1
394      * @throws IOException on error
395      */

396     public void putNextEntry(ZipEntry ze) throws IOException JavaDoc {
397         closeEntry();
398
399         entry = ze;
400         entries.addElement(entry);
401
402         if (entry.getMethod() == -1) { // not specified
403
entry.setMethod(method);
404         }
405
406         if (entry.getTime() == -1) { // not specified
407
entry.setTime(System.currentTimeMillis());
408         }
409
410         // Size/CRC not required if RandomAccessFile is used
411
if (entry.getMethod() == STORED && raf == null) {
412             if (entry.getSize() == -1) {
413                 throw new ZipException JavaDoc("uncompressed size is required for"
414                                        + " STORED method when not writing to a"
415                                        + " file");
416             }
417             if (entry.getCrc() == -1) {
418                 throw new ZipException JavaDoc("crc checksum is required for STORED"
419                                        + " method when not writing to a file");
420             }
421             entry.setCompressedSize(entry.getSize());
422         }
423
424         if (entry.getMethod() == DEFLATED && hasCompressionLevelChanged) {
425             def.setLevel(level);
426             hasCompressionLevelChanged = false;
427         }
428         writeLocalFileHeader(entry);
429     }
430
431     /**
432      * Set the file comment.
433      * @param comment the comment
434      * @since 1.1
435      */

436     public void setComment(String JavaDoc comment) {
437         this.comment = comment;
438     }
439
440     /**
441      * Sets the compression level for subsequent entries.
442      *
443      * <p>Default is Deflater.DEFAULT_COMPRESSION.</p>
444      * @param level the compression level.
445      * @throws IllegalArgumentException if an invalid compression level is specified.
446      * @since 1.1
447      */

448     public void setLevel(int level) {
449         if (level < Deflater.DEFAULT_COMPRESSION
450             || level > Deflater.BEST_COMPRESSION) {
451             throw new IllegalArgumentException JavaDoc(
452                 "Invalid compression level: " + level);
453         }
454         hasCompressionLevelChanged = (this.level != level);
455         this.level = level;
456     }
457
458     /**
459      * Sets the default compression method for subsequent entries.
460      *
461      * <p>Default is DEFLATED.</p>
462      * @param method an <code>int</code> from java.util.zip.ZipEntry
463      * @since 1.1
464      */

465     public void setMethod(int method) {
466         this.method = method;
467     }
468
469     /**
470      * Writes bytes to ZIP entry.
471      * @param b the byte array to write
472      * @param offset the start position to write from
473      * @param length the number of bytes to write
474      * @throws IOException on error
475      */

476     public void write(byte[] b, int offset, int length) throws IOException JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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.getBytes(0X04034B50L);
547     /**
548      * data descriptor signature
549      *
550      * @since 1.1
551      */

552     protected static final byte[] DD_SIG = ZipLong.getBytes(0X08074B50L);
553     /**
554      * central file header signature
555      *
556      * @since 1.1
557      */

558     protected static final byte[] CFH_SIG = ZipLong.getBytes(0X02014B50L);
559     /**
560      * end of central dir signature
561      *
562      * @since 1.1
563      */

564     protected static final byte[] EOCD_SIG = ZipLong.getBytes(0X06054B50L);
565
566     /**
567      * Writes next block of compressed data to the output stream.
568      * @throws IOException on error
569      *
570      * @since 1.14
571      */

572     protected final void deflate() throws IOException JavaDoc {
573         int len = def.deflate(buf, 0, buf.length);
574         if (len > 0) {
575             writeOut(buf, 0, len);
576         }
577     }
578
579     /**
580      * Writes the local file header entry
581      * @param ze the entry to write
582      * @throws IOException on error
583      *
584      * @since 1.1
585      */

586     protected void writeLocalFileHeader(ZipEntry ze) throws IOException JavaDoc {
587         offsets.put(ze, ZipLong.getBytes(written));
588
589         writeOut(LFH_SIG);
590         written += 4;
591
592         //store method in local variable to prevent multiple method calls
593
final int zipMethod = ze.getMethod();
594
595         // version needed to extract
596
// general purpose bit flag
597
if (zipMethod == DEFLATED && raf == null) {
598             // requires version 2 as we are going to store length info
599
// in the data descriptor
600
writeOut(ZipShort.getBytes(20));
601
602             // bit3 set to signal, we use a data descriptor
603
writeOut(ZipShort.getBytes(8));
604         } else {
605             writeOut(ZipShort.getBytes(10));
606             writeOut(ZERO);
607         }
608         written += 4;
609
610         // compression method
611
writeOut(ZipShort.getBytes(zipMethod));
612         written += 2;
613
614         // last mod. time and date
615
writeOut(toDosTime(ze.getTime()));
616         written += 4;
617
618         // CRC
619
// compressed length
620
// uncompressed length
621
localDataStart = written;
622         if (zipMethod == DEFLATED || raf != null) {
623             writeOut(LZERO);
624             writeOut(LZERO);
625             writeOut(LZERO);
626         } else {
627             writeOut(ZipLong.getBytes(ze.getCrc()));
628             writeOut(ZipLong.getBytes(ze.getSize()));
629             writeOut(ZipLong.getBytes(ze.getSize()));
630         }
631         written += 12;
632
633         // file name length
634
byte[] name = getBytes(ze.getName());
635         writeOut(ZipShort.getBytes(name.length));
636         written += 2;
637
638         // extra field length
639
byte[] extra = ze.getLocalFileDataExtra();
640         writeOut(ZipShort.getBytes(extra.length));
641         written += 2;
642
643         // file name
644
writeOut(name);
645         written += name.length;
646
647         // extra field
648
writeOut(extra);
649         written += extra.length;
650
651         dataStart = written;
652     }
653
654     /**
655      * Writes the data descriptor entry.
656      * @param ze the entry to write
657      * @throws IOException on error
658      *
659      * @since 1.1
660      */

661     protected void writeDataDescriptor(ZipEntry ze) throws IOException JavaDoc {
662         if (ze.getMethod() != DEFLATED || raf != null) {
663             return;
664         }
665         writeOut(DD_SIG);
666         writeOut(ZipLong.getBytes(entry.getCrc()));
667         writeOut(ZipLong.getBytes(entry.getCompressedSize()));
668         writeOut(ZipLong.getBytes(entry.getSize()));
669         written += 16;
670     }
671
672     /**
673      * Writes the central file header entry.
674      * @param ze the entry to write
675      * @throws IOException on error
676      *
677      * @since 1.1
678      */

679     protected void writeCentralFileHeader(ZipEntry ze) throws IOException JavaDoc {
680         writeOut(CFH_SIG);
681         written += 4;
682
683         // version made by
684
writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 20));
685         written += 2;
686
687         // version needed to extract
688
// general purpose bit flag
689
if (ze.getMethod() == DEFLATED && raf == null) {
690             // requires version 2 as we are going to store length info
691
// in the data descriptor
692
writeOut(ZipShort.getBytes(20));
693
694             // bit3 set to signal, we use a data descriptor
695
writeOut(ZipShort.getBytes(8));
696         } else {
697             writeOut(ZipShort.getBytes(10));
698             writeOut(ZERO);
699         }
700         written += 4;
701
702         // compression method
703
writeOut(ZipShort.getBytes(ze.getMethod()));
704         written += 2;
705
706         // last mod. time and date
707
writeOut(toDosTime(ze.getTime()));
708         written += 4;
709
710         // CRC
711
// compressed length
712
// uncompressed length
713
writeOut(ZipLong.getBytes(ze.getCrc()));
714         writeOut(ZipLong.getBytes(ze.getCompressedSize()));
715         writeOut(ZipLong.getBytes(ze.getSize()));
716         written += 12;
717
718         // file name length
719
byte[] name = getBytes(ze.getName());
720         writeOut(ZipShort.getBytes(name.length));
721         written += 2;
722
723         // extra field length
724
byte[] extra = ze.getCentralDirectoryExtra();
725         writeOut(ZipShort.getBytes(extra.length));
726         written += 2;
727
728         // file comment length
729
String JavaDoc comm = ze.getComment();
730         if (comm == null) {
731             comm = "";
732         }
733         byte[] commentB = getBytes(comm);
734         writeOut(ZipShort.getBytes(commentB.length));
735         written += 2;
736
737         // disk number start
738
writeOut(ZERO);
739         written += 2;
740
741         // internal file attributes
742
writeOut(ZipShort.getBytes(ze.getInternalAttributes()));
743         written += 2;
744
745         // external file attributes
746
writeOut(ZipLong.getBytes(ze.getExternalAttributes()));
747         written += 4;
748
749         // relative offset of LFH
750
writeOut((byte[]) offsets.get(ze));
751         written += 4;
752
753         // file name
754
writeOut(name);
755         written += name.length;
756
757         // extra field
758
writeOut(extra);
759         written += extra.length;
760
761         // file comment
762
writeOut(commentB);
763         written += commentB.length;
764     }
765
766     /**
767      * Writes the &quot;End of central dir record&quot;.
768      * @throws IOException on error
769      *
770      * @since 1.1
771      */

772     protected void writeCentralDirectoryEnd() throws IOException JavaDoc {
773         writeOut(EOCD_SIG);
774
775         // disk numbers
776
writeOut(ZERO);
777         writeOut(ZERO);
778
779         // number of entries
780
byte[] num = ZipShort.getBytes(entries.size());
781         writeOut(num);
782         writeOut(num);
783
784         // length and location of CD
785
writeOut(ZipLong.getBytes(cdLength));
786         writeOut(ZipLong.getBytes(cdOffset));
787
788         // ZIP file comment
789
byte[] data = getBytes(comment);
790         writeOut(ZipShort.getBytes(data.length));
791         writeOut(data);
792     }
793
794     /**
795      * Smallest date/time ZIP can handle.
796      *
797      * @since 1.1
798      */

799     private static final byte[] DOS_TIME_MIN = ZipLong.getBytes(0x00002100L);
800
801     /**
802      * Convert a Date object to a DOS date/time field.
803      * @param time the <code>Date</code> to convert
804      * @return the date as a <code>ZipLong</code>
805      * @since 1.1
806      */

807     protected static ZipLong toDosTime(Date JavaDoc time) {
808         return new ZipLong(toDosTime(time.getTime()));
809     }
810
811     /**
812      * Convert a Date object to a DOS date/time field.
813      *
814      * <p>Stolen from InfoZip's <code>fileio.c</code></p>
815      * @param t number of milliseconds since the epoch
816      * @return the date as a byte array
817      * @since 1.26
818      */

819     protected static byte[] toDosTime(long t) {
820         Date JavaDoc time = new Date JavaDoc(t);
821         int year = time.getYear() + 1900;
822         if (year < 1980) {
823             return DOS_TIME_MIN;
824         }
825         int month = time.getMonth() + 1;
826         long value = ((year - 1980) << 25)
827             | (month << 21)
828             | (time.getDate() << 16)
829             | (time.getHours() << 11)
830             | (time.getMinutes() << 5)
831             | (time.getSeconds() >> 1);
832         return ZipLong.getBytes(value);
833     }
834
835     /**
836      * Retrieve the bytes for the given String in the encoding set for
837      * this Stream.
838      * @param name the string to get bytes from
839      * @return the bytes as a byte array
840      * @throws ZipException on error
841      *
842      * @since 1.3
843      */

844     protected byte[] getBytes(String JavaDoc name) throws ZipException JavaDoc {
845         if (encoding == null) {
846             return name.getBytes();
847         } else {
848             try {
849                 return name.getBytes(encoding);
850             } catch (UnsupportedEncodingException JavaDoc uee) {
851                 throw new ZipException JavaDoc(uee.getMessage());
852             }
853         }
854     }
855
856     /**
857      * Write bytes to output or random access file.
858      * @param data the byte array to write
859      * @throws IOException on error
860      *
861      * @since 1.14
862      */

863     protected final void writeOut(byte[] data) throws IOException JavaDoc {
864         writeOut(data, 0, data.length);
865     }
866
867     /**
868      * Write bytes to output or random access file.
869      * @param data the byte array to write
870      * @param offset the start position to write from
871      * @param length the number of bytes to write
872      * @throws IOException on error
873      *
874      * @since 1.14
875      */

876     protected final void writeOut(byte[] data, int offset, int length)
877         throws IOException JavaDoc {
878         if (raf != null) {
879             raf.write(data, offset, length);
880         } else {
881             out.write(data, offset, length);
882         }
883     }
884
885     /**
886      * Assumes a negative integer really is a positive integer that
887      * has wrapped around and re-creates the original value.
888      * @param i the value to treat as unsigned int.
889      * @return the unsigned int as a long.
890      * @since 1.34
891      */

892     protected static long adjustToLong(int i) {
893         if (i < 0) {
894             return 2 * ((long) Integer.MAX_VALUE) + 2 + i;
895         } else {
896             return i;
897         }
898     }
899
900 }
901
Popular Tags