Sindbad~EG File Manager

Current Path : /usr/local/diablo-jdk1.6.0/sample/jnlp/servlet/src/classes/jnlp/sample/jardiff/
Upload File :
Current File : /usr/local/diablo-jdk1.6.0/sample/jnlp/servlet/src/classes/jnlp/sample/jardiff/JarDiff.java

/*
 * @(#)JarDiff.java	1.7 05/11/17
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */

package jnlp.sample.jardiff;

import java.io.*;
import java.util.*;
import java.util.jar.*;
import java.util.zip.*;


/**
 * JarDiff is able to create a jar file containing the delta between two
 * jar files (old and new). The delta jar file can then be applied to the
 * old jar file to reconstruct the new jar file.
 * <p>
 * Refer to the JNLP spec for details on how this is done.
 *
 * @version 1.13, 06/26/03
 */
public class JarDiff implements JarDiffConstants {
    private static final int DEFAULT_READ_SIZE = 2048;
    private static byte[] newBytes = new byte[DEFAULT_READ_SIZE];
    private static byte[] oldBytes = new byte[DEFAULT_READ_SIZE];
    private static ResourceBundle _resources = null;

    // The JARDiff.java is the stand-along jardiff.jar tool. Thus, we do not
    // depend on Globals.java and other stuff here. Instead, we use an explicit
    // _debug flag.
    private static boolean _debug;

    public static ResourceBundle getResources() {
	if (_resources == null) {
	    _resources = ResourceBundle.getBundle("jnlp/sample/jardiff/resources/strings");
	}
	return _resources;
    }

    /**
     * Creates a patch from the two passed in files, writing the result
     * to <code>os</code>.
     */
    public static void createPatch(String oldPath, String newPath,
                            OutputStream os, boolean minimal) throws IOException{
        JarFile2 oldJar = new JarFile2(oldPath);
        JarFile2 newJar = new JarFile2(newPath);
      
        try {
          Iterator entries;
          HashMap moved = new HashMap();
          HashSet visited = new HashSet();
          HashSet implicit = new HashSet();
          HashSet moveSrc = new HashSet();
          HashSet newEntries = new HashSet();


          // FIRST PASS
          // Go through the entries in new jar and
          // determine which files are candidates for implicit moves
          // ( files that has the same filename and same content in old.jar
          // and new.jar )
          // and for files that cannot be implicitly moved, we will either
          // find out whether it is moved or new (modified)
          entries = newJar.getJarEntries();
          if (entries != null) {
            while (entries.hasNext()) {
                JarEntry newEntry = (JarEntry)entries.next(); 
		        String newname = newEntry.getName();
	
                // Return best match of contents, will return a name match if possible 
                String oldname = oldJar.getBestMatch(newJar, newEntry);
                if (oldname == null) {
                    // New or modified entry
                    if (_debug) {
                        System.out.println("NEW: "+ newname); 
                    }
                    newEntries.add(newname);
                } else {
                    // Content already exist - need to do a move
		    
                    // Should do implicit move? Yes, if names are the same, and
                    // no move command already exist from oldJar
                    if (oldname.equals(newname) && !moveSrc.contains(oldname)) {
                        if (_debug) { 
                            System.out.println(newname + " added to implicit set!");
                        }
                        implicit.add(newname);
		            } else {
                    // The 1.0.1/1.0 JarDiffPatcher cannot handle
                    // multiple MOVE command with same src.
                    // The work around here is if we are going to generate
                    // a MOVE command with duplicate src, we will
                    // instead add the target as a new file.  This way
                    // the jardiff can be applied by 1.0.1/1.0
                    // JarDiffPatcher also.
                        if (!minimal && (implicit.contains(oldname) || 
                            moveSrc.contains(oldname) )) {
			    
                            // generate non-minimal jardiff
                            // for backward compatibility
			   
                            if (_debug) {
				    
                                System.out.println("NEW: "+ newname); 
                            }
                            newEntries.add(newname);			
                        } else {
                            // Use newname as key, since they are unique
                            if (_debug) {
                                System.err.println("moved.put " + newname + " " + oldname); 
                            }
                            moved.put(newname, oldname);
                            moveSrc.add(oldname);
                        }
                        // Check if this disables an implicit 'move <oldname> <oldname>'
                        if (implicit.contains(oldname) && minimal) { 
			  
                           if (_debug) {
                              System.err.println("implicit.remove " + oldname);
				
                              System.err.println("moved.put " + oldname + " " + oldname); 
				
                            }
                            implicit.remove(oldname);
                            moved.put(oldname, oldname);
                            moveSrc.add(oldname);		     
                        }

		
                    } 
                }
            }
          } //if (entries != null)
	
          // SECOND PASS: <deleted files> = <oldjarnames> - <implicitmoves> - 
          // <source of move commands> - <new or modified entries>
          ArrayList deleted = new ArrayList();
          entries = oldJar.getJarEntries();
          if (entries != null) {
              while (entries.hasNext()) {
                  JarEntry oldEntry = (JarEntry)entries.next();
                  String oldName = oldEntry.getName();
                  if (!implicit.contains(oldName) && !moveSrc.contains(oldName)
                    && !newEntries.contains(oldName)) {
                      if (_debug) {
                          System.err.println("deleted.add " + oldName);
                      }
                      deleted.add(oldName);
                  }
              }
          }
	
          //DEBUG
          if (_debug) {
              //DEBUG:  print out moved map
              entries = moved.keySet().iterator();
              if (entries != null) {
                  System.out.println("MOVED MAP!!!");
                  while (entries.hasNext()) {
                      String newName = (String)entries.next();
                      String oldName = (String)moved.get(newName);	
                      System.out.println("key is " + newName + " value is " + oldName);
                      }
              }
	    
              //DEBUG:  print out IMOVE map
              entries = implicit.iterator();
              if (entries != null) {
                  System.out.println("IMOVE MAP!!!");
                  while (entries.hasNext()) {
                      String newName = (String)entries.next();		 
                      System.out.println("key is " + newName);
                  }
              }
          }

          JarOutputStream jos = new JarOutputStream(os);

          // Write out all the MOVEs and REMOVEs
          createIndex(jos, deleted, moved);

          // Put in New and Modified entries
          entries = newEntries.iterator();
          if (entries != null) {
	   
              while (entries.hasNext()) {
                  String newName = (String)entries.next();		      
                  if (_debug) {
                      System.out.println("New File: " + newName);
                  }
                  writeEntry(jos, newJar.getEntryByName(newName), newJar);
              }
          }
     
    
          jos.finish();
          jos.close();

        } catch (IOException ioE){
          throw ioE;
        } finally {
          try { 
              oldJar.getJarFile().close();
          } catch (IOException e1) {
              //ignore
          }
          try { 
              newJar.getJarFile().close();
          } catch (IOException e1) {
            //ignore
          }
        } // finally
    }

    /**
     * Writes the index file out to <code>jos</code>.
     * <code>oldEntries</code> gives the names of the files that were removed,
     * <code>movedMap</code> maps from the new name to the old name.
     */
    private static void createIndex(JarOutputStream jos, List oldEntries,
                             Map movedMap) throws
                       IOException {
        StringWriter writer = new StringWriter();

        writer.write(VERSION_HEADER);
        writer.write("\r\n");

        // Write out entries that have been removed
        for (int counter = 0; counter < oldEntries.size(); counter++) {
            String name = (String)oldEntries.get(counter);

            writer.write(REMOVE_COMMAND);
            writer.write(" ");
            writeEscapedString(writer, name);
            writer.write("\r\n");
        }

        // And those that have moved
        Iterator names = movedMap.keySet().iterator();

        if (names != null) {
            while (names.hasNext()) {
                String newName = (String)names.next();
                String oldName = (String)movedMap.get(newName);

		writer.write(MOVE_COMMAND);
		writer.write(" ");
		writeEscapedString(writer, oldName);
		writer.write(" ");
		writeEscapedString(writer, newName);
		writer.write("\r\n");
		   
            }
        }

        JarEntry je = new JarEntry(INDEX_NAME);
        byte[] bytes = writer.toString().getBytes("UTF-8");

        writer.close();
        jos.putNextEntry(je);
        jos.write(bytes, 0, bytes.length);
    }

    private static void writeEscapedString(Writer writer, String string)
                      throws IOException {
        int index = 0;
        int last = 0;
        char[] chars = null;

        while ((index = string.indexOf(' ', index)) != -1) {
            if (last != index) {
                if (chars == null) {
                    chars = string.toCharArray();
                }
                writer.write(chars, last, index - last);
            }
            last = index;
            index++;
            writer.write('\\');
        }
        if (last != 0) {
            writer.write(chars, last, chars.length - last);
        }
        else {
            // no spaces
            writer.write(string);
        }
    }

    private static void writeEntry(JarOutputStream jos, JarEntry entry,
                            JarFile2 file) throws IOException {
        writeEntry(jos, entry, file.getJarFile().getInputStream(entry));
    }

    private static void writeEntry(JarOutputStream jos, JarEntry entry,
                            InputStream data) throws IOException {
        jos.putNextEntry(entry);

        try {
            // Read the entry
            int size = data.read(newBytes);

            while (size != -1) {
                jos.write(newBytes, 0, size);
                size = data.read(newBytes);
            }
        } catch(IOException ioE) {
            throw ioE;
        } finally {
            try {
                data.close();
            } catch(IOException e){
                //Ignore
            }

        }
    }

   
  

    /**
     * JarFile2 wraps a JarFile providing some convenience methods.
     */
    private static class JarFile2 {
        private JarFile _jar;
        private List _entries;
        private HashMap _nameToEntryMap;
	private HashMap _crcToEntryMap;
            
        public JarFile2(String path) throws IOException {
            _jar = new JarFile(new File(path));
            index();
        }

        public JarFile getJarFile() {
            return _jar;
        }

        public Iterator getJarEntries() {
            return _entries.iterator();
        }

        public JarEntry getEntryByName(String name) {
            return (JarEntry)_nameToEntryMap.get(name);
        }

	/**
	 * Returns true if the two InputStreams differ.
	 */
	private static boolean differs(InputStream oldIS, InputStream newIS) 
	    throws IOException {
        int newSize = 0;
        int oldSize;
        int total = 0;
        boolean retVal = false;
	    
        try{
            while (newSize != -1) {
                newSize = newIS.read(newBytes);
                oldSize = oldIS.read(oldBytes);
		
                if (newSize != oldSize) {
                    if (_debug) {
                        System.out.println("\tread sizes differ: " + newSize +
                            " " + oldSize + " total " + total);
                    }
                    retVal = true;
                    break;
                }
                if (newSize > 0) {
                    while (--newSize >= 0) {
                        total++;
                        if (newBytes[newSize] != oldBytes[newSize]) {
                            if (_debug) {
                                System.out.println("\tbytes differ at " +
                                                    total);
                            }
                            retVal = true;
                            break;
                        }
                        if ( retVal ) {
                            //Jump out
                            break;
                        }
                        newSize = 0;
                    }
                }
            }
        } catch(IOException ioE){
            throw ioE;
        } finally {
            try {
                oldIS.close();
            } catch(IOException e){
                //Ignore
            }
            try {
                newIS.close();
            } catch(IOException e){
                //Ignore
            }
        }
	    return retVal;
	}
	
	public String getBestMatch(JarFile2 file, JarEntry entry) throws IOException {
	    // check for same name and same content, return name if found
	    if (contains(file, entry)) {
		return (entry.getName());
	    }

	    // return name of same content file or null
	    return (hasSameContent(file,entry));
	}
	
	public boolean contains(JarFile2 f, JarEntry e) throws IOException {

	    JarEntry thisEntry = getEntryByName(e.getName());
	  	 
	    // Look up name in 'this' Jar2File - if not exist return false
	    if (thisEntry == null)
		return false;

	    // Check CRC - if no match - return false
	    if (thisEntry.getCrc() != e.getCrc())
		return false;

	    // Check contents - if no match - return false
	    InputStream oldIS = getJarFile().getInputStream(thisEntry);
	    InputStream newIS = f.getJarFile().getInputStream(e);
	    boolean retValue = differs(oldIS, newIS);

	    return !retValue;
	}

	public String hasSameContent(JarFile2 file, JarEntry entry) throws
	IOException {

	    String thisName = null;
	    
	    Long crcL = new Long(entry.getCrc());

	    // check if this jar contains files with the passed in entry's crc
	    if (_crcToEntryMap.containsKey(crcL)) {
	        // get the Linked List with files with the crc
      		LinkedList ll = (LinkedList)_crcToEntryMap.get(crcL);
	        // go through the list and check for content match
	        ListIterator li = ll.listIterator(0);
	        if (li != null) {
	            while (li.hasNext()) {
		            JarEntry thisEntry = (JarEntry)li.next();

		            // check for content match
	                InputStream oldIS = getJarFile().getInputStream(thisEntry);
	                InputStream newIS = file.getJarFile().getInputStream(entry);		
			    
	                if (!differs(oldIS, newIS)) {
	                    thisName = thisEntry.getName();
	                    return thisName;
	                }
	            }
		    }
	    }
	 
	    return thisName;
	   
	}


      

       
        private void index() throws IOException {
            Enumeration entries = _jar.entries();

            _nameToEntryMap = new HashMap();
	    _crcToEntryMap = new HashMap();
         
            _entries = new ArrayList();
            if (_debug) {
                System.out.println("indexing: " + _jar.getName());
            }
            if (entries != null) {
                while (entries.hasMoreElements()) {
                    JarEntry entry = (JarEntry)entries.nextElement();
                   
		    long crc = entry.getCrc(); 

		    Long crcL = new Long(crc);

                    if (_debug) {
                        System.out.println("\t" + entry.getName() + " CRC " +
                                      crc);
                    }
		 
                    _nameToEntryMap.put(entry.getName(), entry);
                    _entries.add(entry);

		    // generate the CRC to entries map
		    if (_crcToEntryMap.containsKey(crcL)) {
			// key exist, add the entry to the correcponding
			// linked list

			// get the linked list
			LinkedList ll = (LinkedList)_crcToEntryMap.get(crcL);

			// put in the new entry
			ll.add(entry);

			// put it back in the hash map
			_crcToEntryMap.put(crcL, ll);
		    } else {
			// create a new entry in the hashmap for the new key
			
			// first create the linked list and put in the new
			// entry
			LinkedList ll = new LinkedList();
			ll.add(entry);

			// create the new entry in the hashmap
			_crcToEntryMap.put(crcL, ll);
		    }
                  
                }
            }
        }
             
    }


    private static void showHelp() {
        System.out.println("JarDiff: [-nonminimal (for backward compatibility with 1.0.1/1.0] [-creatediff | -applydiff] [-output file] old.jar new.jar");
    }

    // -creatediff -applydiff -debug -output file
    public static void main(String[] args) throws IOException {
        boolean diff = true;
	boolean minimal = true;
        String outputFile = "out.jardiff";

        for (int counter = 0; counter < args.length; counter++) {
	    // for backward compatibilty with 1.0.1/1.0
	    if (args[counter].equals("-nonminimal") ||
                args[counter].equals("-n")) {
		minimal = false;
	    } 
	    else if (args[counter].equals("-creatediff") ||
                args[counter].equals("-c")) {
                diff = true;
            }
            else if (args[counter].equals("-applydiff") ||
                args[counter].equals("-a")) {
                diff = false;
            }
            else if (args[counter].equals("-debug") ||
                args[counter].equals("-d")) {
                _debug = true;
            }
            else if (args[counter].equals("-output") ||
                     args[counter].equals("-o")) {
                if (++counter < args.length) {
                    outputFile = args[counter];
                }
            }
            else if (args[counter].equals("-applydiff") ||
                args[counter].equals("-a")) {
                diff = false;
            }
            else {
                if ((counter + 2) != args.length) {
                    showHelp();
                    System.exit(0);
                }
                if (diff) {
                    try {
                        OutputStream os = new FileOutputStream(outputFile);

                        JarDiff.createPatch(args[counter],
					      args[counter + 1], os, minimal);
                        os.close();
                    } catch (IOException ioe) {
			try {
			    System.out.println(getResources().getString("jardiff.error.create") + " " + ioe);
			} catch (MissingResourceException mre) {
			}
		    }
                }
                else {
                    try {
                        OutputStream os = new FileOutputStream(outputFile);

                        new JarDiffPatcher().applyPatch(
                            null,
                            args[counter],
                            args[counter + 1],
                            os);
                        os.close();
                    } catch (IOException ioe) {
			try {
			    System.out.println(getResources().getString("jardiff.error.apply") + " " + ioe);
			} catch (MissingResourceException mre) {
			}
                    }
                }
                System.exit(0);
            }
        }
        showHelp();
    }
}

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists