1/*
2 * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nio.zipfs;
27
28import java.nio.file.Paths;
29import java.util.Collections;
30import java.util.Map;
31import static jdk.nio.zipfs.ZipConstants.*;
32import static jdk.nio.zipfs.ZipUtils.*;
33
34/**
35 * Print all loc and cen headers of the ZIP file
36 *
37 * @author  Xueming Shen
38 */
39
40public class ZipInfo {
41
42    public static void main(String[] args) throws Throwable {
43        if (args.length < 1) {
44            print("Usage: java ZipInfo zfname");
45        } else {
46            Map<String, ?> env = Collections.emptyMap();
47            ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider()
48                                    .newFileSystem(Paths.get(args[0]), env));
49            byte[] cen = zfs.cen;
50            if (cen == null) {
51                print("zip file is empty%n");
52                return;
53            }
54            int    pos = 0;
55            byte[] buf = new byte[1024];
56            int    no = 1;
57            while (pos + CENHDR < cen.length) {
58                print("----------------#%d--------------------%n", no++);
59                printCEN(cen, pos);
60
61                // use size CENHDR as the extra bytes to read, just in case the
62                // loc.extra is bigger than the cen.extra, try to avoid to read
63                // twice
64                long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR;
65                if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
66                    ZipFileSystem.zerror("read loc header failed");
67                if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) {
68                    // have to read the second time;
69                    len = LOCHDR + LOCNAM(buf) + LOCEXT(buf);
70                    if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
71                        ZipFileSystem.zerror("read loc header failed");
72                }
73                printLOC(buf);
74                pos += CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos);
75            }
76            zfs.close();
77        }
78    }
79
80    static void print(String fmt, Object... objs) {
81        System.out.printf(fmt, objs);
82    }
83
84    static void printLOC(byte[] loc) {
85        print("%n");
86        print("[Local File Header]%n");
87        print("    Signature   :   %#010x%n", LOCSIG(loc));
88        if (LOCSIG(loc) != LOCSIG) {
89           print("    Wrong signature!");
90           return;
91        }
92        print("    Version     :       %#6x    [%d.%d]%n",
93                  LOCVER(loc), LOCVER(loc) / 10, LOCVER(loc) % 10);
94        print("    Flag        :       %#6x%n", LOCFLG(loc));
95        print("    Method      :       %#6x%n", LOCHOW(loc));
96        print("    LastMTime   :   %#10x    [%tc]%n",
97              LOCTIM(loc), dosToJavaTime(LOCTIM(loc)));
98        print("    CRC         :   %#10x%n", LOCCRC(loc));
99        print("    CSize       :   %#10x%n", LOCSIZ(loc));
100        print("    Size        :   %#10x%n", LOCLEN(loc));
101        print("    NameLength  :       %#6x    [%s]%n",
102                  LOCNAM(loc), new String(loc, LOCHDR, LOCNAM(loc)));
103        print("    ExtraLength :       %#6x%n", LOCEXT(loc));
104        if (LOCEXT(loc) != 0)
105            printExtra(loc, LOCHDR + LOCNAM(loc), LOCEXT(loc));
106    }
107
108    static void printCEN(byte[] cen, int off) {
109        print("[Central Directory Header]%n");
110        print("    Signature   :   %#010x%n", CENSIG(cen, off));
111        if (CENSIG(cen, off) != CENSIG) {
112           print("    Wrong signature!");
113           return;
114        }
115        print("    VerMadeby   :       %#6x    [%d, %d.%d]%n",
116              CENVEM(cen, off), (CENVEM(cen, off) >> 8),
117              (CENVEM(cen, off) & 0xff) / 10,
118              (CENVEM(cen, off) & 0xff) % 10);
119        print("    VerExtract  :       %#6x    [%d.%d]%n",
120              CENVER(cen, off), CENVER(cen, off) / 10, CENVER(cen, off) % 10);
121        print("    Flag        :       %#6x%n", CENFLG(cen, off));
122        print("    Method      :       %#6x%n", CENHOW(cen, off));
123        print("    LastMTime   :   %#10x    [%tc]%n",
124              CENTIM(cen, off), dosToJavaTime(CENTIM(cen, off)));
125        print("    CRC         :   %#10x%n", CENCRC(cen, off));
126        print("    CSize       :   %#10x%n", CENSIZ(cen, off));
127        print("    Size        :   %#10x%n", CENLEN(cen, off));
128        print("    NameLen     :       %#6x    [%s]%n",
129              CENNAM(cen, off), new String(cen, off + CENHDR, CENNAM(cen, off)));
130        print("    ExtraLen    :       %#6x%n", CENEXT(cen, off));
131        if (CENEXT(cen, off) != 0)
132            printExtra(cen, off + CENHDR + CENNAM(cen, off), CENEXT(cen, off));
133        print("    CommentLen  :       %#6x%n", CENCOM(cen, off));
134        print("    DiskStart   :       %#6x%n", CENDSK(cen, off));
135        print("    Attrs       :       %#6x%n", CENATT(cen, off));
136        print("    AttrsEx     :   %#10x%n", CENATX(cen, off));
137        print("    LocOff      :   %#10x%n", CENOFF(cen, off));
138
139    }
140
141    static long locoff(byte[] cen, int pos) {
142        long locoff = CENOFF(cen, pos);
143        if (locoff == ZIP64_MINVAL) {    //ZIP64
144            int off = pos + CENHDR + CENNAM(cen, pos);
145            int end = off + CENEXT(cen, pos);
146            while (off + 4 < end) {
147                int tag = SH(cen, off);
148                int sz = SH(cen, off + 2);
149                if (tag != EXTID_ZIP64) {
150                    off += 4 + sz;
151                    continue;
152                }
153                off += 4;
154                if (CENLEN(cen, pos) == ZIP64_MINVAL)
155                    off += 8;
156                if (CENSIZ(cen, pos) == ZIP64_MINVAL)
157                    off += 8;
158                return LL(cen, off);
159            }
160            // should never be here
161        }
162        return locoff;
163    }
164
165    static void printExtra(byte[] extra, int off, int len) {
166        int end = off + len;
167        while (off + 4 <= end) {
168            int tag = SH(extra, off);
169            int sz = SH(extra, off + 2);
170            print("        [tag=0x%04x, sz=%d, data= ", tag, sz);
171            if (off + sz > end) {
172                print("    Error: Invalid extra data, beyond extra length");
173                break;
174            }
175            off += 4;
176            for (int i = 0; i < sz; i++)
177                print("%02x ", extra[off + i]);
178            print("]%n");
179            switch (tag) {
180            case EXTID_ZIP64 :
181                print("         ->ZIP64: ");
182                int pos = off;
183                while (pos + 8 <= off + sz) {
184                    print(" *0x%x ", LL(extra, pos));
185                    pos += 8;
186                }
187                print("%n");
188                break;
189            case EXTID_NTFS:
190                print("         ->PKWare NTFS%n");
191                // 4 bytes reserved
192                if (SH(extra, off + 4) !=  0x0001 || SH(extra, off + 6) !=  24)
193                    print("    Error: Invalid NTFS sub-tag or subsz");
194                print("            mtime:%tc%n",
195                      winToJavaTime(LL(extra, off + 8)));
196                print("            atime:%tc%n",
197                      winToJavaTime(LL(extra, off + 16)));
198                print("            ctime:%tc%n",
199                      winToJavaTime(LL(extra, off + 24)));
200                break;
201            case EXTID_EXTT:
202                print("         ->Info-ZIP Extended Timestamp: flag=%x%n",extra[off]);
203                pos = off + 1 ;
204                while (pos + 4 <= off + sz) {
205                    print("            *%tc%n",
206                          unixToJavaTime(LG(extra, pos)));
207                    pos += 4;
208                }
209                break;
210            default:
211                print("         ->[tag=%x, size=%d]%n", tag, sz);
212            }
213            off += sz;
214        }
215    }
216}
217