OSDN Git Service

Add new source files
[armadillo/armadillo1.git] / src / jp / sfjp / armadillo / archive / zip / ZipInputStream.java
1 package jp.sfjp.armadillo.archive.zip;
2
3 import java.io.*;
4 import java.util.zip.*;
5 import jp.sfjp.armadillo.archive.*;
6 import jp.sfjp.armadillo.io.*;
7
8 public final class ZipInputStream extends ArchiveInputStream {
9
10     private static final int BUFFER_SIZE = 16384;
11
12     private ZipHeader header;
13     private ZipEntry ongoingEntry;
14     private Inflater inflater;
15
16     public ZipInputStream(InputStream is) {
17         super(new RewindableInputStream(is, BUFFER_SIZE));
18         this.header = new ZipHeader();
19         this.inflater = new Inflater(true);
20     }
21
22     public ZipEntry getNextEntry() throws IOException {
23         ensureOpen();
24         if (ongoingEntry != null)
25             closeEntry();
26         ZipEntry entry = header.readLOC(in);
27         if (entry == null)
28             return null;
29         return openEntry(entry);
30     }
31
32     ZipEntry openEntry(ZipEntry entry) throws IOException {
33         assert entry != null;
34         if (entry.isDirectory() || entry.method == ZipEntry.STORED)
35             frontStream = in;
36         else if (entry.method == ZipEntry.DEFLATED)
37             frontStream = new InflaterInputStream(in, inflater, 512);
38         else {
39             System.out.printf("method=%d, name=%s%n", entry.method, entry.getName());
40             frontStream = in;
41         }
42         if (entry.hasEXT())
43             if (entry.isDirectory() && !header.readEXT(in, entry))
44                 throw new ZipException("failed to read EXT header on stream mode (0)");
45             else {
46                 byte[] buffer = new byte[BUFFER_SIZE];
47                 final int readSize = in.read(buffer);
48                 final int offset = findSIGEXT(buffer);
49                 if (offset < 0)
50                     throw new ZipException("failed to read EXT header on stream mode (1)");
51                 ((RewindableInputStream)in).rewind(readSize);
52                 InputStream bis = new ByteArrayInputStream(buffer, offset, ZipHeader.LENGTH_EXT);
53                 if (!header.readEXT(bis, entry))
54                     throw new ZipException("failed to read EXT header on stream mode (2)");
55             }
56         remaining = entry.getSize();
57         return ongoingEntry = entry;
58     }
59
60     public void closeEntry() throws IOException {
61         ZipEntry entry = ongoingEntry;
62         ensureOpen();
63         if (!entry.isDirectory()) {
64             // jump to the head of next header if need
65             if (remaining > 0) {
66                 final long compsize = entry.compsize;
67                 final long uncompsize = entry.uncompsize;
68                 if (remaining == uncompsize) {
69                     long skip = compsize;
70                     while (skip > 0)
71                         skip -= in.skip(skip);
72                     remaining -= uncompsize;
73                     assert (skip != 0) : "skipped size should be zero, but was " + skip;
74                 }
75             }
76             final int inflaterRemaining = inflater.getRemaining();
77             if (inflaterRemaining > 0) // overread
78                 ((RewindableInputStream)in).rewind(inflaterRemaining);
79             assert remaining == 0 : "remaining should be zero, but was %d" + remaining;
80             if (entry.hasEXT() && !header.readEXT(in, entry))
81                 throw new ZipException("failed to read EXT header on stream mode (3)");
82         }
83         // reset
84         ongoingEntry = null;
85         inflater.reset();
86         frontStream = in;
87     }
88
89     private static int findSIGEXT(byte[] bytes) {
90         // SIGEXT=0x504B0708
91         for (int i = 0; i < bytes.length - 3; i++)
92             if (bytes[i] == 0x50)
93                 if (bytes[i + 1] == 0x4B)
94                     if (bytes[i + 2] == 0x07)
95                         if (bytes[i + 3] == 0x08)
96                             return i;
97         return -1;
98     }
99
100     @Override
101     public void close() throws IOException {
102         header = null;
103         inflater = null;
104         ongoingEntry = null;
105     }
106
107 }