1 /*
   2  * Copyright (c) 2009, 2018, 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 
  26 package jdk.nio.zipfs;
  27 
  28 import java.nio.file.Paths;
  29 import java.util.Collections;
  30 import java.util.Map;
  31 
  32 import static jdk.nio.zipfs.ZipConstants.*;
  33 import static jdk.nio.zipfs.ZipUtils.dosToJavaTime;
  34 import static jdk.nio.zipfs.ZipUtils.unixToJavaTime;
  35 import static jdk.nio.zipfs.ZipUtils.winToJavaTime;
  36 
  37 /**
  38  * Print all loc and cen headers of the ZIP file
  39  *
  40  * @author Xueming Shen
  41  */
  42 public class ZipInfo {
  43 
  44     public static void main(String[] args) throws Throwable {
  45         if (args.length < 1) {
  46             print("Usage: java ZipInfo zfname");
  47         } else {
  48             Map<String, ?> env = Collections.emptyMap();
  49             ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider()
  50                                     .newFileSystem(Paths.get(args[0]), env));
  51             byte[] cen = zfs.cen;
  52             if (cen == null) {
  53                 print("zip file is empty%n");
  54                 return;
  55             }
  56             int    pos = 0;
  57             byte[] buf = new byte[1024];
  58             int    no = 1;
  59             while (pos + CENHDR < cen.length) {
  60                 print("----------------#%d--------------------%n", no++);
  61                 printCEN(cen, pos);
  62 
  63                 // use size CENHDR as the extra bytes to read, just in case the
  64                 // loc.extra is bigger than the cen.extra, try to avoid to read
  65                 // twice
  66                 long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR;
  67                 if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
  68                     ZipFileSystem.zerror("read loc header failed");
  69                 if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) {
  70                     // have to read the second time;
  71                     len = LOCHDR + LOCNAM(buf) + LOCEXT(buf);
  72                     if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
  73                         ZipFileSystem.zerror("read loc header failed");
  74                 }
  75                 printLOC(buf);
  76                 pos += CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos);
  77             }
  78             zfs.close();
  79         }
  80     }
  81 
  82     static void print(String fmt, Object... objs) {
  83         System.out.printf(fmt, objs);
  84     }
  85 
  86     static void printLOC(byte[] loc) {
  87         print("%n");
  88         print("[Local File Header]%n");
  89         print("    Signature   :   %#010x%n", LOCSIG(loc));
  90         if (LOCSIG(loc) != LOCSIG) {
  91            print("    Wrong signature!");
  92            return;
  93         }
  94         print("    Version     :       %#6x    [%d.%d]%n",
  95                   LOCVER(loc), LOCVER(loc) / 10, LOCVER(loc) % 10);
  96         print("    Flag        :       %#6x%n", LOCFLG(loc));
  97         print("    Method      :       %#6x%n", LOCHOW(loc));
  98         print("    LastMTime   :   %#10x    [%tc]%n",
  99               LOCTIM(loc), dosToJavaTime(LOCTIM(loc)));
 100         print("    CRC         :   %#10x%n", LOCCRC(loc));
 101         print("    CSize       :   %#10x%n", LOCSIZ(loc));
 102         print("    Size        :   %#10x%n", LOCLEN(loc));
 103         print("    NameLength  :       %#6x    [%s]%n",
 104                   LOCNAM(loc), new String(loc, LOCHDR, LOCNAM(loc)));
 105         print("    ExtraLength :       %#6x%n", LOCEXT(loc));
 106         if (LOCEXT(loc) != 0)
 107             printExtra(loc, LOCHDR + LOCNAM(loc), LOCEXT(loc));
 108     }
 109 
 110     static void printCEN(byte[] cen, int off) {
 111         print("[Central Directory Header]%n");
 112         print("    Signature   :   %#010x%n", CENSIG(cen, off));
 113         if (CENSIG(cen, off) != CENSIG) {
 114            print("    Wrong signature!");
 115            return;
 116         }
 117         print("    VerMadeby   :       %#6x    [%d, %d.%d]%n",
 118               CENVEM(cen, off), (CENVEM(cen, off) >> 8),
 119               (CENVEM(cen, off) & 0xff) / 10,
 120               (CENVEM(cen, off) & 0xff) % 10);
 121         print("    VerExtract  :       %#6x    [%d.%d]%n",
 122               CENVER(cen, off), CENVER(cen, off) / 10, CENVER(cen, off) % 10);
 123         print("    Flag        :       %#6x%n", CENFLG(cen, off));
 124         print("    Method      :       %#6x%n", CENHOW(cen, off));
 125         print("    LastMTime   :   %#10x    [%tc]%n",
 126               CENTIM(cen, off), dosToJavaTime(CENTIM(cen, off)));
 127         print("    CRC         :   %#10x%n", CENCRC(cen, off));
 128         print("    CSize       :   %#10x%n", CENSIZ(cen, off));
 129         print("    Size        :   %#10x%n", CENLEN(cen, off));
 130         print("    NameLen     :       %#6x    [%s]%n",
 131               CENNAM(cen, off), new String(cen, off + CENHDR, CENNAM(cen, off)));
 132         print("    ExtraLen    :       %#6x%n", CENEXT(cen, off));
 133         if (CENEXT(cen, off) != 0)
 134             printExtra(cen, off + CENHDR + CENNAM(cen, off), CENEXT(cen, off));
 135         print("    CommentLen  :       %#6x%n", CENCOM(cen, off));
 136         print("    DiskStart   :       %#6x%n", CENDSK(cen, off));
 137         print("    Attrs       :       %#6x%n", CENATT(cen, off));
 138         print("    AttrsEx     :   %#10x%n", CENATX(cen, off));
 139         print("    LocOff      :   %#10x%n", CENOFF(cen, off));
 140 
 141     }
 142 
 143     static long locoff(byte[] cen, int pos) {
 144         long locoff = CENOFF(cen, pos);
 145         if (locoff == ZIP64_MINVAL) {    //ZIP64
 146             int off = pos + CENHDR + CENNAM(cen, pos);
 147             int end = off + CENEXT(cen, pos);
 148             while (off + 4 < end) {
 149                 int tag = SH(cen, off);
 150                 int sz = SH(cen, off + 2);
 151                 if (tag != EXTID_ZIP64) {
 152                     off += 4 + sz;
 153                     continue;
 154                 }
 155                 off += 4;
 156                 if (CENLEN(cen, pos) == ZIP64_MINVAL)
 157                     off += 8;
 158                 if (CENSIZ(cen, pos) == ZIP64_MINVAL)
 159                     off += 8;
 160                 return LL(cen, off);
 161             }
 162             // should never be here
 163         }
 164         return locoff;
 165     }
 166 
 167     static void printExtra(byte[] extra, int off, int len) {
 168         int end = off + len;
 169         while (off + 4 <= end) {
 170             int tag = SH(extra, off);
 171             int sz = SH(extra, off + 2);
 172             print("        [tag=0x%04x, sz=%d, data= ", tag, sz);
 173             if (off + sz > end) {
 174                 print("    Error: Invalid extra data, beyond extra length");
 175                 break;
 176             }
 177             off += 4;
 178             for (int i = 0; i < sz; i++)
 179                 print("%02x ", extra[off + i]);
 180             print("]%n");
 181             switch (tag) {
 182             case EXTID_ZIP64 :
 183                 print("         ->ZIP64: ");
 184                 int pos = off;
 185                 while (pos + 8 <= off + sz) {
 186                     print(" *0x%x ", LL(extra, pos));
 187                     pos += 8;
 188                 }
 189                 print("%n");
 190                 break;
 191             case EXTID_NTFS:
 192                 print("         ->PKWare NTFS%n");
 193                 // 4 bytes reserved
 194                 if (SH(extra, off + 4) !=  0x0001 || SH(extra, off + 6) !=  24)
 195                     print("    Error: Invalid NTFS sub-tag or subsz");
 196                 print("            mtime:%tc%n",
 197                       winToJavaTime(LL(extra, off + 8)));
 198                 print("            atime:%tc%n",
 199                       winToJavaTime(LL(extra, off + 16)));
 200                 print("            ctime:%tc%n",
 201                       winToJavaTime(LL(extra, off + 24)));
 202                 break;
 203             case EXTID_EXTT:
 204                 print("         ->Info-ZIP Extended Timestamp: flag=%x%n",extra[off]);
 205                 pos = off + 1 ;
 206                 while (pos + 4 <= off + sz) {
 207                     print("            *%tc%n",
 208                           unixToJavaTime(LG(extra, pos)));
 209                     pos += 4;
 210                 }
 211                 break;
 212             default:
 213                 print("         ->[tag=%x, size=%d]%n", tag, sz);
 214             }
 215             off += sz;
 216         }
 217     }
 218 }