diff options
Diffstat (limited to 'test/java/util/zip/zip.java')
-rw-r--r-- | test/java/util/zip/zip.java | 743 |
1 files changed, 743 insertions, 0 deletions
diff --git a/test/java/util/zip/zip.java b/test/java/util/zip/zip.java new file mode 100644 index 0000000000..33eccf9496 --- /dev/null +++ b/test/java/util/zip/zip.java @@ -0,0 +1,743 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.*; +import java.nio.charset.Charset; +import java.util.*; +import java.util.zip.*; +import java.text.MessageFormat; + +/** + * A stripped-down version of Jar tool with a "-encoding" option to + * support non-UTF8 encoidng for entry name and comment. + */ +public class zip { + String program; + PrintStream out, err; + String fname; + String zname = ""; + String[] files; + Charset cs = Charset.forName("UTF-8"); + + Map<String, File> entryMap = new HashMap<String, File>(); + Set<File> entries = new LinkedHashSet<File>(); + List<String> paths = new ArrayList<String>(); + + CRC32 crc32 = new CRC32(); + /* + * cflag: create + * uflag: update + * xflag: xtract + * tflag: table + * vflag: verbose + * flag0: no zip compression (store only) + */ + boolean cflag, uflag, xflag, tflag, vflag, flag0; + + private static ResourceBundle rsrc; + static { + try { + // just use the jar message + rsrc = ResourceBundle.getBundle("sun.tools.jar.resources.jar"); + } catch (MissingResourceException e) { + throw new Error("Fatal: Resource for jar is missing"); + } + } + + public zip(PrintStream out, PrintStream err, String program) { + this.out = out; + this.err = err; + this.program = program; + } + + private boolean ok; + + public synchronized boolean run(String args[]) { + ok = true; + if (!parseArgs(args)) { + return false; + } + try { + if (cflag || uflag) { + if (fname != null) { + zname = fname.replace(File.separatorChar, '/'); + if (zname.startsWith("./")) { + zname = zname.substring(2); + } + } + } + if (cflag) { + OutputStream out; + if (fname != null) { + out = new FileOutputStream(fname); + } else { + out = new FileOutputStream(FileDescriptor.out); + if (vflag) { + vflag = false; + } + } + expand(null, files, false); + create(new BufferedOutputStream(out, 4096)); + out.close(); + } else if (uflag) { + File inputFile = null, tmpFile = null; + FileInputStream in; + FileOutputStream out; + if (fname != null) { + inputFile = new File(fname); + String path = inputFile.getParent(); + tmpFile = File.createTempFile("tmp", null, + new File((path == null) ? "." : path)); + in = new FileInputStream(inputFile); + out = new FileOutputStream(tmpFile); + } else { + in = new FileInputStream(FileDescriptor.in); + out = new FileOutputStream(FileDescriptor.out); + vflag = false; + } + expand(null, files, true); + boolean updateOk = update(in, new BufferedOutputStream(out)); + if (ok) { + ok = updateOk; + } + in.close(); + out.close(); + if (fname != null) { + 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(); + } + } + } + } 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; + } + + + boolean parseArgs(String args[]) { + try { + args = parse(args); + } catch (FileNotFoundException e) { + fatalError(formatMsg("error.cant.open", e.getMessage())); + return false; + } catch (IOException e) { + fatalError(e); + return false; + } + 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) { + usageError(); + return false; + } + cflag = true; + break; + case 'u': + if (cflag || xflag || tflag) { + usageError(); + return false; + } + uflag = true; + break; + case 'x': + if (cflag || uflag || tflag) { + usageError(); + return false; + } + xflag = true; + break; + case 't': + if (cflag || uflag || xflag) { + usageError(); + return false; + } + tflag = true; + break; + case 'v': + vflag = true; + break; + case 'f': + fname = args[count++]; + break; + case '0': + flag0 = true; + 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) { + 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("-encoding")) { + cs = Charset.forName(args[++i]); + } else 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) { + e.printStackTrace(); + usageError(); + return false; + } + if (k != 0) { + files = new String[k]; + System.arraycopy(nameBuf, 0, files, 0, k); + } + } else if (cflag || uflag) { + error(getMsg("error.bad.uflag")); + usageError(); + return false; + } + return true; + } + + 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; + } + } + } + + void create(OutputStream out) throws IOException + { + ZipOutputStream zos = new ZipOutputStream(out, cs); + if (flag0) { + zos.setMethod(ZipOutputStream.STORED); + } + for (File file: entries) { + addFile(zos, file); + } + zos.close(); + } + + boolean update(InputStream in, OutputStream out) throws IOException + { + ZipInputStream zis = new ZipInputStream(in, cs); + ZipOutputStream zos = new ZipOutputStream(out, cs); + ZipEntry e = null; + byte[] buf = new byte[1024]; + int n = 0; + boolean updateOk = true; + + // put the old entries first, replace if necessary + while ((e = zis.getNextEntry()) != null) { + String name = e.getName(); + 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); + while ((n = zis.read(buf, 0, buf.length)) != -1) { + zos.write(buf, 0, n); + } + } 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); + } + zis.close(); + zos.close(); + return updateOk; + } + + 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; + } + + 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; + } + + 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) { + e.setSize(size); + e.setMethod(ZipEntry.STORED); + crc32File(e, file); + } + zos.putNextEntry(e); + if (!isDir) { + byte[] buf = new byte[8192]; + int len; + InputStream is = new BufferedInputStream(new FileInputStream(file)); + while ((len = is.read(buf, 0, buf.length)) != -1) { + zos.write(buf, 0, len); + } + is.close(); + } + 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")); + } + } + } + + private void crc32File(ZipEntry e, File f) throws IOException { + InputStream is = new BufferedInputStream(new FileInputStream(f)); + byte[] buf = new byte[8192]; + crc32.reset(); + int r = 0; + int nread = 0; + long len = f.length(); + while ((r = is.read(buf)) != -1) { + nread += r; + crc32.update(buf, 0, r); + } + is.close(); + if (nread != (int) len) { + throw new ZipException(formatMsg( + "error.incorrect.length", f.getPath())); + } + e.setCrc(crc32.getValue()); + } + + void replaceFSC(String files[]) { + if (files != null) { + for (String file : files) { + file = file.replace(File.separatorChar, '/'); + } + } + } + + Set<ZipEntry> newDirSet() { + return new HashSet<ZipEntry>() { + public boolean add(ZipEntry e) { + return (e == null || 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); + } + } + } + + void extract(InputStream in, String files[]) throws IOException { + ZipInputStream zis = new ZipInputStream(in, cs); + ZipEntry e; + 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; + } + } + } + } + updateLastModifiedTime(dirs); + } + + void extract(String fname, String files[]) throws IOException { + ZipFile zf = new ZipFile(fname, cs); + 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); + } + + 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())); + } + } + OutputStream os = new FileOutputStream(f); + byte[] b = new byte[8192]; + int len; + try { + while ((len = is.read(b, 0, b.length)) != -1) { + os.write(b, 0, len); + } + } finally { + if (is instanceof ZipInputStream) + ((ZipInputStream)is).closeEntry(); + else + is.close(); + os.close(); + } + if (vflag) { + if (e.getMethod() == ZipEntry.DEFLATED) { + output(formatMsg("out.inflated", name)); + } else { + output(formatMsg("out.extracted", name)); + } + } + } + long lastModified = e.getTime(); + if (lastModified != -1) { + f.setLastModified(lastModified); + } + return rc; + } + + void list(InputStream in, String files[]) throws IOException { + ZipInputStream zis = new ZipInputStream(in, cs); + ZipEntry e; + while ((e = zis.getNextEntry()) != null) { + zis.closeEntry(); + printEntry(e, files); + } + } + + void list(String fname, String files[]) throws IOException { + ZipFile zf = new ZipFile(fname, cs); + Enumeration<? extends ZipEntry> zes = zf.entries(); + while (zes.hasMoreElements()) { + printEntry(zes.nextElement(), files); + } + zf.close(); + } + + void printEntry(ZipEntry e, String[] files) throws IOException { + if (files == null) { + printEntry(e); + } else { + String name = e.getName(); + for (String file : files) { + if (name.startsWith(file)) { + printEntry(e); + return; + } + } + } + } + + void printEntry(ZipEntry e) throws IOException { + if (vflag) { + StringBuilder sb = new StringBuilder(); + String s = Long.toString(e.getSize()); + for (int i = 6 - s.length(); i > 0; --i) { + sb.append(' '); + } + sb.append(s).append(' ').append(new Date(e.getTime()).toString()); + sb.append(' ').append(e.getName()); + output(sb.toString()); + } else { + output(e.getName()); + } + } + + void usageError() { + error( + "Usage: zip {ctxu}[vf0] [zip-file] [-encoding encname][-C dir] files ...\n" + + "Options:\n" + + " -c create new archive\n" + + " -t list table of contents for archive\n" + + " -x extract named (or all) files from archive\n" + + " -u update existing archive\n" + + " -v generate verbose output on standard output\n" + + " -f specify archive file name\n" + + " -0 store only; use no ZIP compression\n" + + " -C change to the specified directory and include the following file\n" + + "If any file is a directory then it is processed recursively.\n"); + } + + void fatalError(Exception e) { + e.printStackTrace(); + } + + + void fatalError(String s) { + error(program + ": " + s); + } + + + protected void output(String s) { + out.println(s); + } + + protected void error(String s) { + err.println(s); + } + + 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 static String[] parse(String[] args) throws IOException + { + ArrayList<String> newArgs = new ArrayList<String>(args.length); + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.length() > 1 && arg.charAt(0) == '@') { + arg = arg.substring(1); + if (arg.charAt(0) == '@') { + newArgs.add(arg); + } else { + loadCmdFile(arg, newArgs); + } + } else { + newArgs.add(arg); + } + } + return newArgs.toArray(new String[newArgs.size()]); + } + + private static void loadCmdFile(String name, List<String> args) throws IOException + { + Reader r = new BufferedReader(new FileReader(name)); + StreamTokenizer st = new StreamTokenizer(r); + st.resetSyntax(); + st.wordChars(' ', 255); + st.whitespaceChars(0, ' '); + st.commentChar('#'); + st.quoteChar('"'); + st.quoteChar('\''); + while (st.nextToken() != st.TT_EOF) { + args.add(st.sval); + } + r.close(); + } + + public static void main(String args[]) { + zip z = new zip(System.out, System.err, "zip"); + System.exit(z.run(args) ? 0 : 1); + } +} + |