Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

788
LINES

< > BotCompany Repo | #1034350 // ZipOutputStreamWithRawCopying [abandoned] - uncompilable, uses too many JDK internals. will use zip4j instead

JavaX fragment (include) [tags: use-pretranspiled]

Transpiled version (821L) is out of date.

1  
// extended copy of java.util.zip.ZipOutputStream
2  
// that can store compressed files directly
3  
4  
import static java.util.zip.ZipConstants64.*;
5  
import static java.util.zip.ZipUtils.*;
6  
import sun.nio.cs.UTF_8;
7  
import sun.security.action.GetPropertyAction;
8  
9  
sclass ZipOutputStreamWithRawCopying extends DeflaterOutputStream is ZipConstants {
10  
11  
    /**
12  
     * Whether to use ZIP64 for zip files with more than 64k entries.
13  
     * Until ZIP64 support in zip implementations is ubiquitous, this
14  
     * system property allows the creation of zip files which can be
15  
     * read by legacy zip implementations which tolerate "incorrect"
16  
     * total entry count fields, such as the ones in jdk6, and even
17  
     * some in jdk7.
18  
     */
19  
    private static final boolean inhibitZip64 =
20  
        Boolean.parseBoolean(
21  
            GetPropertyAction.privilegedGetProperty("jdk.util.zip.inhibitZip64"));
22  
23  
    private static class XEntry {
24  
        final ZipEntry entry;
25  
        final long offset;
26  
        public XEntry(ZipEntry entry, long offset) {
27  
            this.entry = entry;
28  
            this.offset = offset;
29  
        }
30  
    }
31  
32  
    private XEntry current;
33  
    private Vector<XEntry> xentries = new Vector<>();
34  
    private HashSet<String> names = new HashSet<>();
35  
    private CRC32 crc = new CRC32();
36  
    private long written = 0;
37  
    private long locoff = 0;
38  
    private byte[] comment;
39  
    private int method = DEFLATED;
40  
    private boolean finished;
41  
42  
    private boolean closed = false;
43  
44  
    private final ZipCoder zc;
45  
46  
    private static int version(ZipEntry e) throws ZipException {
47  
        return switch (e.method) {
48  
        case DEFLATED -> 20;
49  
        case STORED   -> 10;
50  
        default       -> throw new ZipException("unsupported compression method");
51  
        };
52  
    }
53  
54  
    /**
55  
     * Checks to make sure that this stream has not been closed.
56  
     */
57  
    private void ensureOpen() throws IOException {
58  
        if (closed) {
59  
            throw new IOException("Stream closed");
60  
        }
61  
    }
62  
63  
    /**
64  
     * Compression method for uncompressed (STORED) entries.
65  
     */
66  
    public static final int STORED = ZipEntry.STORED;
67  
68  
    /**
69  
     * Compression method for compressed (DEFLATED) entries.
70  
     */
71  
    public static final int DEFLATED = ZipEntry.DEFLATED;
72  
73  
    /**
74  
     * Creates a new ZIP output stream.
75  
     *
76  
     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used
77  
     * to encode the entry names and comments.
78  
     *
79  
     * @param out the actual output stream
80  
     */
81  
    public *(OutputStream out) {
82  
        this(out, UTF_8.INSTANCE);
83  
    }
84  
85  
    /**
86  
     * Creates a new ZIP output stream.
87  
     *
88  
     * @param out the actual output stream
89  
     *
90  
     * @param charset the {@linkplain java.nio.charset.Charset charset}
91  
     *                to be used to encode the entry names and comments
92  
     *
93  
     * @since 1.7
94  
     */
95  
    public *(OutputStream out, Charset charset) {
96  
        super(out, out != null ? new Deflater(Deflater.DEFAULT_COMPRESSION, true) : null);
97  
        if (charset == null)
98  
            throw new NullPointerException("charset is null");
99  
        this.zc = ZipCoder.get(charset);
100  
        usesDefaultDeflater = true;
101  
    }
102  
103  
    /**
104  
     * Sets the ZIP file comment.
105  
     * @param     comment the comment string
106  
     * @throws    IllegalArgumentException if the length of the specified
107  
     *            ZIP file comment is greater than 0xFFFF bytes
108  
     */
109  
    public void setComment(String comment) {
110  
        if (comment != null) {
111  
            this.comment = zc.getBytes(comment);
112  
            if (this.comment.length > 0xffff)
113  
                throw new IllegalArgumentException("ZIP file comment too long.");
114  
        }
115  
    }
116  
117  
    /**
118  
     * Sets the default compression method for subsequent entries. This
119  
     * default will be used whenever the compression method is not specified
120  
     * for an individual ZIP file entry, and is initially set to DEFLATED.
121  
     * @param     method the default compression method
122  
     * @throws    IllegalArgumentException if the specified compression method
123  
     *            is invalid
124  
     */
125  
    public void setMethod(int method) {
126  
        if (method != DEFLATED && method != STORED) {
127  
            throw new IllegalArgumentException("invalid compression method");
128  
        }
129  
        this.method = method;
130  
    }
131  
132  
    /**
133  
     * Sets the compression level for subsequent entries which are DEFLATED.
134  
     * The default setting is DEFAULT_COMPRESSION.
135  
     * @param     level the compression level (0-9)
136  
     * @throws    IllegalArgumentException if the compression level is invalid
137  
     */
138  
    public void setLevel(int level) {
139  
        def.setLevel(level);
140  
    }
141  
142  
    /**
143  
     * Begins writing a new ZIP file entry and positions the stream to the
144  
     * start of the entry data. Closes the current entry if still active.
145  
     * <p>
146  
     * The default compression method will be used if no compression method
147  
     * was specified for the entry. When writing a compressed (DEFLATED)
148  
     * entry, and the compressed size has not been explicitly set with the
149  
     * {@link ZipEntry#setCompressedSize(long)} method, then the compressed
150  
     * size will be set to the actual compressed size after deflation.
151  
     * <p>
152  
     * The current time will be used if the entry has no set modification time.
153  
     *
154  
     * @param     e the ZIP entry to be written
155  
     * @throws    ZipException if a ZIP format error has occurred
156  
     * @throws    IOException if an I/O error has occurred
157  
     */
158  
    public void putNextEntry(ZipEntry e) throws IOException {
159  
        ensureOpen();
160  
        if (current != null) {
161  
            closeEntry();       // close previous entry
162  
        }
163  
        if (e.xdostime == -1) {
164  
            // by default, do NOT use extended timestamps in extra
165  
            // data, for now.
166  
            e.setTime(System.currentTimeMillis());
167  
        }
168  
        if (e.method == -1) {
169  
            e.method = method;  // use default method
170  
        }
171  
        // store size, compressed size, and crc-32 in LOC header
172  
        e.flag = 0;
173  
        switch (e.method) {
174  
        case DEFLATED:
175  
            // If not set, store size, compressed size, and crc-32 in data
176  
            // descriptor immediately following the compressed entry data.
177  
            // Ignore the compressed size of a ZipEntry if it was implcitely set
178  
            // while reading that ZipEntry from a  ZipFile or ZipInputStream because
179  
            // we can't know the compression level of the source zip file/stream.
180  
            if (e.size  == -1 || e.csize == -1 || e.crc   == -1 || !e.csizeSet) {
181  
                e.flag = 8;
182  
            }
183  
            break;
184  
        case STORED:
185  
            // compressed size, uncompressed size, and crc-32 must all be
186  
            // set for entries using STORED compression method
187  
            if (e.size == -1) {
188  
                e.size = e.csize;
189  
            } else if (e.csize == -1) {
190  
                e.csize = e.size;
191  
            } else if (e.size != e.csize) {
192  
                throw new ZipException(
193  
                    "STORED entry where compressed != uncompressed size");
194  
            }
195  
            if (e.size == -1 || e.crc == -1) {
196  
                throw new ZipException(
197  
                    "STORED entry missing size, compressed size, or crc-32");
198  
            }
199  
            break;
200  
        default:
201  
            throw new ZipException("unsupported compression method");
202  
        }
203  
        if (! names.add(e.name)) {
204  
            throw new ZipException("duplicate entry: " + e.name);
205  
        }
206  
        if (zc.isUTF8())
207  
            e.flag |= USE_UTF8;
208  
        current = new XEntry(e, written);
209  
        xentries.add(current);
210  
        writeLOC(current);
211  
    }
212  
213  
    /**
214  
     * Closes the current ZIP entry and positions the stream for writing
215  
     * the next entry.
216  
     * @throws    ZipException if a ZIP format error has occurred
217  
     * @throws    IOException if an I/O error has occurred
218  
     */
219  
    public void closeEntry() throws IOException {
220  
        ensureOpen();
221  
        if (current != null) {
222  
            ZipEntry e = current.entry;
223  
            switch (e.method) {
224  
            case DEFLATED -> {
225  
                def.finish();
226  
                while (!def.finished()) {
227  
                    deflate();
228  
                }
229  
                if ((e.flag & 8) == 0) {
230  
                    // verify size, compressed size, and crc-32 settings
231  
                    if (e.size != def.getBytesRead()) {
232  
                        throw new ZipException(
233  
                            "invalid entry size (expected " + e.size +
234  
                            " but got " + def.getBytesRead() + " bytes)");
235  
                    }
236  
                    if (e.csize != def.getBytesWritten()) {
237  
                        throw new ZipException(
238  
                            "invalid entry compressed size (expected " +
239  
                            e.csize + " but got " + def.getBytesWritten() + " bytes)");
240  
                    }
241  
                    if (e.crc != crc.getValue()) {
242  
                        throw new ZipException(
243  
                            "invalid entry CRC-32 (expected 0x" +
244  
                            Long.toHexString(e.crc) + " but got 0x" +
245  
                            Long.toHexString(crc.getValue()) + ")");
246  
                    }
247  
                } else {
248  
                    e.size = def.getBytesRead();
249  
                    e.csize = def.getBytesWritten();
250  
                    e.crc = crc.getValue();
251  
                    writeEXT(e);
252  
                }
253  
                def.reset();
254  
                written += e.csize;
255  
            }
256  
            case STORED -> {
257  
                // we already know that both e.size and e.csize are the same
258  
                if (e.size != written - locoff) {
259  
                    throw new ZipException(
260  
                        "invalid entry size (expected " + e.size +
261  
                        " but got " + (written - locoff) + " bytes)");
262  
                }
263  
                if (e.crc != crc.getValue()) {
264  
                    throw new ZipException(
265  
                        "invalid entry crc-32 (expected 0x" +
266  
                        Long.toHexString(e.crc) + " but got 0x" +
267  
                        Long.toHexString(crc.getValue()) + ")");
268  
                }
269  
            }
270  
            default -> throw new ZipException("invalid compression method");
271  
            }
272  
            crc.reset();
273  
            current = null;
274  
        }
275  
    }
276  
277  
    /**
278  
     * Writes an array of bytes to the current ZIP entry data. This method
279  
     * will block until all the bytes are written.
280  
     * @param     b the data to be written
281  
     * @param     off the start offset in the data
282  
     * @param     len the number of bytes that are written
283  
     * @throws    ZipException if a ZIP file error has occurred
284  
     * @throws    IOException if an I/O error has occurred
285  
     */
286  
    public synchronized void write(byte[] b, int off, int len)
287  
        throws IOException
288  
    {
289  
        ensureOpen();
290  
        if (off < 0 || len < 0 || off > b.length - len) {
291  
            throw new IndexOutOfBoundsException();
292  
        } else if (len == 0) {
293  
            return;
294  
        }
295  
296  
        if (current == null) {
297  
            throw new ZipException("no current ZIP entry");
298  
        }
299  
        ZipEntry entry = current.entry;
300  
        switch (entry.method) {
301  
            case DEFLATED -> super.write(b, off, len);
302  
            case STORED -> {
303  
                written += len;
304  
                if (written - locoff > entry.size) {
305  
                    throw new ZipException(
306  
                        "attempt to write past end of STORED entry");
307  
                }
308  
                out.write(b, off, len);
309  
            }
310  
            default -> throw new ZipException("invalid compression method");
311  
        }
312  
        crc.update(b, off, len);
313  
    }
314  
315  
    /**
316  
     * Finishes writing the contents of the ZIP output stream without closing
317  
     * the underlying stream. Use this method when applying multiple filters
318  
     * in succession to the same output stream.
319  
     * @throws    ZipException if a ZIP file error has occurred
320  
     * @throws    IOException if an I/O exception has occurred
321  
     */
322  
    public void finish() throws IOException {
323  
        ensureOpen();
324  
        if (finished) {
325  
            return;
326  
        }
327  
        if (current != null) {
328  
            closeEntry();
329  
        }
330  
        // write central directory
331  
        long off = written;
332  
        for (XEntry xentry : xentries)
333  
            writeCEN(xentry);
334  
        writeEND(off, written - off);
335  
        finished = true;
336  
    }
337  
338  
    /**
339  
     * Closes the ZIP output stream as well as the stream being filtered.
340  
     * @throws    ZipException if a ZIP file error has occurred
341  
     * @throws    IOException if an I/O error has occurred
342  
     */
343  
    public void close() throws IOException {
344  
        if (!closed) {
345  
            super.close();
346  
            closed = true;
347  
        }
348  
    }
349  
350  
    /*
351  
     * Writes local file (LOC) header for specified entry.
352  
     */
353  
    private void writeLOC(XEntry xentry) throws IOException {
354  
        ZipEntry e = xentry.entry;
355  
        int flag = e.flag;
356  
        boolean hasZip64 = false;
357  
        int elen = getExtraLen(e.extra);
358  
359  
        writeInt(LOCSIG);               // LOC header signature
360  
        if ((flag & 8) == 8) {
361  
            writeShort(version(e));     // version needed to extract
362  
            writeShort(flag);           // general purpose bit flag
363  
            writeShort(e.method);       // compression method
364  
            writeInt(e.xdostime);       // last modification time
365  
            // store size, uncompressed size, and crc-32 in data descriptor
366  
            // immediately following compressed entry data
367  
            writeInt(0);
368  
            writeInt(0);
369  
            writeInt(0);
370  
        } else {
371  
            if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
372  
                hasZip64 = true;
373  
                writeShort(45);         // ver 4.5 for zip64
374  
            } else {
375  
                writeShort(version(e)); // version needed to extract
376  
            }
377  
            writeShort(flag);           // general purpose bit flag
378  
            writeShort(e.method);       // compression method
379  
            writeInt(e.xdostime);       // last modification time
380  
            writeInt(e.crc);            // crc-32
381  
            if (hasZip64) {
382  
                writeInt(ZIP64_MAGICVAL);
383  
                writeInt(ZIP64_MAGICVAL);
384  
                elen += 20;        //headid(2) + size(2) + size(8) + csize(8)
385  
            } else {
386  
                writeInt(e.csize);  // compressed size
387  
                writeInt(e.size);   // uncompressed size
388  
            }
389  
        }
390  
        byte[] nameBytes = zc.getBytes(e.name);
391  
        writeShort(nameBytes.length);
392  
393  
        int elenEXTT = 0;         // info-zip extended timestamp
394  
        int flagEXTT = 0;
395  
        long umtime = -1;
396  
        long uatime = -1;
397  
        long uctime = -1;
398  
        if (e.mtime != null) {
399  
            elenEXTT += 4;
400  
            flagEXTT |= EXTT_FLAG_LMT;
401  
            umtime = fileTimeToUnixTime(e.mtime);
402  
        }
403  
        if (e.atime != null) {
404  
            elenEXTT += 4;
405  
            flagEXTT |= EXTT_FLAG_LAT;
406  
            uatime = fileTimeToUnixTime(e.atime);
407  
        }
408  
        if (e.ctime != null) {
409  
            elenEXTT += 4;
410  
            flagEXTT |= EXTT_FLAT_CT;
411  
            uctime = fileTimeToUnixTime(e.ctime);
412  
        }
413  
        if (flagEXTT != 0) {
414  
            // to use ntfs time if any m/a/ctime is beyond unixtime upper bound
415  
            if (umtime > UPPER_UNIXTIME_BOUND ||
416  
                uatime > UPPER_UNIXTIME_BOUND ||
417  
                uctime > UPPER_UNIXTIME_BOUND) {
418  
                elen += 36;                // NTFS time, total 36 bytes
419  
            } else {
420  
                elen += (elenEXTT + 5);    // headid(2) + size(2) + flag(1) + data
421  
            }
422  
        }
423  
        writeShort(elen);
424  
        writeBytes(nameBytes, 0, nameBytes.length);
425  
        if (hasZip64) {
426  
            writeShort(ZIP64_EXTID);
427  
            writeShort(16);
428  
            writeLong(e.size);
429  
            writeLong(e.csize);
430  
        }
431  
        if (flagEXTT != 0) {
432  
            if (umtime > UPPER_UNIXTIME_BOUND ||
433  
                uatime > UPPER_UNIXTIME_BOUND ||
434  
                uctime > UPPER_UNIXTIME_BOUND) {
435  
                writeShort(EXTID_NTFS);    // id
436  
                writeShort(32);            // data size
437  
                writeInt(0);               // reserved
438  
                writeShort(0x0001);        // NTFS attr tag
439  
                writeShort(24);
440  
                writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
441  
                                          : fileTimeToWinTime(e.mtime));
442  
                writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
443  
                                          : fileTimeToWinTime(e.atime));
444  
                writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
445  
                                          : fileTimeToWinTime(e.ctime));
446  
            } else {
447  
                writeShort(EXTID_EXTT);
448  
                writeShort(elenEXTT + 1);  // flag + data
449  
                writeByte(flagEXTT);
450  
                if (e.mtime != null)
451  
                    writeInt(umtime);
452  
                if (e.atime != null)
453  
                    writeInt(uatime);
454  
                if (e.ctime != null)
455  
                    writeInt(uctime);
456  
            }
457  
        }
458  
        writeExtra(e.extra);
459  
        locoff = written;
460  
    }
461  
462  
    /*
463  
     * Writes extra data descriptor (EXT) for specified entry.
464  
     */
465  
    private void writeEXT(ZipEntry e) throws IOException {
466  
        writeInt(EXTSIG);           // EXT header signature
467  
        writeInt(e.crc);            // crc-32
468  
        if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
469  
            writeLong(e.csize);
470  
            writeLong(e.size);
471  
        } else {
472  
            writeInt(e.csize);          // compressed size
473  
            writeInt(e.size);           // uncompressed size
474  
        }
475  
    }
476  
477  
    /**
478  
     * Adds information about compatibility of file attribute information
479  
     * to a version value.
480  
     */
481  
    private int versionMadeBy(ZipEntry e, int version) {
482  
        return (e.extraAttributes < 0) ? version :
483  
                VERSION_MADE_BY_BASE_UNIX | (version & 0xff);
484  
    }
485  
486  
    /*
487  
     * Write central directory (CEN) header for specified entry.
488  
     * REMIND: add support for file attributes
489  
     */
490  
    private void writeCEN(XEntry xentry) throws IOException {
491  
        ZipEntry e  = xentry.entry;
492  
        int flag = e.flag;
493  
        int version = version(e);
494  
        long csize = e.csize;
495  
        long size = e.size;
496  
        long offset = xentry.offset;
497  
        int elenZIP64 = 0;
498  
        boolean hasZip64 = false;
499  
500  
        if (e.csize >= ZIP64_MAGICVAL) {
501  
            csize = ZIP64_MAGICVAL;
502  
            elenZIP64 += 8;              // csize(8)
503  
            hasZip64 = true;
504  
        }
505  
        if (e.size >= ZIP64_MAGICVAL) {
506  
            size = ZIP64_MAGICVAL;    // size(8)
507  
            elenZIP64 += 8;
508  
            hasZip64 = true;
509  
        }
510  
        if (xentry.offset >= ZIP64_MAGICVAL) {
511  
            offset = ZIP64_MAGICVAL;
512  
            elenZIP64 += 8;              // offset(8)
513  
            hasZip64 = true;
514  
        }
515  
        writeInt(CENSIG);           // CEN header signature
516  
        if (hasZip64) {
517  
            writeShort(versionMadeBy(e,45));         // ver 4.5 for zip64
518  
            writeShort(45);
519  
        } else {
520  
            writeShort(versionMadeBy(e, version));    // version made by
521  
            writeShort(version);    // version needed to extract
522  
        }
523  
        writeShort(flag);           // general purpose bit flag
524  
        writeShort(e.method);       // compression method
525  
        writeInt(e.xdostime);       // last modification time
526  
        writeInt(e.crc);            // crc-32
527  
        writeInt(csize);            // compressed size
528  
        writeInt(size);             // uncompressed size
529  
        byte[] nameBytes = zc.getBytes(e.name);
530  
        writeShort(nameBytes.length);
531  
532  
        int elen = getExtraLen(e.extra);
533  
        if (hasZip64) {
534  
            elen += (elenZIP64 + 4);// + headid(2) + datasize(2)
535  
        }
536  
        // cen info-zip extended timestamp only outputs mtime
537  
        // but set the flag for a/ctime, if present in loc
538  
        int flagEXTT = 0;
539  
        long umtime = -1;
540  
        long uatime = -1;
541  
        long uctime = -1;
542  
        if (e.mtime != null) {
543  
            flagEXTT |= EXTT_FLAG_LMT;
544  
            umtime = fileTimeToUnixTime(e.mtime);
545  
        }
546  
        if (e.atime != null) {
547  
            flagEXTT |= EXTT_FLAG_LAT;
548  
            uatime = fileTimeToUnixTime(e.atime);
549  
        }
550  
        if (e.ctime != null) {
551  
            flagEXTT |= EXTT_FLAT_CT;
552  
            uctime = fileTimeToUnixTime(e.ctime);
553  
        }
554  
        if (flagEXTT != 0) {
555  
            // to use ntfs time if any m/a/ctime is beyond unixtime upper bound
556  
            if (umtime > UPPER_UNIXTIME_BOUND ||
557  
                uatime > UPPER_UNIXTIME_BOUND ||
558  
                uctime > UPPER_UNIXTIME_BOUND) {
559  
                elen += 36;         // NTFS time total 36 bytes
560  
            } else {
561  
                elen += 5;          // headid(2) + sz(2) + flag(1)
562  
                if (e.mtime != null)
563  
                    elen += 4;      // + mtime (4)
564  
            }
565  
        }
566  
        writeShort(elen);
567  
        byte[] commentBytes;
568  
        if (e.comment != null) {
569  
            commentBytes = zc.getBytes(e.comment);
570  
            writeShort(Math.min(commentBytes.length, 0xffff));
571  
        } else {
572  
            commentBytes = null;
573  
            writeShort(0);
574  
        }
575  
        writeShort(0);              // starting disk number
576  
        writeShort(0);              // internal file attributes (unused)
577  
        // extra file attributes, used for storing posix permissions etc.
578  
        writeInt(e.extraAttributes > 0 ? e.extraAttributes << 16 : 0);
579  
        writeInt(offset);           // relative offset of local header
580  
        writeBytes(nameBytes, 0, nameBytes.length);
581  
582  
        // take care of EXTID_ZIP64 and EXTID_EXTT
583  
        if (hasZip64) {
584  
            writeShort(ZIP64_EXTID);// Zip64 extra
585  
            writeShort(elenZIP64);
586  
            if (size == ZIP64_MAGICVAL)
587  
                writeLong(e.size);
588  
            if (csize == ZIP64_MAGICVAL)
589  
                writeLong(e.csize);
590  
            if (offset == ZIP64_MAGICVAL)
591  
                writeLong(xentry.offset);
592  
        }
593  
        if (flagEXTT != 0) {
594  
            if (umtime > UPPER_UNIXTIME_BOUND ||
595  
                uatime > UPPER_UNIXTIME_BOUND ||
596  
                uctime > UPPER_UNIXTIME_BOUND) {
597  
                writeShort(EXTID_NTFS);    // id
598  
                writeShort(32);            // data size
599  
                writeInt(0);               // reserved
600  
                writeShort(0x0001);        // NTFS attr tag
601  
                writeShort(24);
602  
                writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
603  
                                          : fileTimeToWinTime(e.mtime));
604  
                writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
605  
                                          : fileTimeToWinTime(e.atime));
606  
                writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
607  
                                          : fileTimeToWinTime(e.ctime));
608  
            } else {
609  
                writeShort(EXTID_EXTT);
610  
                if (e.mtime != null) {
611  
                    writeShort(5);      // flag + mtime
612  
                    writeByte(flagEXTT);
613  
                    writeInt(umtime);
614  
                } else {
615  
                    writeShort(1);      // flag only
616  
                    writeByte(flagEXTT);
617  
                }
618  
            }
619  
        }
620  
        writeExtra(e.extra);
621  
        if (commentBytes != null) {
622  
            writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
623  
        }
624  
    }
625  
626  
    /*
627  
     * Writes end of central directory (END) header.
628  
     */
629  
    private void writeEND(long off, long len) throws IOException {
630  
        boolean hasZip64 = false;
631  
        long xlen = len;
632  
        long xoff = off;
633  
        if (xlen >= ZIP64_MAGICVAL) {
634  
            xlen = ZIP64_MAGICVAL;
635  
            hasZip64 = true;
636  
        }
637  
        if (xoff >= ZIP64_MAGICVAL) {
638  
            xoff = ZIP64_MAGICVAL;
639  
            hasZip64 = true;
640  
        }
641  
        int count = xentries.size();
642  
        if (count >= ZIP64_MAGICCOUNT) {
643  
            hasZip64 |= !inhibitZip64;
644  
            if (hasZip64) {
645  
                count = ZIP64_MAGICCOUNT;
646  
            }
647  
        }
648  
        if (hasZip64) {
649  
            long off64 = written;
650  
            //zip64 end of central directory record
651  
            writeInt(ZIP64_ENDSIG);        // zip64 END record signature
652  
            writeLong(ZIP64_ENDHDR - 12);  // size of zip64 end
653  
            writeShort(45);                // version made by
654  
            writeShort(45);                // version needed to extract
655  
            writeInt(0);                   // number of this disk
656  
            writeInt(0);                   // central directory start disk
657  
            writeLong(xentries.size());    // number of directory entires on disk
658  
            writeLong(xentries.size());    // number of directory entires
659  
            writeLong(len);                // length of central directory
660  
            writeLong(off);                // offset of central directory
661  
662  
            //zip64 end of central directory locator
663  
            writeInt(ZIP64_LOCSIG);        // zip64 END locator signature
664  
            writeInt(0);                   // zip64 END start disk
665  
            writeLong(off64);              // offset of zip64 END
666  
            writeInt(1);                   // total number of disks (?)
667  
        }
668  
        writeInt(ENDSIG);                 // END record signature
669  
        writeShort(0);                    // number of this disk
670  
        writeShort(0);                    // central directory start disk
671  
        writeShort(count);                // number of directory entries on disk
672  
        writeShort(count);                // total number of directory entries
673  
        writeInt(xlen);                   // length of central directory
674  
        writeInt(xoff);                   // offset of central directory
675  
        if (comment != null) {            // zip file comment
676  
            writeShort(comment.length);
677  
            writeBytes(comment, 0, comment.length);
678  
        } else {
679  
            writeShort(0);
680  
        }
681  
    }
682  
683  
    /*
684  
     * Returns the length of extra data without EXTT and ZIP64.
685  
     */
686  
    private int getExtraLen(byte[] extra) {
687  
        if (extra == null)
688  
            return 0;
689  
        int skipped = 0;
690  
        int len = extra.length;
691  
        int off = 0;
692  
        while (off + 4 <= len) {
693  
            int tag = get16(extra, off);
694  
            int sz = get16(extra, off + 2);
695  
            if (sz < 0 || (off + 4 + sz) > len) {
696  
                break;
697  
            }
698  
            if (tag == EXTID_EXTT || tag == EXTID_ZIP64) {
699  
                skipped += (sz + 4);
700  
            }
701  
            off += (sz + 4);
702  
        }
703  
        return len - skipped;
704  
    }
705  
706  
    /*
707  
     * Writes extra data without EXTT and ZIP64.
708  
     *
709  
     * Extra timestamp and ZIP64 data is handled/output separately
710  
     * in writeLOC and writeCEN.
711  
     */
712  
    private void writeExtra(byte[] extra) throws IOException {
713  
        if (extra != null) {
714  
            int len = extra.length;
715  
            int off = 0;
716  
            while (off + 4 <= len) {
717  
                int tag = get16(extra, off);
718  
                int sz = get16(extra, off + 2);
719  
                if (sz < 0 || (off + 4 + sz) > len) {
720  
                    writeBytes(extra, off, len - off);
721  
                    return;
722  
                }
723  
                if (tag != EXTID_EXTT && tag != EXTID_ZIP64) {
724  
                    writeBytes(extra, off, sz + 4);
725  
                }
726  
                off += (sz + 4);
727  
            }
728  
            if (off < len) {
729  
                writeBytes(extra, off, len - off);
730  
            }
731  
        }
732  
    }
733  
734  
    /*
735  
     * Writes a 8-bit byte to the output stream.
736  
     */
737  
    private void writeByte(int v) throws IOException {
738  
        OutputStream out = this.out;
739  
        out.write(v & 0xff);
740  
        written += 1;
741  
    }
742  
743  
    /*
744  
     * Writes a 16-bit short to the output stream in little-endian byte order.
745  
     */
746  
    private void writeShort(int v) throws IOException {
747  
        OutputStream out = this.out;
748  
        out.write((v >>> 0) & 0xff);
749  
        out.write((v >>> 8) & 0xff);
750  
        written += 2;
751  
    }
752  
753  
    /*
754  
     * Writes a 32-bit int to the output stream in little-endian byte order.
755  
     */
756  
    private void writeInt(long v) throws IOException {
757  
        OutputStream out = this.out;
758  
        out.write((int)((v >>>  0) & 0xff));
759  
        out.write((int)((v >>>  8) & 0xff));
760  
        out.write((int)((v >>> 16) & 0xff));
761  
        out.write((int)((v >>> 24) & 0xff));
762  
        written += 4;
763  
    }
764  
765  
    /*
766  
     * Writes a 64-bit int to the output stream in little-endian byte order.
767  
     */
768  
    private void writeLong(long v) throws IOException {
769  
        OutputStream out = this.out;
770  
        out.write((int)((v >>>  0) & 0xff));
771  
        out.write((int)((v >>>  8) & 0xff));
772  
        out.write((int)((v >>> 16) & 0xff));
773  
        out.write((int)((v >>> 24) & 0xff));
774  
        out.write((int)((v >>> 32) & 0xff));
775  
        out.write((int)((v >>> 40) & 0xff));
776  
        out.write((int)((v >>> 48) & 0xff));
777  
        out.write((int)((v >>> 56) & 0xff));
778  
        written += 8;
779  
    }
780  
781  
    /*
782  
     * Writes an array of bytes to the output stream.
783  
     */
784  
    private void writeBytes(byte[] b, int off, int len) throws IOException {
785  
        super.out.write(b, off, len);
786  
        written += len;
787  
    }
788  
}

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1034350
Snippet name: ZipOutputStreamWithRawCopying [abandoned] - uncompilable, uses too many JDK internals. will use zip4j instead
Eternal ID of this version: #1034350/4
Text MD5: 34fec5df077d85d06d9f106ed04aa6b8
Author: stefan
Category: javax / stefan's os
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-02-03 04:41:47
Source code size: 30162 bytes / 788 lines
Pitched / IR pitched: No / No
Views / Downloads: 71 / 117
Version history: 3 change(s)
Referenced in: [show references]