📄 jardiff.java
字号:
/* * @(#)JarDiff.java 1.13 03/06/26 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */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); 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); } } } } } // 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(); } /** * 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -