blob: 7cef6ce54ed43837156873d0f160b9c1dde4da0f [file] [log] [blame]
/*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
package com.sun.nio.zipfs;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Map;
import static com.sun.nio.zipfs.ZipConstants.*;
import static com.sun.nio.zipfs.ZipUtils.*;
/**
* Print all loc and cen headers of the ZIP file
*
* @author Xueming Shen
*/
public class ZipInfo {
public static void main(String[] args) throws Throwable {
if (args.length < 1) {
print("Usage: java ZipInfo zfname");
} else {
Map<String, ?> env = Collections.emptyMap();
ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider()
.newFileSystem(Paths.get(args[0]), env));
byte[] cen = zfs.cen;
if (cen == null) {
print("zip file is empty%n");
return;
}
int pos = 0;
byte[] buf = new byte[1024];
int no = 1;
while (pos + CENHDR < cen.length) {
print("----------------#%d--------------------%n", no++);
printCEN(cen, pos);
// use size CENHDR as the extra bytes to read, just in case the
// loc.extra is bigger than the cen.extra, try to avoid to read
// twice
long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR;
if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
ZipFileSystem.zerror("read loc header failed");
if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) {
// have to read the second time;
len = LOCHDR + LOCNAM(buf) + LOCEXT(buf);
if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
ZipFileSystem.zerror("read loc header failed");
}
printLOC(buf);
pos += CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos);
}
zfs.close();
}
}
static void print(String fmt, Object... objs) {
System.out.printf(fmt, objs);
}
static void printLOC(byte[] loc) {
print("%n");
print("[Local File Header]%n");
print(" Signature : %#010x%n", LOCSIG(loc));
if (LOCSIG(loc) != LOCSIG) {
print(" Wrong signature!");
return;
}
print(" Version : %#6x [%d.%d]%n",
LOCVER(loc), LOCVER(loc) / 10, LOCVER(loc) % 10);
print(" Flag : %#6x%n", LOCFLG(loc));
print(" Method : %#6x%n", LOCHOW(loc));
print(" LastMTime : %#10x [%tc]%n",
LOCTIM(loc), dosToJavaTime(LOCTIM(loc)));
print(" CRC : %#10x%n", LOCCRC(loc));
print(" CSize : %#10x%n", LOCSIZ(loc));
print(" Size : %#10x%n", LOCLEN(loc));
print(" NameLength : %#6x [%s]%n",
LOCNAM(loc), new String(loc, LOCHDR, LOCNAM(loc)));
print(" ExtraLength : %#6x%n", LOCEXT(loc));
if (LOCEXT(loc) != 0)
printExtra(loc, LOCHDR + LOCNAM(loc), LOCEXT(loc));
}
static void printCEN(byte[] cen, int off) {
print("[Central Directory Header]%n");
print(" Signature : %#010x%n", CENSIG(cen, off));
if (CENSIG(cen, off) != CENSIG) {
print(" Wrong signature!");
return;
}
print(" VerMadeby : %#6x [%d, %d.%d]%n",
CENVEM(cen, off), (CENVEM(cen, off) >> 8),
(CENVEM(cen, off) & 0xff) / 10,
(CENVEM(cen, off) & 0xff) % 10);
print(" VerExtract : %#6x [%d.%d]%n",
CENVER(cen, off), CENVER(cen, off) / 10, CENVER(cen, off) % 10);
print(" Flag : %#6x%n", CENFLG(cen, off));
print(" Method : %#6x%n", CENHOW(cen, off));
print(" LastMTime : %#10x [%tc]%n",
CENTIM(cen, off), dosToJavaTime(CENTIM(cen, off)));
print(" CRC : %#10x%n", CENCRC(cen, off));
print(" CSize : %#10x%n", CENSIZ(cen, off));
print(" Size : %#10x%n", CENLEN(cen, off));
print(" NameLen : %#6x [%s]%n",
CENNAM(cen, off), new String(cen, off + CENHDR, CENNAM(cen, off)));
print(" ExtraLen : %#6x%n", CENEXT(cen, off));
if (CENEXT(cen, off) != 0)
printExtra(cen, off + CENHDR + CENNAM(cen, off), CENEXT(cen, off));
print(" CommentLen : %#6x%n", CENCOM(cen, off));
print(" DiskStart : %#6x%n", CENDSK(cen, off));
print(" Attrs : %#6x%n", CENATT(cen, off));
print(" AttrsEx : %#10x%n", CENATX(cen, off));
print(" LocOff : %#10x%n", CENOFF(cen, off));
}
static long locoff(byte[] cen, int pos) {
long locoff = CENOFF(cen, pos);
if (locoff == ZIP64_MINVAL) { //ZIP64
int off = pos + CENHDR + CENNAM(cen, pos);
int end = off + CENEXT(cen, pos);
while (off + 4 < end) {
int tag = SH(cen, off);
int sz = SH(cen, off + 2);
if (tag != EXTID_ZIP64) {
off += 4 + sz;
continue;
}
off += 4;
if (CENLEN(cen, pos) == ZIP64_MINVAL)
off += 8;
if (CENSIZ(cen, pos) == ZIP64_MINVAL)
off += 8;
return LL(cen, off);
}
// should never be here
}
return locoff;
}
static void printExtra(byte[] extra, int off, int len) {
int end = off + len;
while (off + 4 <= end) {
int tag = SH(extra, off);
int sz = SH(extra, off + 2);
print(" [tag=0x%04x, sz=%d, data= ", tag, sz);
if (off + sz > end) {
print(" Error: Invalid extra data, beyond extra length");
break;
}
off += 4;
for (int i = 0; i < sz; i++)
print("%02x ", extra[off + i]);
print("]%n");
switch (tag) {
case EXTID_ZIP64 :
print(" ->ZIP64: ");
int pos = off;
while (pos + 8 <= off + sz) {
print(" *0x%x ", LL(extra, pos));
pos += 8;
}
print("%n");
break;
case EXTID_NTFS:
print(" ->PKWare NTFS%n");
// 4 bytes reserved
if (SH(extra, off + 4) != 0x0001 || SH(extra, off + 6) != 24)
print(" Error: Invalid NTFS sub-tag or subsz");
print(" mtime:%tc%n",
winToJavaTime(LL(extra, off + 8)));
print(" atime:%tc%n",
winToJavaTime(LL(extra, off + 16)));
print(" ctime:%tc%n",
winToJavaTime(LL(extra, off + 24)));
break;
case EXTID_EXTT:
print(" ->Info-ZIP Extended Timestamp: flag=%x%n",extra[off]);
pos = off + 1 ;
while (pos + 4 <= off + sz) {
print(" *%tc%n",
unixToJavaTime(LG(extra, pos)));
pos += 4;
}
break;
default:
print(" ->[tag=%x, size=%d]%n", tag, sz);
}
off += sz;
}
}
}