[kaffe] CVS kaffe (guilhem): Fixes for Jar tool.

Kaffe CVS cvs-commits at kaffe.org
Thu Apr 28 07:14:11 PDT 2005


PatchSet 6429 
Date: 2005/04/28 14:09:31
Author: guilhem
Branch: HEAD
Tag: (none) 
Log:
Fixes for Jar tool.

        * libraries/javalib/kaffe/tools/jar/Jar.java
        (buildUnicityMap): New method.
        (addMapEntry): New method.
        (unicityMap): New field.
        (createJar): Use unicityMap directly.
        (updateFilesInJar): Use unicityMap directly.

Members: 
	ChangeLog:1.3957->1.3958 
	libraries/javalib/kaffe/tools/jar/Jar.java:INITIAL->1.8 

Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.3957 kaffe/ChangeLog:1.3958
--- kaffe/ChangeLog:1.3957	Thu Apr 28 11:21:33 2005
+++ kaffe/ChangeLog	Thu Apr 28 14:09:31 2005
@@ -1,3 +1,12 @@
+2005-04-28  Guilhem Lavaux  <guilhem at kaffe.org>
+
+	* libraries/javalib/kaffe/tools/jar/Jar.java
+	(buildUnicityMap): New method.
+	(addMapEntry): New method.
+	(unicityMap): New field.
+	(createJar): Use unicityMap directly.
+	(updateFilesInJar): Use unicityMap directly.
+	
 2005-04-27  Dalibor Topic  <robilad at kaffe.org>
 
 	* developers/patch-libtool-no-default-install.diff:
===================================================================
Checking out kaffe/libraries/javalib/kaffe/tools/jar/Jar.java
RCS:  /home/cvs/kaffe/kaffe/libraries/javalib/kaffe/tools/jar/Jar.java,v
VERS: 1.8
***************
--- /dev/null	Sun Aug  4 19:57:58 2002
+++ kaffe/libraries/javalib/kaffe/tools/jar/Jar.java	Thu Apr 28 14:14:11 2005
@@ -0,0 +1,1531 @@
+/* Program : Jar
+
+   Use this class to create .zip and .jar files in Java.
+   It should work as a drop in replacement for the JDK's jar program.
+
+   Copyright : Moses DeJong, dejong at cs.umn.edu, 1998, 2000.
+   Source code licensed under the GPL.
+   You can get a copy of the license from www.gnu.org.
+
+   This code is intended for use in the Kaffe project but you can use
+   it in other projects as long as you follow the license rules.
+
+*/
+
+
+package kaffe.tools.jar;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Enumeration;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import kaffe.util.Base64;
+
+public class Jar {
+
+    public static void main(String[] argv) {
+	if (debug) {
+	    System.out.println("entered Jar.main()");
+	    System.out.flush();
+	}
+
+	Jar j = new Jar(argv);
+
+	j.setExitOnError(true);
+
+	try {
+	    j.start();
+	} catch (IOException e) {
+	    e.printStackTrace();
+	    j.exit(2);
+	}
+    }
+
+    public Jar(String[] argv) {
+	this.argv = argv;
+    }
+
+
+    //  Begin processing the command line
+
+    public void start() throws IOException {
+
+	// First process the command line arguments so that we know
+	// What mode we are going to be running in.
+
+	processCommandLine();
+
+	processJar();
+
+    }
+
+
+    public void setExitOnError(boolean exitOnError) {
+	if (exitOnError) {
+	    exitCode = 1;
+	} else {
+	    exitCode = 0;
+	}
+    }
+
+    public int getCompletionCode() {
+	return exitCode;
+    }
+
+    void exit(int code) {
+	if (exitCode != 0) {
+
+	    if (debug) {
+		System.out.println("now exiting with code " + code);
+		System.out.flush();
+
+		try {
+		    throw new Exception();
+		} catch (Exception e) {
+		    e.printStackTrace();
+		    System.err.flush();
+		    try {
+			Thread.sleep(5000);
+		    } catch (Exception e2) {}
+		}
+	    }
+
+	    System.out.flush();
+	    System.err.flush();
+	    System.exit(code);
+	} else {
+	    exitCode = code;
+	}
+    }
+
+    void processCommandLine() throws IOException
+    {
+	// Initial set of options tell us if we are extracting or
+	// creating an archive, if zip compressing will be used,
+	// if a manifest will be included and so on.
+
+	if (debug) {
+	    System.out.println("entered Jar.processCommandLine()");
+	    System.out.flush();
+	}
+
+	if (argv.length == 0) {
+	    printUsage();
+	    exit(1);
+	}
+
+
+	// The first argument gives the options to the jar program
+
+	String options = argv[0];
+
+	// This will store where the "next" argv index
+
+	int options_index = 1;
+
+	int i = 0;
+
+	// if the first char is a '-' just ignore it
+
+	if (options.charAt(0) == '-') {
+	    i++;
+	}
+
+	for (; i < options.length() ; i++) {
+	    switch (options.charAt(i)) {
+	    case 'c': // Create new archive
+	    case 't': // List archive table
+	    case 'x': // Extract from archive
+	    case 'u': // Update archive
+
+		// Fall through an process all possible modes
+		if (mode != 0) {
+		    printUsage();
+		    exit(1);
+		}
+
+		mode = options.charAt(i);
+		break;
+
+	    case 'v': // Verbose listing
+		verbose = true;
+		break;
+
+	    case 'f': // Archive file name
+
+		if (archive != null || options_index >= argv.length) {
+		    printUsage();
+		    exit(1);
+		}
+
+		archive = argv[options_index++];
+		break;
+
+	    case 'm': // Manifest file name
+
+		if (manifest != null || options_index >= argv.length ||
+		    !create_manifest) {
+		    printUsage();
+		    exit(1);
+		}
+
+		manifest = argv[options_index++];
+		break;
+
+	    case '0': // Turn off ZIP compression
+		compression = false;
+		break;
+
+	    case 'M': // Do not create a Manifest file in the archive
+
+		if (manifest != null) {
+		    printUsage();
+		    exit(1);
+		}
+
+		create_manifest = false;
+		break;
+
+	    default:
+		System.out.println("Illegal option: " + options.charAt(i));
+		printUsage();
+		exit(1);
+	    }
+	}
+
+
+	// now get the remaining files that need to be processed
+	// and keep track of any -C (dir change) arguments
+
+	i = options_index;
+	if ((argv.length - i) > 0) {
+
+	    files = new String[argv.length - i];
+
+	    for (int j = 0; i < argv.length ; i++, j++) {
+		if (argv[i].equals("-C")) {
+		    // Make sure we did not run out of arguments
+		    // and that "-C -C" or "-C dir -C" are not given
+		    if ((i + 2) >= argv.length ||
+                        argv[i+1].equals("-C") ||
+			argv[i+2].equals("-C")) {
+			printUsage();
+			exit(1);
+		    }
+
+		    i++;
+
+		    if (dir_changes == null) {
+			dir_changes = new String[files.length]; 
+		    }
+
+		    dir_changes[j] = argv[i];
+		j--;
+		} else {
+		    files[j] = argv[i];
+		}
+	    }
+
+
+	    // If there were dir changes we must trim the files
+	    // so that only valid files are in the array
+
+	    if (dir_changes != null) {
+		for (i=0; i < files.length ; i++) {
+		    if (files[i] == null) {
+			break;
+		    }
+		}
+		String[] tmp;
+
+		tmp = files;
+		files = new String[i];
+		System.arraycopy(tmp,0,files,0,i);
+
+		tmp = dir_changes;
+		dir_changes = new String[i];
+		System.arraycopy(tmp,0,dir_changes,0,i);	       
+	    }
+	}
+
+
+	// Check to make sure the mode is compatible with the arguments
+
+	switch (mode) {
+	case 'c':
+	    // When creating we must have at least on file argument
+
+	    if (files == null) {
+		System.out.println("'c' flag requires that input files be specified!");
+		printUsage();
+		exit(1);
+	    }
+
+	    break;
+
+	case 't':
+	    // Listing an archive can have 0 file arguments.
+
+	    // Make sure that no -C options were given when -t is used
+
+	    if (dir_changes != null) {
+		System.out.println("'t' flag can not be used with the -C flag!");
+		printUsage();
+		exit(1);  
+	    }
+
+	    // If archive file name is given then make sure it exists
+
+	    if (archive != null) {
+		XPFile archive_file = new XPFile(archive);
+		if (! archive_file.exists()) {
+		    System.out.println("archive \"" +
+				       archive_file.getPath() + "\" does not exist");
+		    exit(1);
+		}
+	    }
+
+	    break;
+
+	case 'x':
+	    // Extract from archive can have 0 file arguments.
+
+	    // If archive file name is given make sure it exists
+
+	    if (archive != null) {
+		XPFile archive_file = new XPFile(archive);
+		if (! archive_file.exists()) {
+		    System.out.println("archive \"" +
+				       archive_file.getPath() + "\" does not exist");
+		    exit(1);
+		}
+	    }
+
+	    break;
+
+	case 'u':
+	    // Update of archive requires files to update
+	    // Update without an archive makes no sense.
+
+	    if (files == null || archive == null) {
+		System.out.println("'u' flag requires that manifest or archive or input files be specified!");
+		printUsage();
+		exit(1);
+	    }
+
+	    if (archive != null) {
+		XPFile archive_file = new XPFile(archive);
+		if (! archive_file.exists()) {
+		    System.out.println("archive \"" +
+				       archive_file.getPath() + "\" does not exist");
+		    System.out.flush();
+		    exit(1);
+		}
+	    }
+
+	    break;
+
+	default:
+	    System.out.println("One of the options -{ctxu} must be specified!");
+	    printUsage();
+	    exit(1);
+	}
+
+	// lookup table must be created after the mode has been checked
+	createFileLookupTable();
+
+	if (debug) {
+	    dump();
+	}
+    }
+
+
+    void printUsage() {
+	PrintStream o = vout;
+
+        o.println("Usage: jar {ctxu}[vfm0M] [jar-file] [manifest-file] [-C dir] files ...");
+	o.println("Options:");
+	o.print('\t');
+	o.println("-c  create new archive");
+	o.print('\t');
+	o.println("-t  list table of contents for archive");
+	o.print('\t');
+	o.println("-x  extract named (or all) files from archive");
+	o.print('\t');
+	o.println("-u  update existing archive");
+	o.print('\t');
+	o.println("-v  generate verbose output on standard output");
+	o.print('\t');
+	o.println("-f  specify archive file name");
+	o.print('\t');
+	o.println("-m  include manifest information from specified manifest file");
+	o.print('\t');
+	o.println("-0  store only; use no ZIP compression");
+	o.print('\t');
+	o.println("-M  Do not create a manifest file for the entries");
+	o.print('\t');
+	o.println("-C  change to the specified directory and include the following files");
+	o.println("If any file is a directory then it is processed recursively.");
+	o.println("The manifest file name and the archive file name needs to be specified");
+	o.println("in the same order the 'm' and 'f' flags are specified.");
+	o.println();
+	o.println("Example 1: to archive two class files into an archive called classes.jar:");
+	o.print('\t');
+	o.println("jar cvf classes.jar Foo.class Bar.class");
+	o.println("Example 2: use an existing manifest file 'mymanifest' and archive all the");
+	o.print('\t');
+	o.print('\t');
+	o.println("files in the foo/ directory into 'classes.jar':");
+	o.print('\t');
+	o.println("jar cvfm classes.jar mymanifest -C foo/ .");
+    }
+
+
+
+
+    void processJar() throws IOException
+    {
+	if (debug) {
+	    System.out.println("entered Jar.processCommandLine()");
+	    System.out.println("current mode is " + mode);
+	    System.out.flush();
+	}
+
+	// Get the current directory
+
+	switch (mode) {
+	case 'c':
+	    createJar(files, absolute_files);
+	    exit(0);
+	    break;
+	case 't':
+	    listFilesInJar(files);
+	    exit(0);
+	    break;
+	case 'x':
+	    extractFilesInJar(files, absolute_files);
+	    exit(0);
+	    break;
+	case 'u':
+	    updateFilesInJar(files, absolute_files);
+	    exit(0);
+	    break;
+	default:
+	    System.out.println("Unexpected error, '" + mode + "' not matched");
+	    exit(1);
+	}
+
+    }
+
+    void addMapEntry(Map m, String shortname, XPFile entry)
+    {
+      // Make sure the entryname ends with a '/' if it is a directory
+      
+      boolean entryfile_isDirectory = entry.isDirectory();
+
+      if (entryfile_isDirectory) {
+	if (shortname.length() == 0) {
+	  // Something is very wrong here.
+	  throw new RuntimeException("entryname was empty");
+	}
+	
+	if (shortname.charAt( shortname.length() - 1 ) != '/') {
+	  shortname = shortname + '/';
+	}
+      }
+      
+      m.put(shortname, entry);
+      
+      if (!entryfile_isDirectory)
+	return;
+      
+      String[] dir_files = entry.list();
+
+      for (int i = 0; i < dir_files.length; i++) {
+	XPFile abs_entry = new XPFile(entry, dir_files[i]);
+	String rel_entry = new XPFile(shortname, dir_files[i]).getPath();
+
+	addMapEntry(m, rel_entry, abs_entry);
+      }
+    }
+
+    // Build a set containing all shortnames
+    void buildUnicityMap()
+    {
+      unicityMap = new HashMap();
+
+      for (int i = 0; i < files.length; i++)
+	addMapEntry(unicityMap, new XPFile(files[i]).getPath(), new XPFile(absolute_files[i]));
+    }
+  
+
+    // Create a table that will map argument file names to
+    // fully qualified file names.
+
+    void createFileLookupTable() throws IOException
+    {
+
+	//final boolean debug = true;
+
+	if (debug) {
+	    System.out.println("entered Jar.createFileLookupTable()");
+	    System.out.flush();
+	}
+
+	if (files == null) {
+	    if (debug) {
+		System.out.println("no files for lookup table");
+	    }	    
+	    return;
+	}
+
+
+	File parent = null;
+	File tmp;
+
+
+	// File existence requirements for each mode
+	// 'u': Files must exist.
+	// 'x': None
+	// 't': None
+	// 'c': Files must exist.
+
+	boolean requireExistence = (mode == 'u' || mode == 'c');
+
+	boolean existenceError = false;
+
+	absolute_files = new String[files.length];
+
+	for (int i = 0; i < files.length ; i++) {
+
+	    // At this point, make sure that any Windows
+	    // Style \ chars in the relative file names are
+	    // replaced with unix style / chars so that matching
+	    // the file name to the jar entry works. This also
+	    // requires that XPFile is used on the file names later.
+
+	    files[i] = files[i].replace('\\','/');
+
+	    if (dir_changes != null && dir_changes[i] != null) {
+		parent = new XPFile(dir_changes[i]);
+	    }
+
+	    // if the file is already absolute then do not
+	    // combine it with the -C argument
+
+	    tmp = new XPFile(files[i]);
+
+	    if (! tmp.isAbsolute()) {
+		tmp = new XPFile(parent,files[i]);
+	    } else {
+		// Find and remove the first '/' in the short name
+		String name = files[i];
+		int index = name.indexOf('/');
+
+		if (index == -1) {
+		    // Something really strange happended, the file
+		    // is absolute so something is really screwed up
+
+		    throw new RuntimeException("absolute file " +
+			          name + " had no '/' chars in it");
+		}
+
+		// gaurd against the case where / is at the end of the string
+		if ((index + 1) < name.length()) {
+		    files[i] = name.substring(index + 1);
+		}
+	    }
+
+
+	    String absolute_name = tmp.getAbsolutePath();
+
+	    if (debug) {
+	        String canon = tmp.getCanonicalPath();
+
+		System.out.println("absolute  was \"" + absolute_name + "\"");
+		System.out.println("canon     was \"" + canon + "\"");
+
+		System.out.println("file name is \"" + files[i]
+				   + "\"");
+
+		System.out.println("absolute_name is \"" +
+				   absolute_name + "\"");
+
+		System.out.println("exists() is \"" + tmp.exists() + "\"");
+
+		System.out.println("isDirectory() is \"" +
+				      tmp.isDirectory() + "\"");
+	    }
+
+	    if (requireExistence && !tmp.exists()) {
+		existenceError = true;
+		// Non existant file error message
+		System.out.println(tmp.getPath() + 
+				   ": no such file or directory");
+	    }
+
+	    absolute_files[i] = absolute_name;
+	}
+
+	if (existenceError) {
+	    // The JDK's jar will print each bad file name before
+	    // exiting so we do that too
+
+	    if (debug) {
+		System.out.println("calling exit() because of existence error");
+	    }
+
+	    exit(2); 
+	}
+	
+	// If we are in update mode we also have to walk the full tree to be able to
+	// remove the redundant entries in the jar.
+	if (requireExistence) {
+	  buildUnicityMap();
+	}
+    }
+
+    // List the file arguments that exist in this jar file
+    // if files argument is null then list them all
+
+    void listFilesInJar(String[] shortnames)
+	throws IOException {
+
+	if (debug) {
+	    System.out.println("entered Jar.listFilesInJar()");
+	    System.out.flush();
+	}
+
+	ZipInputStream zin;
+	ZipEntry       entry;
+
+	//final boolean debug = true;
+
+	if (debug) {
+	    System.out.println("opening archive \"" + archive + "\"");
+	}
+
+	if (archive == null) {
+	    zin = new ZipInputStream(System.in);
+	} else {
+	    zin = new ZipInputStream(new XPFileInputStream(archive));
+	}
+
+	try {
+	    while ((entry = zin.getNextEntry()) != null) { 
+		// close entry right after we open it so that
+		// all the data is read in and we can read the entry.
+
+		zin.closeEntry();
+
+
+		// see if the current ZipEntry's name equals 
+		// the file we want to extract. If equal then
+		// print the name of the file to stdout.
+
+		String entry_name = entry.getName();
+		boolean match = (shortnames == null);
+
+		if (! match) {
+		    if (debug) {
+			System.out.println("looking for match for \"" +
+					   entry_name + "\"");
+		    }
+
+		    for (int i = 0; i < shortnames.length ; i++) {
+			if (entry_name.equals(shortnames[i])) {
+			    match = true;
+			}
+		    }
+		}
+
+		if (match) {
+		    if (debug) {
+			System.out.println("found match for \"" +
+					   entry_name + "\"");
+		    }
+
+		    if (verbose) {
+			// FORMAT for verbose jar output.
+			// 10 Wed Feb 10 01:42:40 CST 1999 data.txt
+
+
+			// print size in at least 6 char wide field
+			// with right justification.
+
+			int width = 6;
+
+			String info = String.valueOf(entry.getSize());
+
+			if (info.length() > width) {
+			    vout.print(info);
+			} else {
+			    while (width > info.length()) {
+				vout.print(' ');
+				width--;
+			    }
+			    vout.print(info);
+			}
+
+
+			vout.print(' ');
+
+			Date date = new Date(entry.getTime());
+
+			vout.print(date);
+
+			vout.print(' ');
+
+			vout.println(entry_name);
+
+		    } else {
+			vout.println(entry_name);
+		    }
+		}
+	    }
+
+	} finally {
+	    zin.close();
+	}
+
+    }
+
+
+
+    void extractFilesInJar(String[] shortnames, String[] longnames)
+	throws IOException
+    {
+	ZipInputStream zin;
+	ZipEntry       entry;
+
+	//final boolean debug = true;
+
+	if (debug) {
+	    System.out.println("opening archive \"" + archive + "\"");
+	}
+
+	if (archive == null) {
+	    zin = new ZipInputStream(System.in);
+	} else {
+	    zin = new ZipInputStream(new XPFileInputStream(archive));
+	}
+
+	try {
+	    while ((entry = zin.getNextEntry()) != null) { 
+		// see if the current ZipEntry's name equals 
+		// the file we want to extract. If equal then
+		// print the name of the file to stdout.
+
+		String entry_name = entry.getName();
+		boolean match = (shortnames == null);
+		String longname = entry_name;
+
+		if (! match) {
+		    if (debug) {
+			System.out.println("looking for match for \"" +
+					   entry_name + "\"");
+		    }
+
+		    for (int i = 0; i < shortnames.length ; i++) {
+			if (entry_name.equals(shortnames[i])) {
+			    match = true;
+			    longname = longnames[i];
+			}
+		    }
+		}
+
+		if (match) {
+		    if (debug) {
+			System.out.println("found match for \"" +
+					   entry_name + "\"");
+		    }
+
+		    if (verbose) {
+			// FORMAT for verbose jar output.
+			// Actually, there is a bug in the JDK jar
+			// implementation in that the output is
+			// exactly the opposite of what is shown here.
+			// The JDK output makes not sense so we do not
+			// duplicate the bug in this implementation.
+
+			//  for DEFLATED entries
+			//   created: META-INF/
+			//  inflated: META-INF/MANIFEST.MF
+
+			//  for STORED entries
+		        //   created: META-INF/
+			// extracted: META-INF/MANIFEST.MF
+
+
+			// print in at least 10 char wide field
+			// with right justification.
+
+			int width = 10;
+
+			String info;
+
+			if (entry.isDirectory()) {
+			    info = "created";
+			} else {
+			    if (entry.getMethod() == ZipEntry.STORED) {
+				info = "extracted";
+			    } else {
+				info = "inflated";
+			    }
+			}
+
+			if (info.length() > width) {
+			    vout.print(info);
+			} else {
+			    while (width > info.length()) {
+				vout.print(' ');
+				width--;
+			    }
+			    vout.print(info);
+			}
+
+
+			vout.print(':');
+			vout.print(' ');
+
+			vout.println(entry_name);
+
+		    }
+
+		    // Now Extract the entry.
+
+
+		    if (entry.isDirectory()) {
+			// If the entry is a directory then
+			// we can just create that directory
+			// and go on to the next entry
+
+			XPFile dir = new XPFile(longname);
+			if (! dir.exists()) {
+			    dir.mkdirs();
+			}
+
+			continue;
+		    }
+
+
+		    // If it is in a directory that does
+		    // not exist we will need to create it.
+
+		    ensureParentsExist(longname);
+
+		    if (debug) {
+			System.out.println("opening output file \"" +
+					   longname + "\"");
+		    }
+
+		    XPFileOutputStream fos = new XPFileOutputStream(longname);
+
+		    try {
+			readwriteStreams(zin, fos);
+		    } finally {
+			fos.close();
+		    }
+
+		}
+	    }
+
+	} finally {
+	    zin.close();
+	}
+
+    }
+
+
+
+
+
+
+    void updateFilesInJar(String[] shortnames, String[] longnames)
+	throws IOException
+    {
+	    // TODO: Handle the Manifest argument.
+
+	    // create the jar output stream in memory.
+	    // rewrite not updated files into jar output stream.
+	    // write updated and fresh files into jar output stream.
+	    // write memory contents of jar outpur stream to previous
+	    // jar file.
+
+	    ZipFile zf = new ZipFile(archive);
+	    ByteArrayOutputStream baos = new ByteArrayOutputStream((int) new File(archive).length());
+	    ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(baos));
+	    Enumeration entries = zf.entries();
+	    
+	    //final boolean debug = true;
+
+	    if (debug) {
+		    System.out.println("opening archive \"" + archive + "\"");
+	    }
+	    
+	    try {
+		    while (entries.hasMoreElements()) { 
+			    // The ZIP file spec allows the entry data to be specified after the
+			    // compressed data for that entry. This means entry.getSize() can be 0.
+			    // A simple hack-around this is to mark the input stream with a
+			    // sufficient look ahead buffer (512 k in this case), get the next entry
+			    // and reset. This of course only works, if the files on the zip input stream
+
+			    ZipEntry entry = (ZipEntry) entries.nextElement();
+
+			    long size = entry.getSize();
+
+			    // see if the current ZipEntry's name equals 
+			    // the file we want to extract. If equal then
+			    // print the name of the file to stdout.
+			    
+			    String entry_name = entry.getName();
+			    String longname = entry_name;
+			    
+			    if (debug) {
+			      System.out.println("looking for match for \"" +
+						 entry_name + "\"");
+			    }
+			    
+			    if (unicityMap.get(entry_name) != null) {
+			      if (debug) {
+				System.out.println("found match for \"" +
+						   entry_name + "\"");
+			      }
+			      
+			      // skip matching entries, removing them from the
+			      // output stream. So entries that need to be 
+			      // updated don't appear on the stream twice.
+			      continue;
+			    }
+			    
+			    ZipEntry new_entry = new ZipEntry(entry_name);
+			    
+			    // Copy values of fields over from original entry
+			    // except for compressedSize, which can change
+			    // depending on the zip compression implementation.
+			    
+			    new_entry.setComment(entry.getComment());
+			    new_entry.setExtra(entry.getExtra());
+			    new_entry.setMethod(entry.getMethod());
+			    new_entry.setTime(entry.getTime());
+			    new_entry.setSize(entry.getSize());
+
+			    // Directories have a CRC of 0
+			    if (size == 0) {
+				    new_entry.setCrc(0);
+			    }
+	  
+			    // write the entry out into jar output stream
+			    zos.putNextEntry(new_entry);
+
+			    InputStream in = zf.getInputStream(entry);
+
+			    try {
+				    readwriteStreams(in, zos);
+			    } finally {
+				    in.close();
+			    }
+
+			    zos.closeEntry();
+		    }
+
+		    // add the updated entries
+		    

*** Patch too long, truncated ***




More information about the kaffe mailing list