1211 lines · 39.7 KB · Java
RawDownload
/* * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.jar; import java.io.*;import java.nio.file.Path;import java.nio.file.Files;import java.util.*;import java.util.zip.*;import java.util.jar.*;import java.util.jar.Manifest;import java.text.MessageFormat;import sun.misc.JarIndex;import static sun.misc.JarIndex.INDEX_NAME;import static java.util.jar.JarFile.MANIFEST_NAME;import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; /** * This class implements a simple utility for creating files in the JAR * (Java Archive) file format. The JAR format is based on the ZIP file * format, with optional meta-information stored in a MANIFEST entry. */publicclass Main {    String program;    PrintStream out, err;    String fname, mname, ename;    String zname = "";    String[] files;    String rootjar = null;     // An entryName(path)->File map generated during "expand", it helps to    // decide whether or not an existing entry in a jar file needs to be    // replaced, during the "update" operation.    Map<String, File> entryMap = new HashMap<String, File>();     // All files need to be added/updated.    Set<File> entries = new LinkedHashSet<File>();     // Directories specified by "-C" operation.    Set<String> paths = new HashSet<String>();     /*     * cflag: create     * uflag: update     * xflag: xtract     * tflag: table     * vflag: verbose     * flag0: no zip compression (store only)     * Mflag: DO NOT generate a manifest file (just ZIP)     * iflag: generate jar index     */    boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag;     static final String MANIFEST_DIR = "META-INF/";    static final String VERSION = "1.0";     private static ResourceBundle rsrc;     /**     * If true, maintain compatibility with JDK releases prior to 6.0 by     * timestamping extracted files with the time at which they are extracted.     * Default is to use the time given in the archive.     */    private static final boolean useExtractionTime =        Boolean.getBoolean("sun.tools.jar.useExtractionTime");     /**     * Initialize ResourceBundle     */    static {        try {            rsrc = ResourceBundle.getBundle("sun.tools.jar.resources.jar");        } catch (MissingResourceException e) {            throw new Error("Fatal: Resource for jar is missing");        }    }     private String getMsg(String key) {        try {            return (rsrc.getString(key));        } catch (MissingResourceException e) {            throw new Error("Error in message file");        }    }     private String formatMsg(String key, String arg) {        String msg = getMsg(key);        String[] args = new String[1];        args[0] = arg;        return MessageFormat.format(msg, (Object[]) args);    }     private String formatMsg2(String key, String arg, String arg1) {        String msg = getMsg(key);        String[] args = new String[2];        args[0] = arg;        args[1] = arg1;        return MessageFormat.format(msg, (Object[]) args);    }     public Main(PrintStream out, PrintStream err, String program) {        this.out = out;        this.err = err;        this.program = program;    }     /**     * Creates a new empty temporary file in the same directory as the     * specified file.  A variant of File.createTempFile.     */    private static File createTempFileInSameDirectoryAs(File file)        throws IOException {        File dir = file.getParentFile();        if (dir == null)            dir = new File(".");        return File.createTempFile("jartmp", null, dir);    }     private boolean ok;     /**     * Starts main program with the specified arguments.     */    public synchronized boolean run(String args[]) {        ok = true;        if (!parseArgs(args)) {            return false;        }        try {            if (cflag || uflag) {                if (fname != null) {                    // The name of the zip file as it would appear as its own                    // zip file entry. We use this to make sure that we don't                    // add the zip file to itself.                    zname = fname.replace(File.separatorChar, '/');                    if (zname.startsWith("./")) {                        zname = zname.substring(2);                    }                }            }            if (cflag) {                Manifest manifest = null;                InputStream in = null;                 if (!Mflag) {                    if (mname != null) {                        in = new FileInputStream(mname);                        manifest = new Manifest(new BufferedInputStream(in));                    } else {                        manifest = new Manifest();                    }                    addVersion(manifest);                    addCreatedBy(manifest);                    if (isAmbiguousMainClass(manifest)) {                        if (in != null) {                            in.close();                        }                        return false;                    }                    if (ename != null) {                        addMainClass(manifest, ename);                    }                }                OutputStream out;                if (fname != null) {                    out = new FileOutputStream(fname);                } else {                    out = new FileOutputStream(FileDescriptor.out);                    if (vflag) {                        // Disable verbose output so that it does not appear                        // on stdout along with file data                        // error("Warning: -v option ignored");                        vflag = false;                    }                }                expand(null, files, false);                create(new BufferedOutputStream(out, 4096), manifest);                if (in != null) {                    in.close();                }                out.close();            } else if (uflag) {                File inputFile = null, tmpFile = null;                FileInputStream in;                FileOutputStream out;                if (fname != null) {                    inputFile = new File(fname);                    tmpFile = createTempFileInSameDirectoryAs(inputFile);                    in = new FileInputStream(inputFile);                    out = new FileOutputStream(tmpFile);                } else {                    in = new FileInputStream(FileDescriptor.in);                    out = new FileOutputStream(FileDescriptor.out);                    vflag = false;                }                InputStream manifest = (!Mflag && (mname != null)) ?                    (new FileInputStream(mname)) : null;                expand(null, files, true);                boolean updateOk = update(in, new BufferedOutputStream(out),                                          manifest, null);                if (ok) {                    ok = updateOk;                }                in.close();                out.close();                if (manifest != null) {                    manifest.close();                }                if (fname != null) {                    // on Win32, we need this delete                    inputFile.delete();                    if (!tmpFile.renameTo(inputFile)) {                        tmpFile.delete();                        throw new IOException(getMsg("error.write.file"));                    }                    tmpFile.delete();                }            } else if (tflag) {                replaceFSC(files);                if (fname != null) {                    list(fname, files);                } else {                    InputStream in = new FileInputStream(FileDescriptor.in);                    try{                        list(new BufferedInputStream(in), files);                    } finally {                        in.close();                    }                }            } else if (xflag) {                replaceFSC(files);                if (fname != null && files != null) {                    extract(fname, files);                } else {                    InputStream in = (fname == null)                        ? new FileInputStream(FileDescriptor.in)                        : new FileInputStream(fname);                    try {                        extract(new BufferedInputStream(in), files);                    } finally {                        in.close();                    }                }            } else if (iflag) {                genIndex(rootjar, files);            }        } catch (IOException e) {            fatalError(e);            ok = false;        } catch (Error ee) {            ee.printStackTrace();            ok = false;        } catch (Throwable t) {            t.printStackTrace();            ok = false;        }        out.flush();        err.flush();        return ok;    }     /**     * Parses command line arguments.     */    boolean parseArgs(String args[]) {        /* Preprocess and expand @file arguments */        try {            args = CommandLine.parse(args);        } catch (FileNotFoundException e) {            fatalError(formatMsg("error.cant.open", e.getMessage()));            return false;        } catch (IOException e) {            fatalError(e);            return false;        }        /* parse flags */        int count = 1;        try {            String flags = args[0];            if (flags.startsWith("-")) {                flags = flags.substring(1);            }            for (int i = 0; i < flags.length(); i++) {                switch (flags.charAt(i)) {                case 'c':                    if (xflag || tflag || uflag || iflag) {                        usageError();                        return false;                    }                    cflag = true;                    break;                case 'u':                    if (cflag || xflag || tflag || iflag) {                        usageError();                        return false;                    }                    uflag = true;                    break;                case 'x':                    if (cflag || uflag || tflag || iflag) {                        usageError();                        return false;                    }                    xflag = true;                    break;                case 't':                    if (cflag || uflag || xflag || iflag) {                        usageError();                        return false;                    }                    tflag = true;                    break;                case 'M':                    Mflag = true;                    break;                case 'v':                    vflag = true;                    break;                case 'f':                    fname = args[count++];                    break;                case 'm':                    mname = args[count++];                    break;                case '0':                    flag0 = true;                    break;                case 'i':                    if (cflag || uflag || xflag || tflag) {                        usageError();                        return false;                    }                    // do not increase the counter, files will contain rootjar                    rootjar = args[count++];                    iflag = true;                    break;                case 'e':                     ename = args[count++];                     break;                default:                    error(formatMsg("error.illegal.option",                                String.valueOf(flags.charAt(i))));                    usageError();                    return false;                }            }        } catch (ArrayIndexOutOfBoundsException e) {            usageError();            return false;        }        if (!cflag && !tflag && !xflag && !uflag && !iflag) {            error(getMsg("error.bad.option"));            usageError();            return false;        }        /* parse file arguments */        int n = args.length - count;        if (n > 0) {            int k = 0;            String[] nameBuf = new String[n];            try {                for (int i = count; i < args.length; i++) {                    if (args[i].equals("-C")) {                        /* change the directory */                        String dir = args[++i];                        dir = (dir.endsWith(File.separator) ?                               dir : (dir + File.separator));                        dir = dir.replace(File.separatorChar, '/');                        while (dir.indexOf("//") > -1) {                            dir = dir.replace("//", "/");                        }                        paths.add(dir.replace(File.separatorChar, '/'));                        nameBuf[k++] = dir + args[++i];                    } else {                        nameBuf[k++] = args[i];                    }                }            } catch (ArrayIndexOutOfBoundsException e) {                usageError();                return false;            }            files = new String[k];            System.arraycopy(nameBuf, 0, files, 0, k);        } else if (cflag && (mname == null)) {            error(getMsg("error.bad.cflag"));            usageError();            return false;        } else if (uflag) {            if ((mname != null) || (ename != null)) {                /* just want to update the manifest */                return true;            } else {                error(getMsg("error.bad.uflag"));                usageError();                return false;            }        }        return true;    }     /**     * Expands list of files to process into full list of all files that     * can be found by recursively descending directories.     */    void expand(File dir, String[] files, boolean isUpdate) {        if (files == null) {            return;        }        for (int i = 0; i < files.length; i++) {            File f;            if (dir == null) {                f = new File(files[i]);            } else {                f = new File(dir, files[i]);            }            if (f.isFile()) {                if (entries.add(f)) {                    if (isUpdate)                        entryMap.put(entryName(f.getPath()), f);                }            } else if (f.isDirectory()) {                if (entries.add(f)) {                    if (isUpdate) {                        String dirPath = f.getPath();                        dirPath = (dirPath.endsWith(File.separator)) ? dirPath :                            (dirPath + File.separator);                        entryMap.put(entryName(dirPath), f);                    }                    expand(f, f.list(), isUpdate);                }            } else {                error(formatMsg("error.nosuch.fileordir", String.valueOf(f)));                ok = false;            }        }    }     /**     * Creates a new JAR file.     */    void create(OutputStream out, Manifest manifest)        throws IOException    {        ZipOutputStream zos = new JarOutputStream(out);        if (flag0) {            zos.setMethod(ZipOutputStream.STORED);        }        if (manifest != null) {            if (vflag) {                output(getMsg("out.added.manifest"));            }            ZipEntry e = new ZipEntry(MANIFEST_DIR);            e.setTime(System.currentTimeMillis());            e.setSize(0);            e.setCrc(0);            zos.putNextEntry(e);            e = new ZipEntry(MANIFEST_NAME);            e.setTime(System.currentTimeMillis());            if (flag0) {                crc32Manifest(e, manifest);            }            zos.putNextEntry(e);            manifest.write(zos);            zos.closeEntry();        }        for (File file: entries) {            addFile(zos, file);        }        zos.close();    }     private char toUpperCaseASCII(char c) {        return (c < 'a' || c > 'z') ? c : (char) (c + 'A' - 'a');    }     /**

Lines 1–500 of 1211.