All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jnlp.sample.jardiff.JarDiffPatcher Maven / Gradle / Ivy

Go to download

JNLP Sample servlet that supports pack200 protocol. Taken from Sun's JDK sample/jnlp directory thanks to its permissive license.

The newest version!
/*
 * @(#)JarDiffPatcher.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.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;

/**
 * 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.
 * 

* Refer to the JNLP spec for details on how this is done. * * @version 1.11, 06/26/03 */ public class JarDiffPatcher implements JarDiffConstants, Patcher { 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 = JarDiff.getResources(); public static ResourceBundle getResources() { return JarDiff.getResources(); } public void applyPatch( Patcher.PatchDelegate delegate, String oldJarPath, String jarDiffPath, OutputStream result ) throws IOException { File oldFile = new File( oldJarPath ); File diffFile = new File( jarDiffPath ); JarOutputStream jos = new JarOutputStream( result ); JarFile oldJar = new JarFile( oldFile ); JarFile jarDiff = new JarFile( diffFile ); Set ignoreSet = new HashSet(); Map renameMap = new HashMap(); determineNameMapping( jarDiff, ignoreSet, renameMap ); // get all keys in renameMap Object[] keys = renameMap.keySet().toArray(); // Files to implicit move Set oldjarNames = new HashSet(); Enumeration oldEntries = oldJar.entries(); if ( oldEntries != null ) { while ( oldEntries.hasMoreElements() ) { oldjarNames.add( ( (JarEntry) oldEntries.nextElement() ).getName() ); } } // size depends on the three parameters below, which is // basically the counter for each loop that do the actual // writes to the output file // since oldjarNames.size() changes in the first two loop // below, we need to adjust the size accordingly also when // oldjarNames.size() changes double size = oldjarNames.size() + keys.length + jarDiff.size(); double currentEntry = 0; // Handle all remove commands oldjarNames.removeAll( ignoreSet ); size -= ignoreSet.size(); // Add content from JARDiff Enumeration entries = jarDiff.entries(); if ( entries != null ) { while ( entries.hasMoreElements() ) { JarEntry entry = (JarEntry) entries.nextElement(); if ( !INDEX_NAME.equals( entry.getName() ) ) { updateDelegate( delegate, currentEntry, size ); currentEntry++; writeEntry( jos, entry, jarDiff ); // Remove entry from oldjarNames since no implicit //move is needed boolean wasInOld = oldjarNames.remove( entry.getName() ); // Update progress counters. If it was in old, we do // not need an implicit move, so adjust total size. if ( wasInOld ) { size--; } } else { // no write is done, decrement size size--; } } } // go through the renameMap and apply move for each entry for ( int j = 0; j < keys.length; j++ ) { // Apply move command String newName = (String) keys[j]; String oldName = (String) renameMap.get( newName ); // Get source JarEntry JarEntry oldEntry = oldJar.getJarEntry( oldName ); if ( oldEntry == null ) { String moveCmd = MOVE_COMMAND + oldName + " " + newName; handleException( "jardiff.error.badmove", moveCmd ); } // Create dest JarEntry JarEntry newEntry = new JarEntry( newName ); newEntry.setTime( oldEntry.getTime() ); newEntry.setSize( oldEntry.getSize() ); newEntry.setCompressedSize( oldEntry.getCompressedSize() ); newEntry.setCrc( oldEntry.getCrc() ); newEntry.setMethod( oldEntry.getMethod() ); newEntry.setExtra( oldEntry.getExtra() ); newEntry.setComment( oldEntry.getComment() ); updateDelegate( delegate, currentEntry, size ); currentEntry++; writeEntry( jos, newEntry, oldJar.getInputStream( oldEntry ) ); // Remove entry from oldjarNames since no implicit //move is needed boolean wasInOld = oldjarNames.remove( oldName ); // Update progress counters. If it was in old, we do // not need an implicit move, so adjust total size. if ( wasInOld ) { size--; } } // implicit move Iterator iEntries = oldjarNames.iterator(); if ( iEntries != null ) { while ( iEntries.hasNext() ) { String name = (String) iEntries.next(); JarEntry entry = oldJar.getJarEntry( name ); updateDelegate( delegate, currentEntry, size ); currentEntry++; writeEntry( jos, entry, oldJar ); } } updateDelegate( delegate, currentEntry, size ); jos.finish(); } private void updateDelegate( Patcher.PatchDelegate delegate, double currentSize, double size ) { if ( delegate != null ) { delegate.patching( (int) ( currentSize / size ) ); } } private void determineNameMapping( JarFile jarDiff, Set ignoreSet, Map renameMap ) throws IOException { InputStream is = jarDiff.getInputStream( jarDiff.getEntry( INDEX_NAME ) ); if ( is == null ) { handleException( "jardiff.error.noindex", null ); } LineNumberReader indexReader = new LineNumberReader( new InputStreamReader( is, "UTF-8" ) ); String line = indexReader.readLine(); if ( line == null || !line.equals( VERSION_HEADER ) ) { handleException( "jardiff.error.badheader", line ); } while ( ( line = indexReader.readLine() ) != null ) { if ( line.startsWith( REMOVE_COMMAND ) ) { List sub = getSubpaths( line.substring( REMOVE_COMMAND.length() ) ); if ( sub.size() != 1 ) { handleException( "jardiff.error.badremove", line ); } ignoreSet.add( sub.get( 0 ) ); } else if ( line.startsWith( MOVE_COMMAND ) ) { List sub = getSubpaths( line.substring( MOVE_COMMAND.length() ) ); if ( sub.size() != 2 ) { handleException( "jardiff.error.badmove", line ); } // target of move should be the key if ( renameMap.put( sub.get( 1 ), sub.get( 0 ) ) != null ) { // invalid move - should not move to same target twice handleException( "jardiff.error.badmove", line ); } } else if ( line.length() > 0 ) { handleException( "jardiff.error.badcommand", line ); } } } private void handleException( String errorMsg, String line ) throws IOException { try { throw new IOException( getResources().getString( errorMsg ) + " " + line ); } catch ( MissingResourceException mre ) { System.err.println( "Fatal error: " + errorMsg ); new Throwable().printStackTrace( System.err ); System.exit( -1 ); } } private List getSubpaths( String path ) { int index = 0; int length = path.length(); ArrayList sub = new ArrayList(); while ( index < length ) { while ( index < length && Character.isWhitespace( path.charAt( index ) ) ) { index++; } if ( index < length ) { int start = index; int last = start; String subString = null; while ( index < length ) { char aChar = path.charAt( index ); if ( aChar == '\\' && ( index + 1 ) < length && path.charAt( index + 1 ) == ' ' ) { if ( subString == null ) { subString = path.substring( last, index ); } else { subString += path.substring( last, index ); } last = ++index; } else if ( Character.isWhitespace( aChar ) ) { break; } index++; } if ( last != index ) { if ( subString == null ) { subString = path.substring( last, index ); } else { subString += path.substring( last, index ); } } sub.add( subString ); } } return sub; } private void writeEntry( JarOutputStream jos, JarEntry entry, JarFile file ) throws IOException { writeEntry( jos, entry, file.getInputStream( entry ) ); } private void writeEntry( JarOutputStream jos, JarEntry entry, InputStream data ) throws IOException { //Create a new ZipEntry to clear the compressed size. 5079423 jos.putNextEntry( new ZipEntry( entry.getName() ) ); // Read the entry int size = data.read( newBytes ); while ( size != -1 ) { jos.write( newBytes, 0, size ); size = data.read( newBytes ); } data.close(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy