OSDN Git Service

Add new source files
[armadillo/armadillo1.git] / src / jp / sfjp / armadillo / archive / zip / DumpZipHeader.java
1 package jp.sfjp.armadillo.archive.zip;
2
3 import java.io.*;
4 import java.nio.*;
5 import java.nio.channels.*;
6 import java.util.*;
7 import java.util.zip.*;
8 import jp.sfjp.armadillo.archive.*;
9 import jp.sfjp.armadillo.io.*;
10
11 /**
12  * Dump ZIP archive header.
13  */
14 public final class DumpZipHeader extends DumpArchiveHeader {
15
16     private static final String fmt1 = "  * %s = %s%n";
17     private static final String fmt2 = "  %1$-16s = [0x%2$08X] ( %2$d )%n";
18     private static final int siglen = 4;
19     private static final int siglen_m1 = siglen - 1;
20
21     static final int SIGN_LOC = 0x04034B50;
22     static final int SIGN_CEN = 0x02014B50;
23     static final int SIGN_END = 0x06054B50;
24     static final int SIGN_EXT = 0x08074B50;
25     static final int LENGTH_LOC = 30;
26     static final int LENGTH_CEN = 46;
27     static final int LENGTH_END = 22;
28     static final int LENGTH_EXT = 16;
29
30     private final ByteBuffer buffer;
31
32     public DumpZipHeader() {
33         this.buffer = ByteBuffer.allocate(LENGTH_CEN).order(ByteOrder.LITTLE_ENDIAN);
34     }
35
36     @Override
37     public void dump(InputStream is, PrintWriter out) throws IOException {
38         final int bufferSize = 65536;
39         byte[] bytes = new byte[bufferSize];
40         int p = 0;
41         RewindableInputStream pis = new RewindableInputStream(is, bufferSize);
42         while (true) {
43             Arrays.fill(bytes, (byte)0);
44             final int readSize = pis.read(bytes);
45             if (readSize <= 0)
46                 break;
47             final int offset = findPK(bytes);
48             if (offset < 0) {
49                 if (readSize < siglen)
50                     break;
51                 pis.rewind(siglen_m1);
52                 p += readSize - siglen_m1;
53                 continue;
54             }
55             if (offset == 0)
56                 pis.rewind(readSize);
57             else if (offset < bufferSize - siglen)
58                 pis.rewind(readSize - offset);
59             p += offset;
60             printOffset(out, p);
61             ByteBuffer buffer = ByteBuffer.wrap(bytes, offset, siglen)
62                                           .order(ByteOrder.LITTLE_ENDIAN);
63             final int len;
64             final int signature = buffer.getInt();
65             switch (signature) {
66                 case SIGN_LOC:
67                     len = readLOC(pis, out);
68                     break;
69                 case SIGN_CEN:
70                     len = readCEN(pis, out);
71                     break;
72                 case SIGN_END:
73                     len = readEND(pis, out);
74                     break;
75                 case SIGN_EXT:
76                     len = readEXT(pis, out);
77                     break;
78                 default:
79                     warn(out, "[%08X] is not a signature", signature);
80                     len = 0;
81             }
82             assert len >= 0;
83             if (len > 0)
84                 p += len;
85             else {
86                 pis.read();
87                 ++p;
88             }
89         }
90         printEnd(out, "ZIP", p);
91     }
92
93     static int findPK(byte[] bytes) {
94         // PK=0x504B
95         final int n = bytes.length - siglen_m1;
96         for (int i = 0; i < n; i++)
97             if (bytes[i] == 0x50)
98                 if (bytes[i + 1] == 0x4B)
99                     return i;
100         return -1;
101     }
102
103     int readLOC(InputStream is, PrintWriter out) throws IOException {
104         int readSize = 0;
105         // Local file header (LOC)
106         final int signature; // local file header signature
107         final short version; // version needed to extract
108         final short flags; // general purpose bit flag
109         final short method; // compression method
110         final short mtime; // last mod file time
111         final short mdate; // last mod file date
112         final int crc; // crc-32
113         final int compsize; // compressed size
114         final int uncompsize; // uncompressed size
115         final short namelen; // file name length
116         final short extlen; // extra field length
117         buffer.clear();
118         buffer.limit(LENGTH_LOC);
119         Channels.newChannel(is).read(buffer);
120         readSize += buffer.position();
121         buffer.rewind();
122         signature = buffer.getInt();
123         version = buffer.getShort();
124         flags = buffer.getShort();
125         method = buffer.getShort();
126         mtime = buffer.getShort();
127         mdate = buffer.getShort();
128         crc = buffer.getInt();
129         compsize = buffer.getInt();
130         uncompsize = buffer.getInt();
131         namelen = buffer.getShort();
132         extlen = buffer.getShort();
133         final String name;
134         assert namelen >= 0;
135         if (namelen == 0)
136             name = "";
137         else { // if (namelen > 0)
138             byte[] nameBuffer = new byte[namelen];
139             final int read = is.read(nameBuffer);
140             name = new String(nameBuffer);
141             if (read != namelen)
142                 warn(out, "namelen=%d, read=%d, name=%s", namelen, read, name);
143             readSize += read;
144         }
145         if (extlen > 0) {
146             final long read = is.skip(extlen);
147             if (read != extlen)
148                 throw new ZipException("invalid LOC header (extra length)");
149             readSize += read;
150         }
151         printHeaderName(out, "LOC header");
152         out.printf(fmt1, "name", name);
153         out.printf(fmt1, "mtime as date", toDate(mdate, mtime));
154         out.printf(fmt2, "signature", signature);
155         out.printf(fmt2, "version", version);
156         out.printf(fmt2, "flags", flags);
157         out.printf(fmt2, "method", method);
158         out.printf(fmt2, "mtime", mtime);
159         out.printf(fmt2, "mdate", mdate);
160         out.printf(fmt2, "crc", crc);
161         out.printf(fmt2, "compsize", compsize);
162         out.printf(fmt2, "uncompsize", uncompsize);
163         out.printf(fmt2, "namelen", namelen);
164         out.printf(fmt2, "extlen", extlen);
165         return readSize;
166     }
167
168     int readCEN(InputStream is, PrintWriter out) throws IOException {
169         int readSize = 0;
170         // Central file header (CEN)
171         final int signature; // central file header signature
172         final short madever; // version made by
173         final short needver; // version needed to extract
174         final short flags; // general purpose bit flag
175         final short method; // compression method
176         final short mtime; // last mod file time
177         final short mdate; // last mod file date
178         final int crc; // crc-32
179         final int compsize; // compressed size
180         final int uncompsize; // uncompressed size
181         final short namelen; // file name length
182         final short extlen; // extra field length
183         final short fcmlen; // file comment length
184         final short dnum; // disk number start
185         final short inattr; // internal file attributes
186         final int exattr; // external file attributes
187         final int reloff; // relative offset of local header
188         buffer.clear();
189         buffer.limit(LENGTH_CEN);
190         Channels.newChannel(is).read(buffer);
191         readSize += buffer.position();
192         if (buffer.position() == 0)
193             return readSize;
194         buffer.rewind();
195         signature = buffer.getInt();
196         madever = buffer.getShort();
197         needver = buffer.getShort();
198         flags = buffer.getShort();
199         method = buffer.getShort();
200         mtime = buffer.getShort();
201         mdate = buffer.getShort();
202         crc = buffer.getInt();
203         compsize = buffer.getInt();
204         uncompsize = buffer.getInt();
205         namelen = buffer.getShort();
206         extlen = buffer.getShort();
207         fcmlen = buffer.getShort();
208         dnum = buffer.getShort();
209         inattr = buffer.getShort();
210         exattr = buffer.getInt();
211         reloff = buffer.getInt();
212         final String name;
213         if (namelen > 0) {
214             final int reallen = namelen;
215             byte[] nameBuffer = new byte[reallen];
216             final int read = is.read(nameBuffer);
217             name = new String(nameBuffer);
218             if (read != namelen)
219                 warn(out, "namelen=%d, read=%d, name=%s", namelen, read, name);
220         }
221         else
222             name = "";
223         if (extlen > 0) {
224             final long read = is.skip(extlen);
225             if (read != extlen)
226                 throw new ZipException("invalid CEN header (extra length)");
227             readSize += read;
228         }
229         if (fcmlen > 0)
230             System.out.println();
231         printHeaderName(out, "CEN header");
232         out.printf(fmt1, "name", name);
233         out.printf(fmt1, "mtime as date", toDate(mdate, mtime));
234         out.printf(fmt2, "signature", signature);
235         out.printf(fmt2, "madever", madever);
236         out.printf(fmt2, "needver", needver);
237         out.printf(fmt2, "flags", flags);
238         out.printf(fmt2, "method", method);
239         out.printf(fmt2, "mtime", mtime);
240         out.printf(fmt2, "mdate", mdate);
241         out.printf(fmt2, "crc", crc);
242         out.printf(fmt2, "compsize", compsize);
243         out.printf(fmt2, "uncompsize", uncompsize);
244         out.printf(fmt2, "namelen", namelen);
245         out.printf(fmt2, "extlen", extlen);
246         out.printf(fmt2, "fcmlen", fcmlen);
247         out.printf(fmt2, "dnum", dnum);
248         out.printf(fmt2, "infattr", inattr);
249         out.printf(fmt2, "exfattr", exattr);
250         out.printf(fmt2, "reloff", reloff);
251         return readSize;
252     }
253
254     int readEND(InputStream is, PrintWriter out) throws IOException {
255         int readSize = 0;
256         // End of central dir header (END)
257         final int signature; // end of central dir signature
258         final short ndisk; // number of this disk
259         final short ndiskCEN; // number of the disk with the start of the central directory
260         final short countDiskCENs; // total number of entries in the central directory on this disk
261         final short countCENs; // total number of entries in the central directory
262         final int sizeCENs; // size of the central directory
263         final int offsetCENs; // offset of start of central directory with respect to the starting disk number
264         final short commentlen; // .ZIP file comment length
265         final byte[] comment; // .ZIP file comment
266         buffer.clear();
267         buffer.limit(LENGTH_END);
268         Channels.newChannel(is).read(buffer);
269         readSize += buffer.position();
270         buffer.rewind();
271         signature = buffer.getInt();
272         ndisk = buffer.getShort();
273         ndiskCEN = buffer.getShort();
274         countDiskCENs = buffer.getShort();
275         countCENs = buffer.getShort();
276         sizeCENs = buffer.getInt();
277         offsetCENs = buffer.getInt();
278         commentlen = buffer.getShort();
279         final String commentString;
280         if (commentlen > 0) {
281             comment = new byte[commentlen];
282             final int read = is.read(comment);
283             if (read != commentlen)
284                 throw new ZipException("invalid END header (comment length)");
285             readSize += read;
286             commentString = new String(comment);
287         }
288         else
289             commentString = "";
290         printHeaderName(out, "END header");
291         out.printf(fmt2, "signature", signature);
292         out.printf(fmt2, "ndisk", ndisk);
293         out.printf(fmt2, "ndiskCEN", ndiskCEN);
294         out.printf(fmt2, "countDiskCENs", countDiskCENs);
295         out.printf(fmt2, "countCENs", countCENs);
296         out.printf(fmt2, "sizeCENs", sizeCENs);
297         out.printf(fmt2, "offsetCENs", offsetCENs);
298         out.printf(fmt2, "commentlen", commentlen);
299         out.printf(fmt1, "comment", commentString);
300         return readSize;
301     }
302
303     int readEXT(InputStream is, PrintWriter out) throws IOException {
304         int readSize = 0;
305         // Extend header (EXT)
306         final int signature; // extend header signature
307         final int crc; // crc-32
308         final int compsize; // compressed size
309         final int uncompsize; // uncompressed size
310         buffer.clear();
311         buffer.limit(LENGTH_EXT);
312         Channels.newChannel(is).read(buffer);
313         readSize += buffer.position();
314         buffer.rewind();
315         signature = buffer.getInt();
316         crc = buffer.getInt();
317         compsize = buffer.getInt();
318         uncompsize = buffer.getInt();
319         printHeaderName(out, "EXT header");
320         out.printf(fmt2, "signature", signature);
321         out.printf(fmt2, "crc", crc);
322         out.printf(fmt2, "compsize", compsize);
323         out.printf(fmt2, "uncompsize", uncompsize);
324         return readSize;
325     }
326
327     static Date toDate(short mdate, short mtime) {
328         ZipEntry entry = new ZipEntry();
329         entry.mdate = mdate;
330         entry.mtime = mtime;
331         return new Date(entry.getLastModified());
332     }
333
334 }