1 /*
   2  * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30  */
  31 
  32 /*
  33  * This source code is provided to illustrate the usage of a given feature
  34  * or technique and has been deliberately simplified. Additional steps
  35  * required for a production-quality application, such as security checks,
  36  * input validation and proper error handling, might not be present in
  37  * this sample code.
  38  */
  39 
  40 
  41 package com.sun.nio.zipfs;
  42 
  43 import java.nio.file.Paths;
  44 import java.util.Collections;
  45 import java.util.Map;
  46 import static com.sun.nio.zipfs.ZipConstants.*;
  47 import static com.sun.nio.zipfs.ZipUtils.*;
  48 
  49 /**
  50  * Print all loc and cen headers of the ZIP file
  51  *
  52  * @author  Xueming Shen
  53  */
  54 
  55 public class ZipInfo {
  56 
  57     public static void main(String[] args) throws Throwable {
  58         if (args.length < 1) {
  59             print("Usage: java ZipInfo zfname");
  60         } else {
  61             Map<String, ?> env = Collections.emptyMap();
  62             ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider()
  63                                     .newFileSystem(Paths.get(args[0]), env));
  64             byte[] cen = zfs.cen;
  65             if (cen == null) {
  66                 print("zip file is empty%n");
  67                 return;
  68             }
  69             int    pos = 0;
  70             byte[] buf = new byte[1024];
  71             int    no = 1;
  72             while (pos + CENHDR < cen.length) {
  73                 print("----------------#%d--------------------%n", no++);
  74                 printCEN(cen, pos);
  75 
  76                 // use size CENHDR as the extra bytes to read, just in case the
  77                 // loc.extra is bigger than the cen.extra, try to avoid to read
  78                 // twice
  79                 long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR;
  80                 if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
  81                     ZipFileSystem.zerror("read loc header failed");
  82                 if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) {
  83                     // have to read the second time;
  84                     len = LOCHDR + LOCNAM(buf) + LOCEXT(buf);
  85                     if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
  86                         ZipFileSystem.zerror("read loc header failed");
  87                 }
  88                 printLOC(buf);
  89                 pos += CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos);
  90             }
  91             zfs.close();
  92         }
  93     }
  94 
  95     static void print(String fmt, Object... objs) {
  96         System.out.printf(fmt, objs);
  97     }
  98 
  99     static void printLOC(byte[] loc) {
 100         print("%n");
 101         print("[Local File Header]%n");
 102         print("    Signature   :   %#010x%n", LOCSIG(loc));
 103         if (LOCSIG(loc) != LOCSIG) {
 104            print("    Wrong signature!");
 105            return;
 106         }
 107         print("    Version     :       %#6x    [%d.%d]%n",
 108                   LOCVER(loc), LOCVER(loc) / 10, LOCVER(loc) % 10);
 109         print("    Flag        :       %#6x%n", LOCFLG(loc));
 110         print("    Method      :       %#6x%n", LOCHOW(loc));
 111         print("    LastMTime   :   %#10x    [%tc]%n",
 112               LOCTIM(loc), dosToJavaTime(LOCTIM(loc)));
 113         print("    CRC         :   %#10x%n", LOCCRC(loc));
 114         print("    CSize       :   %#10x%n", LOCSIZ(loc));
 115         print("    Size        :   %#10x%n", LOCLEN(loc));
 116         print("    NameLength  :       %#6x    [%s]%n",
 117                   LOCNAM(loc), new String(loc, LOCHDR, LOCNAM(loc)));
 118         print("    ExtraLength :       %#6x%n", LOCEXT(loc));
 119         if (LOCEXT(loc) != 0)
 120             printExtra(loc, LOCHDR + LOCNAM(loc), LOCEXT(loc));
 121     }
 122 
 123     static void printCEN(byte[] cen, int off) {
 124         print("[Central Directory Header]%n");
 125         print("    Signature   :   %#010x%n", CENSIG(cen, off));
 126         if (CENSIG(cen, off) != CENSIG) {
 127            print("    Wrong signature!");
 128            return;
 129         }
 130         print("    VerMadeby   :       %#6x    [%d, %d.%d]%n",
 131               CENVEM(cen, off), (CENVEM(cen, off) >> 8),
 132               (CENVEM(cen, off) & 0xff) / 10,
 133               (CENVEM(cen, off) & 0xff) % 10);
 134         print("    VerExtract  :       %#6x    [%d.%d]%n",
 135               CENVER(cen, off), CENVER(cen, off) / 10, CENVER(cen, off) % 10);
 136         print("    Flag        :       %#6x%n", CENFLG(cen, off));
 137         print("    Method      :       %#6x%n", CENHOW(cen, off));
 138         print("    LastMTime   :   %#10x    [%tc]%n",
 139               CENTIM(cen, off), dosToJavaTime(CENTIM(cen, off)));
 140         print("    CRC         :   %#10x%n", CENCRC(cen, off));
 141         print("    CSize       :   %#10x%n", CENSIZ(cen, off));
 142         print("    Size        :   %#10x%n", CENLEN(cen, off));
 143         print("    NameLen     :       %#6x    [%s]%n",
 144               CENNAM(cen, off), new String(cen, off + CENHDR, CENNAM(cen, off)));
 145         print("    ExtraLen    :       %#6x%n", CENEXT(cen, off));
 146         if (CENEXT(cen, off) != 0)
 147             printExtra(cen, off + CENHDR + CENNAM(cen, off), CENEXT(cen, off));
 148         print("    CommentLen  :       %#6x%n", CENCOM(cen, off));
 149         print("    DiskStart   :       %#6x%n", CENDSK(cen, off));
 150         print("    Attrs       :       %#6x%n", CENATT(cen, off));
 151         print("    AttrsEx     :   %#10x%n", CENATX(cen, off));
 152         print("    LocOff      :   %#10x%n", CENOFF(cen, off));
 153 
 154     }
 155 
 156     static long locoff(byte[] cen, int pos) {
 157         long locoff = CENOFF(cen, pos);
 158         if (locoff == ZIP64_MINVAL) {    //ZIP64
 159             int off = pos + CENHDR + CENNAM(cen, pos);
 160             int end = off + CENEXT(cen, pos);
 161             while (off + 4 < end) {
 162                 int tag = SH(cen, off);
 163                 int sz = SH(cen, off + 2);
 164                 if (tag != EXTID_ZIP64) {
 165                     off += 4 + sz;
 166                     continue;
 167                 }
 168                 off += 4;
 169                 if (CENLEN(cen, pos) == ZIP64_MINVAL)
 170                     off += 8;
 171                 if (CENSIZ(cen, pos) == ZIP64_MINVAL)
 172                     off += 8;
 173                 return LL(cen, off);
 174             }
 175             // should never be here
 176         }
 177         return locoff;
 178     }
 179 
 180     static void printExtra(byte[] extra, int off, int len) {
 181         int end = off + len;
 182         while (off + 4 <= end) {
 183             int tag = SH(extra, off);
 184             int sz = SH(extra, off + 2);
 185             print("        [tag=0x%04x, sz=%d, data= ", tag, sz);
 186             if (off + sz > end) {
 187                 print("    Error: Invalid extra data, beyond extra length");
 188                 break;
 189             }
 190             off += 4;
 191             for (int i = 0; i < sz; i++)
 192                 print("%02x ", extra[off + i]);
 193             print("]%n");
 194             switch (tag) {
 195             case EXTID_ZIP64 :
 196                 print("         ->ZIP64: ");
 197                 int pos = off;
 198                 while (pos + 8 <= off + sz) {
 199                     print(" *0x%x ", LL(extra, pos));
 200                     pos += 8;
 201                 }
 202                 print("%n");
 203                 break;
 204             case EXTID_NTFS:
 205                 print("         ->PKWare NTFS%n");
 206                 // 4 bytes reserved
 207                 if (SH(extra, off + 4) !=  0x0001 || SH(extra, off + 6) !=  24)
 208                     print("    Error: Invalid NTFS sub-tag or subsz");
 209                 print("            mtime:%tc%n",
 210                       winToJavaTime(LL(extra, off + 8)));
 211                 print("            atime:%tc%n",
 212                       winToJavaTime(LL(extra, off + 16)));
 213                 print("            ctime:%tc%n",
 214                       winToJavaTime(LL(extra, off + 24)));
 215                 break;
 216             case EXTID_EXTT:
 217                 print("         ->Info-ZIP Extended Timestamp: flag=%x%n",extra[off]);
 218                 pos = off + 1 ;
 219                 while (pos + 4 <= off + sz) {
 220                     print("            *%tc%n",
 221                           unixToJavaTime(LG(extra, pos)));
 222                     pos += 4;
 223                 }
 224                 break;
 225             default:
 226                 print("         ->[tag=%x, size=%d]%n", tag, sz);
 227             }
 228             off += sz;
 229         }
 230     }
 231 }