package net.i2p.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.IOException; import java.util.zip.ZipException; import net.i2p.data.DataHelper; /** * Not available in ZipFile until Java 7. Refs: * https://secure.wikimedia.org/wikipedia/en/wiki/ZIP_%28file_format%29 * http://download.oracle.com/javase/1.5.0/docs/api/java/util/zip/ZipFile.html * http://bugs.sun.com/view_bug.do?bug_id=6646605 * * Code modified from: * http://www.flattermann.net/2009/01/read-a-zip-file-comment-with-java/ * Beerware. * * @deprecated scheduled for removal late 2017, not for external use * @since 0.8.8 */ @Deprecated public abstract class ZipFileComment { private static final int BLOCK_LEN = 22; private static final byte[] magicStart = {0x50, 0x4b, 0x03, 0x04}; private static final int HEADER_LEN = magicStart.length; private static final byte[] magicDirEnd = {0x50, 0x4b, 0x05, 0x06}; private static final int MAGIC_LEN = magicDirEnd.length; /** * @param max The max length of the comment in bytes. * If the actual comment is longer, it will not be found and * this method will throw an IOE * * @return empty string if no comment, or the comment. * The string is decoded with UTF-8 * * @throws IOException if no valid end-of-central-directory record found */ public static String getComment(File file, int max) throws IOException { return getComment(file, max, 0); } /** * @param max The max length of the comment in bytes. * If the actual comment is longer, it will not be found and * this method will throw an IOE * @param skip Number of bytes to skip in the file before looking for the * zip header. Use 56 for sud/su2 files. * * @return empty string if no comment, or the comment. * The string is decoded with UTF-8 * * @throws IOException if no valid end-of-central-directory record found */ public static String getComment(File file, int max, int skip) throws IOException { if (!file.exists()) throw new FileNotFoundException("File not found: " + file); long len = file.length(); if (len < BLOCK_LEN + HEADER_LEN + skip) throw new ZipException("File too short: " + file); if (len > Integer.MAX_VALUE) throw new ZipException("File too long: " + file); int fileLen = (int) len; byte[] buffer = new byte[Math.min(fileLen - skip, max + BLOCK_LEN)]; InputStream in = null; try { in = new FileInputStream(file); if (skip > 0) DataHelper.skip(in, skip); byte[] hdr = new byte[HEADER_LEN]; DataHelper.read(in, hdr); if (!DataHelper.eq(hdr, magicStart)) throw new ZipException("Not a zip file: " + file); DataHelper.skip(in, fileLen - (skip + HEADER_LEN + buffer.length)); DataHelper.read(in, buffer); return getComment(buffer); } finally { if (in != null) try { in.close(); } catch (IOException ioe) {} } } /** * go backwards from the end */ private static String getComment(byte[] buffer) throws IOException { for (int i = buffer.length - (1 + BLOCK_LEN - MAGIC_LEN); i >= 0; i--) { if (DataHelper.eq(buffer, i, magicDirEnd, 0, MAGIC_LEN)) { int commentLen = (buffer[i + BLOCK_LEN - 2] & 0xff) + ((buffer[i + BLOCK_LEN - 1] & 0xff) * 256); return new String(buffer, i + BLOCK_LEN, commentLen, "UTF-8"); } } throw new ZipException("No comment block found"); } public static void main(String args[]) throws IOException { if (args.length != 1) { System.err.println("Usage: ZipFileComment file"); return; } int skip = 0; String file = args[0]; if (file.endsWith(".sud") || file.endsWith(".su2")) skip = 56; String c = getComment(new File(file), 256, skip); System.out.println("comment is: \"" + c + '\"'); } }