1211 lines · 39.7 KB · Java
RawDownload
     * Compares two strings for equality, ignoring case.  The second     * argument must contain only upper-case ASCII characters.     * We don't want case comparison to be locale-dependent (else we     * have the notorious "turkish i bug").     */    private boolean equalsIgnoreCase(String s, String upper) {        assert upper.toUpperCase(java.util.Locale.ENGLISH).equals(upper);        int len;        if ((len = s.length()) != upper.length())            return false;        for (int i = 0; i < len; i++) {            char c1 = s.charAt(i);            char c2 = upper.charAt(i);            if (c1 != c2 && toUpperCaseASCII(c1) != c2)                return false;        }        return true;    }     /**     * Updates an existing jar file.     */    boolean update(InputStream in, OutputStream out,                   InputStream newManifest,                   JarIndex jarIndex) throws IOException    {        ZipInputStream zis = new ZipInputStream(in);        ZipOutputStream zos = new JarOutputStream(out);        ZipEntry e = null;        boolean foundManifest = false;        boolean updateOk = true;         if (jarIndex != null) {            addIndex(jarIndex, zos);        }         // put the old entries first, replace if necessary        while ((e = zis.getNextEntry()) != null) {            String name = e.getName();             boolean isManifestEntry = equalsIgnoreCase(name, MANIFEST_NAME);             if ((jarIndex != null && equalsIgnoreCase(name, INDEX_NAME))                || (Mflag && isManifestEntry)) {                continue;            } else if (isManifestEntry && ((newManifest != null) ||                        (ename != null))) {                foundManifest = true;                if (newManifest != null) {                    // Don't read from the newManifest InputStream, as we                    // might need it below, and we can't re-read the same data                    // twice.                    FileInputStream fis = new FileInputStream(mname);                    boolean ambiguous = isAmbiguousMainClass(new Manifest(fis));                    fis.close();                    if (ambiguous) {                        return false;                    }                }                 // Update the manifest.                Manifest old = new Manifest(zis);                if (newManifest != null) {                    old.read(newManifest);                }                updateManifest(old, zos);            } else {                if (!entryMap.containsKey(name)) { // copy the old stuff                    // do our own compression                    ZipEntry e2 = new ZipEntry(name);                    e2.setMethod(e.getMethod());                    e2.setTime(e.getTime());                    e2.setComment(e.getComment());                    e2.setExtra(e.getExtra());                    if (e.getMethod() == ZipEntry.STORED) {                        e2.setSize(e.getSize());                        e2.setCrc(e.getCrc());                    }                    zos.putNextEntry(e2);                    copy(zis, zos);                } else { // replace with the new files                    File f = entryMap.get(name);                    addFile(zos, f);                    entryMap.remove(name);                    entries.remove(f);                }            }        }         // add the remaining new files        for (File f: entries) {            addFile(zos, f);        }        if (!foundManifest) {            if (newManifest != null) {                Manifest m = new Manifest(newManifest);                updateOk = !isAmbiguousMainClass(m);                if (updateOk) {                    updateManifest(m, zos);                }            } else if (ename != null) {                updateManifest(new Manifest(), zos);            }        }        zis.close();        zos.close();        return updateOk;    }      private void addIndex(JarIndex index, ZipOutputStream zos)        throws IOException    {        ZipEntry e = new ZipEntry(INDEX_NAME);        e.setTime(System.currentTimeMillis());        if (flag0) {            CRC32OutputStream os = new CRC32OutputStream();            index.write(os);            os.updateEntry(e);        }        zos.putNextEntry(e);        index.write(zos);        zos.closeEntry();    }     private void updateManifest(Manifest m, ZipOutputStream zos)        throws IOException    {        addVersion(m);        addCreatedBy(m);        if (ename != null) {            addMainClass(m, ename);        }        ZipEntry e = new ZipEntry(MANIFEST_NAME);        e.setTime(System.currentTimeMillis());        if (flag0) {            crc32Manifest(e, m);        }        zos.putNextEntry(e);        m.write(zos);        if (vflag) {            output(getMsg("out.update.manifest"));        }    }      private String entryName(String name) {        name = name.replace(File.separatorChar, '/');        String matchPath = "";        for (String path : paths) {            if (name.startsWith(path)                && (path.length() > matchPath.length())) {                matchPath = path;            }        }        name = name.substring(matchPath.length());         if (name.startsWith("/")) {            name = name.substring(1);        } else if (name.startsWith("./")) {            name = name.substring(2);        }        return name;    }     private void addVersion(Manifest m) {        Attributes global = m.getMainAttributes();        if (global.getValue(Attributes.Name.MANIFEST_VERSION) == null) {            global.put(Attributes.Name.MANIFEST_VERSION, VERSION);        }    }     private void addCreatedBy(Manifest m) {        Attributes global = m.getMainAttributes();        if (global.getValue(new Attributes.Name("Created-By")) == null) {            String javaVendor = System.getProperty("java.vendor");            String jdkVersion = System.getProperty("java.version");            global.put(new Attributes.Name("Created-By"), jdkVersion + " (" +                        javaVendor + ")");        }    }     private void addMainClass(Manifest m, String mainApp) {        Attributes global = m.getMainAttributes();         // overrides any existing Main-Class attribute        global.put(Attributes.Name.MAIN_CLASS, mainApp);    }     private boolean isAmbiguousMainClass(Manifest m) {        if (ename != null) {            Attributes global = m.getMainAttributes();            if ((global.get(Attributes.Name.MAIN_CLASS) != null)) {                error(getMsg("error.bad.eflag"));                usageError();                return true;            }        }        return false;    }     /**     * Adds a new file entry to the ZIP output stream.     */    void addFile(ZipOutputStream zos, File file) throws IOException {        String name = file.getPath();        boolean isDir = file.isDirectory();        if (isDir) {            name = name.endsWith(File.separator) ? name :                (name + File.separator);        }        name = entryName(name);         if (name.equals("") || name.equals(".") || name.equals(zname)) {            return;        } else if ((name.equals(MANIFEST_DIR) || name.equals(MANIFEST_NAME))                   && !Mflag) {            if (vflag) {                output(formatMsg("out.ignore.entry", name));            }            return;        }         long size = isDir ? 0 : file.length();         if (vflag) {            out.print(formatMsg("out.adding", name));        }        ZipEntry e = new ZipEntry(name);        e.setTime(file.lastModified());        if (size == 0) {            e.setMethod(ZipEntry.STORED);            e.setSize(0);            e.setCrc(0);        } else if (flag0) {            crc32File(e, file);        }        zos.putNextEntry(e);        if (!isDir) {            copy(file, zos);        }        zos.closeEntry();        /* report how much compression occurred. */        if (vflag) {            size = e.getSize();            long csize = e.getCompressedSize();            out.print(formatMsg2("out.size", String.valueOf(size),                        String.valueOf(csize)));            if (e.getMethod() == ZipEntry.DEFLATED) {                long ratio = 0;                if (size != 0) {                    ratio = ((size - csize) * 100) / size;                }                output(formatMsg("out.deflated", String.valueOf(ratio)));            } else {                output(getMsg("out.stored"));            }        }    }     /**     * A buffer for use only by copy(InputStream, OutputStream).     * Not as clean as allocating a new buffer as needed by copy,     * but significantly more efficient.     */    private byte[] copyBuf = new byte[8192];     /**     * Copies all bytes from the input stream to the output stream.     * Does not close or flush either stream.     *     * @param from the input stream to read from     * @param to the output stream to write to     * @throws IOException if an I/O error occurs     */    private void copy(InputStream from, OutputStream to) throws IOException {        int n;        while ((n = from.read(copyBuf)) != -1)            to.write(copyBuf, 0, n);    }     /**     * Copies all bytes from the input file to the output stream.     * Does not close or flush the output stream.     *     * @param from the input file to read from     * @param to the output stream to write to     * @throws IOException if an I/O error occurs     */    private void copy(File from, OutputStream to) throws IOException {        InputStream in = new FileInputStream(from);        try {            copy(in, to);        } finally {            in.close();        }    }     /**     * Copies all bytes from the input stream to the output file.     * Does not close the input stream.     *     * @param from the input stream to read from     * @param to the output file to write to     * @throws IOException if an I/O error occurs     */    private void copy(InputStream from, File to) throws IOException {        OutputStream out = new FileOutputStream(to);        try {            copy(from, out);        } finally {            out.close();        }    }     /**     * Computes the crc32 of a Manifest.  This is necessary when the     * ZipOutputStream is in STORED mode.     */    private void crc32Manifest(ZipEntry e, Manifest m) throws IOException {        CRC32OutputStream os = new CRC32OutputStream();        m.write(os);        os.updateEntry(e);    }     /**     * Computes the crc32 of a File.  This is necessary when the     * ZipOutputStream is in STORED mode.     */    private void crc32File(ZipEntry e, File f) throws IOException {        CRC32OutputStream os = new CRC32OutputStream();        copy(f, os);        if (os.n != f.length()) {            throw new JarException(formatMsg(                        "error.incorrect.length", f.getPath()));        }        os.updateEntry(e);    }     void replaceFSC(String files[]) {        if (files != null) {            for (String file : files) {                file = file.replace(File.separatorChar, '/');            }        }    }     @SuppressWarnings("serial")    Set<ZipEntry> newDirSet() {        return new HashSet<ZipEntry>() {            public boolean add(ZipEntry e) {                return ((e == null || useExtractionTime) ? false : super.add(e));            }};    }     void updateLastModifiedTime(Set<ZipEntry> zes) throws IOException {        for (ZipEntry ze : zes) {            long lastModified = ze.getTime();            if (lastModified != -1) {                File f = new File(ze.getName().replace('/', File.separatorChar));                f.setLastModified(lastModified);            }        }    }     /**     * Extracts specified entries from JAR file.     */    void extract(InputStream in, String files[]) throws IOException {        ZipInputStream zis = new ZipInputStream(in);        ZipEntry e;        // Set of all directory entries specified in archive.  Disallows        // null entries.  Disallows all entries if using pre-6.0 behavior.        Set<ZipEntry> dirs = newDirSet();        while ((e = zis.getNextEntry()) != null) {            if (files == null) {                dirs.add(extractFile(zis, e));            } else {                String name = e.getName();                for (String file : files) {                    if (name.startsWith(file)) {                        dirs.add(extractFile(zis, e));                        break;                    }                }            }        }         // Update timestamps of directories specified in archive with their        // timestamps as given in the archive.  We do this after extraction,        // instead of during, because creating a file in a directory changes        // that directory's timestamp.        updateLastModifiedTime(dirs);    }     /**     * Extracts specified entries from JAR file, via ZipFile.     */    void extract(String fname, String files[]) throws IOException {        ZipFile zf = new ZipFile(fname);        Set<ZipEntry> dirs = newDirSet();        Enumeration<? extends ZipEntry> zes = zf.entries();        while (zes.hasMoreElements()) {            ZipEntry e = zes.nextElement();            InputStream is;            if (files == null) {                dirs.add(extractFile(zf.getInputStream(e), e));            } else {                String name = e.getName();                for (String file : files) {                    if (name.startsWith(file)) {                        dirs.add(extractFile(zf.getInputStream(e), e));                        break;                    }                }            }        }        zf.close();        updateLastModifiedTime(dirs);    }     /**     * Extracts next entry from JAR file, creating directories as needed.  If     * the entry is for a directory which doesn't exist prior to this     * invocation, returns that entry, otherwise returns null.     */    ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException {        ZipEntry rc = null;        String name = e.getName();        File f = new File(e.getName().replace('/', File.separatorChar));        if (e.isDirectory()) {            if (f.exists()) {                if (!f.isDirectory()) {                    throw new IOException(formatMsg("error.create.dir",                        f.getPath()));                }            } else {                if (!f.mkdirs()) {                    throw new IOException(formatMsg("error.create.dir",                        f.getPath()));                } else {                    rc = e;                }            }             if (vflag) {                output(formatMsg("out.create", name));            }        } else {            if (f.getParent() != null) {                File d = new File(f.getParent());                if (!d.exists() && !d.mkdirs() || !d.isDirectory()) {                    throw new IOException(formatMsg(                        "error.create.dir", d.getPath()));                }            }            try {                copy(is, f);            } finally {                if (is instanceof ZipInputStream)                    ((ZipInputStream)is).closeEntry();                else                    is.close();            }            if (vflag) {                if (e.getMethod() == ZipEntry.DEFLATED) {                    output(formatMsg("out.inflated", name));                } else {                    output(formatMsg("out.extracted", name));                }            }        }        if (!useExtractionTime) {            long lastModified = e.getTime();            if (lastModified != -1) {                f.setLastModified(lastModified);            }        }        return rc;    }     /**     * Lists contents of JAR file.     */    void list(InputStream in, String files[]) throws IOException {        ZipInputStream zis = new ZipInputStream(in);        ZipEntry e;        while ((e = zis.getNextEntry()) != null) {            /*             * In the case of a compressed (deflated) entry, the entry size             * is stored immediately following the entry data and cannot be             * determined until the entry is fully read. Therefore, we close             * the entry first before printing out its attributes.             */            zis.closeEntry();            printEntry(e, files);        }    }     /**

Lines 501–1000 of 1211. Previous lines