package org.codehaus.plexus.archiver.zip;
/*
* Copyright 2001-2002,2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import java.util.Hashtable;
import java.util.Vector;
import java.util.zip.ZipException;
/**
* ZipExtraField related methods
*
* @version $Revision$ $Date$
* from org.apache.ant.tools.zip.ExtraFieldUtils v1.9
*/
public class ExtraFieldUtils
{
/**
* Static registry of known extra fields.
*
* @since 1.1
*/
private static Hashtable implementations;
static
{
implementations = new Hashtable();
register( AsiExtraField.class );
}
/**
* Register a ZipExtraField implementation.
* <p/>
* <p>The given class must have a no-arg constructor and implement
* the {@link ZipExtraField ZipExtraField interface}.</p>
*
* @since 1.1
*/
public static void register( Class c )
{
try
{
ZipExtraField ze = (ZipExtraField) c.newInstance();
implementations.put( ze.getHeaderId(), c );
}
catch ( ClassCastException cc )
{
throw new RuntimeException( c + " doesn\'t implement ZipExtraField" );
}
catch ( InstantiationException ie )
{
throw new RuntimeException( c + " is not a concrete class" );
}
catch ( IllegalAccessException ie )
{
throw new RuntimeException( c + "\'s no-arg constructor is not public" );
}
}
/**
* Create an instance of the approriate ExtraField, falls back to
* {@link UnrecognizedExtraField UnrecognizedExtraField}.
*
* @since 1.1
*/
public static ZipExtraField createExtraField( ZipShort headerId )
throws InstantiationException, IllegalAccessException
{
Class c = (Class) implementations.get( headerId );
if ( c != null )
{
return (ZipExtraField) c.newInstance();
}
UnrecognizedExtraField u = new UnrecognizedExtraField();
u.setHeaderId( headerId );
return u;
}
/**
* Split the array into ExtraFields and populate them with the
* give data.
*
* @since 1.1
*/
public static ZipExtraField[] parse( byte[] data )
throws ZipException
{
Vector v = new Vector();
int start = 0;
while ( start <= data.length - 4 )
{
ZipShort headerId = new ZipShort( data, start );
int length = ( new ZipShort( data, start + 2 ) ).getValue();
if ( start + 4 + length > data.length )
{
throw new ZipException( "data starting at " + start + " is in unknown format" );
}
try
{
ZipExtraField ze = createExtraField( headerId );
ze.parseFromLocalFileData( data, start + 4, length );
v.addElement( ze );
}
catch ( InstantiationException ie )
{
throw new ZipException( ie.getMessage() );
}
catch ( IllegalAccessException iae )
{
throw new ZipException( iae.getMessage() );
}
start += ( length + 4 );
}
if ( start != data.length )
{ // array not exhausted
throw new ZipException( "data starting at " + start + " is in unknown format" );
}
ZipExtraField[] result = new ZipExtraField[v.size()];
v.copyInto( result );
return result;
}
/**
* Merges the local file data fields of the given ZipExtraFields.
*
* @since 1.1
*/
public static byte[] mergeLocalFileDataData( ZipExtraField[] data )
{
int sum = 4 * data.length;
for ( int i = 0; i < data.length; i++ )
{
sum += data[ i ].getLocalFileDataLength().getValue();
}
byte[] result = new byte[sum];
int start = 0;
for ( int i = 0; i < data.length; i++ )
{
System.arraycopy( data[i].getHeaderId().getBytes(), 0, result, start, 2 );
System.arraycopy( data[i].getLocalFileDataLength().getBytes(), 0, result, start + 2, 2 );
byte[] local = data[ i ].getLocalFileDataData();
System.arraycopy( local, 0, result, start + 4, local.length );
start += ( local.length + 4 );
}
return result;
}
/**
* Merges the central directory fields of the given ZipExtraFields.
*
* @since 1.1
*/
public static byte[] mergeCentralDirectoryData( ZipExtraField[] data )
{
int sum = 4 * data.length;
for ( int i = 0; i < data.length; i++ )
{
sum += data[ i ].getCentralDirectoryLength().getValue();
}
byte[] result = new byte[sum];
int start = 0;
for ( int i = 0; i < data.length; i++ )
{
System.arraycopy( data[i].getHeaderId().getBytes(), 0, result, start, 2 );
System.arraycopy( data[i].getCentralDirectoryLength().getBytes(), 0, result, start + 2, 2 );
byte[] local = data[ i ].getCentralDirectoryData();
System.arraycopy( local, 0, result, start + 4, local.length );
start += ( local.length + 4 );
}
return result;
}
}