to allow Ant generated zip/jar/war/ear files to be extracted on Unix boxes without permission problems for directories. This one uses external file attributes like InfoZip's zip does, this is a rough cut - the infrastructure to set arbitrary permissions and add user/group IDs via Zip's external fields is there, but not used ATM. Directories will always get 755 permissions right now. The testcases work on my box, and I can extract Ant created archives without any trouble - can't await tomorrows Gump run. package documentation for org.apache.tools.zip will follow. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268959 13f79535-47bb-0310-9956-ffa450edef68master
@@ -10,6 +10,9 @@ Changes that could break older environments: | |||
rmic to use a new compiler a lot easier but may break custom | |||
versions of this task that rely on the old implementation. | |||
* several Zip methods have changed their signature as we now use a Zip | |||
package of our own that handles Unix permissions for directories. | |||
Other changes: | |||
-------------- | |||
@@ -55,10 +55,10 @@ package org.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.*; | |||
import org.apache.tools.ant.types.ZipFileSet; | |||
import org.apache.tools.zip.*; | |||
import java.io.*; | |||
import java.util.Vector; | |||
import java.util.zip.*; | |||
/** | |||
* Creates a EAR archive. Based on WAR task | |||
@@ -56,9 +56,9 @@ package org.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.*; | |||
import org.apache.tools.ant.types.ZipFileSet; | |||
import org.apache.tools.zip.*; | |||
import java.io.*; | |||
import java.util.zip.*; | |||
/** | |||
* Creates a JAR archive. | |||
@@ -56,10 +56,10 @@ package org.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.*; | |||
import org.apache.tools.ant.types.ZipFileSet; | |||
import org.apache.tools.zip.*; | |||
import java.io.*; | |||
import java.util.Vector; | |||
import java.util.zip.*; | |||
/** | |||
* Creates a WAR archive. | |||
@@ -59,10 +59,12 @@ import java.util.Hashtable; | |||
import java.util.Stack; | |||
import java.util.StringTokenizer; | |||
import java.util.Vector; | |||
import java.util.zip.*; | |||
import java.util.zip.CRC32; | |||
import java.util.zip.ZipInputStream; | |||
import org.apache.tools.ant.*; | |||
import org.apache.tools.ant.types.*; | |||
import org.apache.tools.ant.util.*; | |||
import org.apache.tools.zip.*; | |||
/** | |||
* Create a ZIP archive. | |||
@@ -280,7 +282,7 @@ public class Zip extends MatchingTask { | |||
try { | |||
in = new ZipInputStream(new FileInputStream(zipSrc)); | |||
while ((entry = in.getNextEntry()) != null) { | |||
while ((entry = new ZipEntry(in.getNextEntry())) != null) { | |||
String vPath = entry.getName(); | |||
if (zipScanner.match(vPath)) { | |||
addParentDirs(null, vPath, zOut, prefix); | |||
@@ -414,6 +416,10 @@ public class Zip extends MatchingTask { | |||
ze.setMethod (ZipEntry.STORED); | |||
// This is faintly ridiculous: | |||
ze.setCrc (emptyCrc); | |||
// this is 040775 | MS-DOS directory flag in reverse byte order | |||
ze.setExternalAttributes(0x41FD0010L); | |||
zOut.putNextEntry (ze); | |||
} | |||
@@ -0,0 +1,366 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import java.util.zip.CRC32; | |||
import java.util.zip.ZipException; | |||
/** | |||
* Adds Unix file permission and UID/GID fields as well as symbolic | |||
* link handling. | |||
* | |||
* <p>This class uses the ASi extra field in the format: | |||
* <pre> | |||
* Value Size Description | |||
* ----- ---- ----------- | |||
* (Unix3) 0x756e Short tag for this extra block type | |||
* TSize Short total data size for this block | |||
* CRC Long CRC-32 of the remaining data | |||
* Mode Short file permissions | |||
* SizDev Long symlink'd size OR major/minor dev num | |||
* UID Short user ID | |||
* GID Short group ID | |||
* (var.) variable symbolic link filename | |||
* </pre> | |||
* taken from appnote.iz (Info-ZIP note, 981119) found at <a | |||
* href="ftp://ftp.uu.net/pub/archiving/zip/doc/">ftp://ftp.uu.net/pub/archiving/zip/doc/</a></p> | |||
* | |||
* <p>Short is two bytes and Long is four bytes in big endian byte and | |||
* word order, device numbers are currently not supported.</p> | |||
* | |||
* @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { | |||
private final static ZipShort HEADER_ID = new ZipShort(0x756E); | |||
/** | |||
* Standard Unix stat(2) file mode. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private int mode = 0; | |||
/** | |||
* User ID. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private int uid = 0; | |||
/** | |||
* Group ID. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private int gid = 0; | |||
/** | |||
* File this entry points to, if it is a symbolic link. | |||
* | |||
* <p>empty string - if entry is not a symbolic link.</p> | |||
* | |||
* @since 1.1 | |||
*/ | |||
private String link = ""; | |||
/** | |||
* Is this an entry for a directory? | |||
* | |||
* @since 1.1 | |||
*/ | |||
private boolean dirFlag = false; | |||
/** | |||
* Instance used to calculate checksums. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private CRC32 crc = new CRC32(); | |||
public AsiExtraField() { | |||
} | |||
/** | |||
* The Header-ID. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipShort getHeaderId() { | |||
return HEADER_ID; | |||
} | |||
/** | |||
* Length of the extra field in the local file data - without | |||
* Header-ID or length specifier. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipShort getLocalFileDataLength() { | |||
return new ZipShort( 4 // CRC | |||
+ 2 // Mode | |||
+ 4 // SizDev | |||
+ 2 // UID | |||
+ 2 // GID | |||
+ getLinkedFile().getBytes().length); | |||
} | |||
/** | |||
* Delegate to local file data. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipShort getCentralDirectoryLength() { | |||
return getLocalFileDataLength(); | |||
} | |||
/** | |||
* The actual data to put into local file data - without Header-ID | |||
* or length specifier. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public byte[] getLocalFileDataData() { | |||
// CRC will be added later | |||
byte[] data = new byte[getLocalFileDataLength().getValue() - 4]; | |||
System.arraycopy((new ZipShort(getMode())).getBytes(), 0, data, 0, 2); | |||
byte[] linkArray = getLinkedFile().getBytes(); | |||
System.arraycopy((new ZipLong(linkArray.length)).getBytes(), | |||
0, data, 2, 4); | |||
System.arraycopy((new ZipShort(getUserId())).getBytes(), | |||
0, data, 6, 2); | |||
System.arraycopy((new ZipShort(getGroupId())).getBytes(), | |||
0, data, 8, 2); | |||
System.arraycopy(linkArray, 0, data, 10, linkArray.length); | |||
crc.reset(); | |||
crc.update(data); | |||
long checksum = crc.getValue(); | |||
byte[] result = new byte[data.length + 4]; | |||
System.arraycopy((new ZipLong(checksum)).getBytes(), 0, result, 0, 4); | |||
System.arraycopy(data, 0, result, 4, data.length); | |||
return result; | |||
} | |||
/** | |||
* Delegate to local file data. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public byte[] getCentralDirectoryData() { | |||
return getLocalFileDataData(); | |||
} | |||
/** | |||
* Set the user id. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setUserId(int uid) { | |||
this.uid = uid; | |||
} | |||
/** | |||
* Get the user id. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public int getUserId() { | |||
return uid; | |||
} | |||
/** | |||
* Set the group id. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setGroupId(int gid) { | |||
this.gid = gid; | |||
} | |||
/** | |||
* Get the group id. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public int getGroupId() { | |||
return gid; | |||
} | |||
/** | |||
* Indicate that this entry is a symbolic link to the given filename. | |||
* | |||
* @param name Name of the file this entry links to, empty String | |||
* if it is not a symbolic link. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setLinkedFile(String name) { | |||
link = name; | |||
mode = getMode(mode); | |||
} | |||
/** | |||
* Name of linked file | |||
* | |||
* @return name of the file this entry links to if it is a | |||
* symbolic link, the empty string otherwise. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public String getLinkedFile() { | |||
return link; | |||
} | |||
/** | |||
* Is this entry a symbolic link? | |||
* | |||
* @since 1.1 | |||
*/ | |||
public boolean isLink() { | |||
return getLinkedFile().length() != 0; | |||
} | |||
/** | |||
* File mode of this file. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setMode(int mode) { | |||
this.mode = getMode(mode); | |||
} | |||
/** | |||
* File mode of this file. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public int getMode() { | |||
return mode; | |||
} | |||
/** | |||
* Indicate whether this entry is a directory. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setDirectory(boolean dirFlag) { | |||
this.dirFlag = dirFlag; | |||
mode = getMode(mode); | |||
} | |||
/** | |||
* Is this entry a directory? | |||
* | |||
* @since 1.1 | |||
*/ | |||
public boolean isDirectory() { | |||
return dirFlag && !isLink(); | |||
} | |||
/** | |||
* Populate data from this array as if it was in local file data. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void parseFromLocalFileData(byte[] data, int offset, int length) | |||
throws ZipException { | |||
long givenChecksum = (new ZipLong(data, offset)).getValue(); | |||
byte[] tmp = new byte[length-4]; | |||
System.arraycopy(data, offset+4, tmp, 0, length-4); | |||
crc.reset(); | |||
crc.update(tmp); | |||
long realChecksum = crc.getValue(); | |||
if (givenChecksum != realChecksum) { | |||
throw new ZipException("bad CRC checksum " | |||
+ Long.toHexString(givenChecksum) | |||
+ " instead of " | |||
+ Long.toHexString(realChecksum)); | |||
} | |||
int newMode = (new ZipShort(tmp, 0)).getValue(); | |||
byte[] linkArray = new byte[(int) (new ZipLong(tmp, 2)).getValue()]; | |||
uid = (new ZipShort(tmp, 6)).getValue(); | |||
gid = (new ZipShort(tmp, 8)).getValue(); | |||
if (linkArray.length == 0) { | |||
link = ""; | |||
} else { | |||
System.arraycopy(tmp, 10, linkArray, 0, linkArray.length); | |||
link = new String(linkArray); | |||
} | |||
setDirectory((newMode & DIR_FLAG) != 0); | |||
setMode(newMode); | |||
} | |||
/** | |||
* Get the file mode for given permissions with the correct file type. | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected int getMode(int mode) { | |||
int type = FILE_FLAG; | |||
if (isLink()) { | |||
type = LINK_FLAG; | |||
} else if (isDirectory()) { | |||
type = DIR_FLAG; | |||
} | |||
return type | (mode & PERM_MASK); | |||
} | |||
} |
@@ -0,0 +1,203 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import java.util.Hashtable; | |||
import java.util.Vector; | |||
import java.util.zip.ZipException; | |||
/** | |||
* ZipExtraField related methods | |||
* | |||
* @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
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>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; | |||
} | |||
} |
@@ -0,0 +1,113 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
/** | |||
* Constants from stat.h on Unix systems. | |||
* | |||
* @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
public interface UnixStat { | |||
/** | |||
* Bits used for permissions (and sticky bit) | |||
* | |||
* @since 1.1 | |||
*/ | |||
public static final int PERM_MASK = 07777; | |||
/** | |||
* Indicates symbolic links. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public static final int LINK_FLAG = 0120000; | |||
/** | |||
* Indicates plain files. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public static final int FILE_FLAG = 0100000; | |||
/** | |||
* Indicates directories. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public static final int DIR_FLAG = 040000; | |||
// ---------------------------------------------------------- | |||
// somewhat arbitrary choices that are quite common for shared | |||
// installations | |||
// ----------------------------------------------------------- | |||
/** | |||
* Default permissions for symbolic links. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public static final int DEFAULT_LINK_PERM = 0777; | |||
/** | |||
* Default permissions for directories. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public static final int DEFAULT_DIR_PERM = 0755; | |||
/** | |||
* Default permissions for plain files. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public static final int DEFAULT_FILE_PERM = 0644; | |||
} |
@@ -0,0 +1,131 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
/** | |||
* Simple placeholder for all those extra fields we don't want to deal | |||
* with. | |||
* | |||
* <p>Assumes local file data and central directory entries are | |||
* identical - unless told the opposite.</p> | |||
* | |||
* @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
public class UnrecognizedExtraField implements ZipExtraField { | |||
/** | |||
* The Header-ID. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private ZipShort headerId; | |||
public void setHeaderId(ZipShort headerId) { | |||
this.headerId = headerId; | |||
} | |||
public ZipShort getHeaderId() {return headerId;} | |||
/** | |||
* Extra field data in local file data - without | |||
* Header-ID or length specifier. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private byte[] localData; | |||
public void setLocalFileDataData(byte[] data) { | |||
localData = data; | |||
} | |||
public ZipShort getLocalFileDataLength() { | |||
return new ZipShort(localData.length); | |||
} | |||
public byte[] getLocalFileDataData() {return localData;} | |||
/** | |||
* Extra field data in central directory - without | |||
* Header-ID or length specifier. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private byte[] centralData; | |||
public void setCentralDirectoryData(byte[] data) { | |||
centralData = data; | |||
} | |||
public ZipShort getCentralDirectoryLength() { | |||
if (centralData != null) { | |||
return new ZipShort(centralData.length); | |||
} | |||
return getLocalFileDataLength(); | |||
} | |||
public byte[] getCentralDirectoryData() { | |||
if (centralData != null) { | |||
return centralData; | |||
} | |||
return getLocalFileDataData(); | |||
} | |||
public void parseFromLocalFileData(byte[] data, int offset, int length) { | |||
byte[] tmp = new byte[length]; | |||
System.arraycopy(data, offset, tmp, 0, length); | |||
setLocalFileDataData(tmp); | |||
} | |||
} |
@@ -0,0 +1,272 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import java.util.Vector; | |||
import java.util.zip.ZipException; | |||
/** | |||
* Extension that adds better handling of extra fields and provides | |||
* access to the internal and external file attributes. | |||
* | |||
* @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
public class ZipEntry extends java.util.zip.ZipEntry { | |||
private int internalAttributes = 0; | |||
private long externalAttributes = 0; | |||
private Vector extraFields = new Vector(); | |||
/** | |||
* Creates a new zip entry with the specified name. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipEntry(String name) { | |||
super(name); | |||
} | |||
/** | |||
* Creates a new zip entry with fields taken from the specified zip entry. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipEntry(java.util.zip.ZipEntry entry) throws ZipException { | |||
super(entry); | |||
byte[] extra = entry.getExtra(); | |||
if (extra != null) { | |||
setExtraFields(ExtraFieldUtils.parse(extra)); | |||
} else { | |||
// initializes extra data to an empty byte array | |||
setExtra(); | |||
} | |||
} | |||
/** | |||
* Creates a new zip entry with fields taken from the specified zip entry. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipEntry(ZipEntry entry) { | |||
super(entry); | |||
setInternalAttributes(entry.getInternalAttributes()); | |||
setExternalAttributes(entry.getExternalAttributes()); | |||
setExtraFields(entry.getExtraFields()); | |||
} | |||
/** | |||
* Overwrite clone | |||
* | |||
* @since 1.1 | |||
*/ | |||
public Object clone() { | |||
ZipEntry e = null; | |||
try { | |||
e = new ZipEntry((java.util.zip.ZipEntry) super.clone()); | |||
} catch (Exception ex) { | |||
// impossible as extra data is in correct format | |||
ex.printStackTrace(); | |||
} | |||
e.setInternalAttributes(getInternalAttributes()); | |||
e.setExternalAttributes(getExternalAttributes()); | |||
e.setExtraFields(getExtraFields()); | |||
return e; | |||
} | |||
/** | |||
* Retrieves the internal file attributes. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public int getInternalAttributes() { | |||
return internalAttributes; | |||
} | |||
/** | |||
* Sets the internal file attributes. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setInternalAttributes(int value) { | |||
internalAttributes = value; | |||
} | |||
/** | |||
* Retrieves the external file attributes. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public long getExternalAttributes() { | |||
return externalAttributes; | |||
} | |||
/** | |||
* Sets the external file attributes. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setExternalAttributes(long value) { | |||
externalAttributes = value; | |||
} | |||
/** | |||
* Replaces all currently attached extra fields with the new array. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setExtraFields(ZipExtraField[] fields) { | |||
extraFields.removeAllElements(); | |||
for (int i=0; i<fields.length; i++) { | |||
extraFields.addElement(fields[i]); | |||
} | |||
setExtra(); | |||
} | |||
/** | |||
* Retrieves extra fields. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipExtraField[] getExtraFields() { | |||
ZipExtraField[] result = new ZipExtraField[extraFields.size()]; | |||
extraFields.copyInto(result); | |||
return result; | |||
} | |||
/** | |||
* Adds an extra fields - replacing an already present extra field | |||
* of the same type. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void addExtraField(ZipExtraField ze) { | |||
ZipShort type = ze.getHeaderId(); | |||
boolean done = false; | |||
for (int i=0; !done && i<extraFields.size(); i++) { | |||
if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) { | |||
extraFields.setElementAt(ze, i); | |||
done = true; | |||
} | |||
} | |||
if (!done) { | |||
extraFields.addElement(ze); | |||
} | |||
setExtra(); | |||
} | |||
/** | |||
* Remove an extra fields. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void removeExtraField(ZipShort type) { | |||
boolean done = false; | |||
for (int i=0; !done && i<extraFields.size(); i++) { | |||
if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) { | |||
extraFields.removeElementAt(i); | |||
done = true; | |||
} | |||
} | |||
if (!done) { | |||
throw new java.util.NoSuchElementException(); | |||
} | |||
setExtra(); | |||
} | |||
/** | |||
* Throws an Exception if extra data cannot be parsed into extra fields. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setExtra(byte[] extra) throws RuntimeException { | |||
try { | |||
setExtraFields(ExtraFieldUtils.parse(extra)); | |||
} catch (Exception e) { | |||
throw new RuntimeException(e.getMessage()); | |||
} | |||
} | |||
/** | |||
* Unfortunately {@link java.util.zip.ZipOutputStream | |||
* java.util.zip.ZipOutputStream} seems to access the extra data | |||
* directly, so overriding getExtra doesn't help - we need to | |||
* modify super's data directly. | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected void setExtra() { | |||
super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields())); | |||
} | |||
/** | |||
* Retrieves the extra data for the local file data. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public byte[] getLocalFileDataExtra() { | |||
byte[] extra = getExtra(); | |||
return extra != null ? extra : new byte[0]; | |||
} | |||
/** | |||
* Retrieves the extra data for the central directory. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public byte[] getCentralDirectoryExtra() { | |||
return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields()); | |||
} | |||
} |
@@ -0,0 +1,119 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import java.util.zip.ZipException; | |||
/** | |||
* General format of extra field data. | |||
* | |||
* <p>Extra fields usually apper twice per file, once in the local | |||
* file data and once in the central directory. Usually they are the | |||
* same, but they don't have to be. {@link | |||
* java.util.zip.ZipOutputStream java.util.zip.ZipOutputStream} will | |||
* only use write the local file data at both places.</p> | |||
* | |||
* @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
public interface ZipExtraField { | |||
/** | |||
* The Header-ID. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipShort getHeaderId(); | |||
/** | |||
* Length of the extra field in the local file data - without | |||
* Header-ID or length specifier. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipShort getLocalFileDataLength(); | |||
/** | |||
* Length of the extra field in the central directory - without | |||
* Header-ID or length specifier. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipShort getCentralDirectoryLength(); | |||
/** | |||
* The actual data to put into local file data - without Header-ID | |||
* or length specifier. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public byte[] getLocalFileDataData(); | |||
/** | |||
* The actual data to put central directory - without Header-ID or | |||
* length specifier. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public byte[] getCentralDirectoryData(); | |||
/** | |||
* Populate data from this array as if it was in local file data. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void parseFromLocalFileData(byte[] data, int offset, int length) | |||
throws ZipException; | |||
} |
@@ -0,0 +1,142 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
/** | |||
* Utility class that represents a four byte integer with conversion | |||
* rules for the big endian byte order of ZIP files. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
public class ZipLong implements Cloneable { | |||
private long value; | |||
/** | |||
* Create instance from a number. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipLong(long value) { | |||
this.value = value; | |||
} | |||
/** | |||
* Create instance from bytes. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipLong (byte[] bytes) { | |||
this(bytes, 0); | |||
} | |||
/** | |||
* Create instance from the four bytes starting at offset. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipLong (byte[] bytes, int offset) { | |||
value = (bytes[offset+3] << 24) & 0xFF000000l; | |||
value += (bytes[offset+2] << 16) & 0xFF0000; | |||
value += (bytes[offset+1] << 8) & 0xFF00; | |||
value += (bytes[offset] & 0xFF); | |||
} | |||
/** | |||
* Get value as two bytes in big endian byte order. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public byte[] getBytes() { | |||
byte[] result = new byte[4]; | |||
result[0] = (byte) ((value & 0xFF)); | |||
result[1] = (byte) ((value & 0xFF00) >> 8); | |||
result[2] = (byte) ((value & 0xFF0000) >> 16); | |||
result[3] = (byte) ((value & 0xFF000000l) >> 24); | |||
return result; | |||
} | |||
/** | |||
* Get value as Java int. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public long getValue() { | |||
return value; | |||
} | |||
/** | |||
* Override to make two instances with same value equal. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public boolean equals(Object o) { | |||
if (o == null || !(o instanceof ZipLong)) { | |||
return false; | |||
} | |||
return value == ((ZipLong) o).getValue(); | |||
} | |||
/** | |||
* Override to make two instances with same value equal. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public int hashCode() { | |||
return (int) value; | |||
} | |||
}// ZipLong |
@@ -0,0 +1,619 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import java.io.*; | |||
import java.util.Date; | |||
import java.util.Hashtable; | |||
import java.util.Vector; | |||
import java.util.zip.CRC32; | |||
import java.util.zip.Deflater; | |||
import java.util.zip.DeflaterOutputStream; | |||
import java.util.zip.ZipException; | |||
/** | |||
* Reimplementation of {@link java.util.zip.ZipOutputStream | |||
* java.util.zip.ZipOutputStream} that does handle the extended | |||
* functionality of this package, especially internal/external file | |||
* attributes and extra fields with different layouts for local file | |||
* data and central directory entries. | |||
* | |||
* <p>This implementation will use a Data Descriptor to store size and | |||
* CRC information for DEFLATED entries, this means, you don't need to | |||
* calculate them yourself. Unfortunately this is not possible for | |||
* the STORED method, here setting the CRC and uncompressed size | |||
* information is required before {@link #putNextEntry putNextEntry} | |||
* will be called.</p> | |||
* | |||
* @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
public class ZipOutputStream extends DeflaterOutputStream { | |||
/** | |||
* Current entry. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private ZipEntry entry; | |||
/** | |||
* The file comment. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private String comment = ""; | |||
/** | |||
* Compression level for next entry. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private int level = Deflater.DEFAULT_COMPRESSION; | |||
/** | |||
* Default compression method for next entry. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private int method = DEFLATED; | |||
/** | |||
* List of ZipEntries written so far. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private Vector entries = new Vector(); | |||
/** | |||
* CRC instance to avoid parsing DEFLATED data twice. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private CRC32 crc = new CRC32(); | |||
/** | |||
* Count the bytes written to out. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private long written = 0; | |||
/** | |||
* Data for current entry started here. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private long dataStart = 0; | |||
/** | |||
* Start of central directory. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private ZipLong cdOffset = new ZipLong(0); | |||
/** | |||
* Length of central directory. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private ZipLong cdLength = new ZipLong(0); | |||
/** | |||
* Helper, a 0 as ZipShort. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private static final byte[] ZERO = {0, 0}; | |||
/** | |||
* Helper, a 0 as ZipLong. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private static final byte[] LZERO = {0, 0, 0, 0}; | |||
/** | |||
* Holds the offsets of the LFH starts for each entry | |||
* | |||
* @since 1.1 | |||
*/ | |||
private Hashtable offsets = new Hashtable(); | |||
/** | |||
* Compression method for deflated entries. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public static final int DEFLATED = ZipEntry.DEFLATED; | |||
/** | |||
* Compression method for deflated entries. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public static final int STORED = ZipEntry.STORED; | |||
/** | |||
* Creates a new ZIP OutputStream filtering the underlying stream. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipOutputStream(OutputStream out) { | |||
super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true)); | |||
} | |||
/* | |||
* Found out by experiment, that DeflaterOutputStream.close() | |||
* will call finish() - so we don't need to override close | |||
* ourselves.</p> | |||
*/ | |||
/** | |||
* Finishs writing the contents and closes this as well as the | |||
* underlying stream. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void finish() throws IOException { | |||
closeEntry(); | |||
cdOffset = new ZipLong(written); | |||
for (int i=0; i<entries.size(); i++) { | |||
writeCentralFileHeader((ZipEntry) entries.elementAt(i)); | |||
} | |||
cdLength = new ZipLong(written-cdOffset.getValue()); | |||
writeCentralDirectoryEnd(); | |||
offsets.clear(); | |||
entries.removeAllElements(); | |||
} | |||
/** | |||
* Writes all necessary data for this entry. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void closeEntry() throws IOException { | |||
if (entry == null) { | |||
return; | |||
} | |||
long realCrc = crc.getValue(); | |||
crc.reset(); | |||
if (entry.getMethod() == DEFLATED) { | |||
def.finish(); | |||
while (!def.finished()) { | |||
deflate(); | |||
} | |||
entry.setSize(def.getTotalIn()); | |||
entry.setCompressedSize(def.getTotalOut()); | |||
entry.setCrc(realCrc); | |||
def.reset(); | |||
written += entry.getCompressedSize(); | |||
} else { | |||
if (entry.getCrc() != realCrc) { | |||
throw new ZipException("bad CRC checksum for entry " | |||
+entry.getName()+ ": " | |||
+ Long.toHexString(entry.getCrc()) | |||
+ " instead of " | |||
+ Long.toHexString(realCrc)); | |||
} | |||
if (entry.getSize() != written - dataStart) { | |||
throw new ZipException("bad size for entry " | |||
+entry.getName()+ ": " | |||
+ entry.getSize() | |||
+ " instead of " | |||
+ (written - dataStart)); | |||
} | |||
} | |||
writeDataDescriptor(entry); | |||
entry = null; | |||
} | |||
/** | |||
* Begin writing next entry. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void putNextEntry(ZipEntry ze) throws IOException { | |||
closeEntry(); | |||
entry = ze; | |||
entries.addElement(entry); | |||
if (entry.getMethod() == -1) { // not specified | |||
entry.setMethod(method); | |||
} | |||
if (entry.getTime() == -1) { // not specified | |||
entry.setTime(System.currentTimeMillis()); | |||
} | |||
if (entry.getMethod() == STORED) { | |||
if (entry.getSize() == -1) { | |||
throw new ZipException("uncompressed size is required for STORED method"); | |||
} | |||
if (entry.getCrc() == -1) { | |||
throw new ZipException("crc checksum is required for STORED method"); | |||
} | |||
entry.setCompressedSize(entry.getSize()); | |||
} else { | |||
def.setLevel(level); | |||
} | |||
writeLocalFileHeader(entry); | |||
} | |||
/** | |||
* Set the file comment. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setComment(String comment) { | |||
this.comment = comment; | |||
} | |||
/** | |||
* Sets the compression level for subsequent entries. | |||
* | |||
* <p>Default is Deflater.DEFAULT_COMPRESSION.</p> | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setLevel(int level) { | |||
this.level = level; | |||
} | |||
/** | |||
* Sets the default compression method for subsequent entries. | |||
* | |||
* <p>Default is DEFLATED.</p> | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void setMethod(int method) { | |||
this.method = method; | |||
} | |||
/** | |||
* Writes bytes to ZIP entry. | |||
* | |||
* <p>Override is necessary to support STORED entries, as well as | |||
* calculationg CRC automatically for DEFLATED entries.</p> | |||
*/ | |||
public void write(byte[] b, int offset, int length) throws IOException { | |||
if (entry.getMethod() == DEFLATED) { | |||
super.write(b, offset, length); | |||
} else { | |||
out.write(b, offset, length); | |||
written += length; | |||
} | |||
crc.update(b, offset, length); | |||
} | |||
/* | |||
* Various ZIP constants | |||
*/ | |||
/** | |||
* local file header signature | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected static final ZipLong LFH_SIG = new ZipLong(0X04034B50L); | |||
/** | |||
* data descriptor signature | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected static final ZipLong DD_SIG = new ZipLong(0X08074B50L); | |||
/** | |||
* central file header signature | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected static final ZipLong CFH_SIG = new ZipLong(0X02014B50L); | |||
/** | |||
* end of central dir signature | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected static final ZipLong EOCD_SIG = new ZipLong(0X06054B50L); | |||
/** | |||
* Writes the local file header entry | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected void writeLocalFileHeader(ZipEntry ze) throws IOException { | |||
offsets.put(ze, new ZipLong(written)); | |||
out.write(LFH_SIG.getBytes()); | |||
written += 4; | |||
// version needed to extract | |||
// general purpose bit flag | |||
if (ze.getMethod() == DEFLATED) { | |||
// requires version 2 as we are going to store length info | |||
// in the data descriptor | |||
out.write((new ZipShort(20)).getBytes()); | |||
// bit3 set to signal, we use a data descriptor | |||
out.write((new ZipShort(8)).getBytes()); | |||
} else { | |||
out.write((new ZipShort(10)).getBytes()); | |||
out.write(ZERO); | |||
} | |||
written += 4; | |||
// compression method | |||
out.write((new ZipShort(ze.getMethod())).getBytes()); | |||
written += 2; | |||
// last mod. time and date | |||
out.write(toDosTime(new Date(ze.getTime())).getBytes()); | |||
written += 4; | |||
// CRC | |||
// compressed length | |||
// uncompressed length | |||
if (ze.getMethod() == DEFLATED) { | |||
out.write(LZERO); | |||
out.write(LZERO); | |||
out.write(LZERO); | |||
} else { | |||
out.write((new ZipLong(ze.getCrc())).getBytes()); | |||
out.write((new ZipLong(ze.getSize())).getBytes()); | |||
out.write((new ZipLong(ze.getSize())).getBytes()); | |||
} | |||
written += 12; | |||
// file name length | |||
byte[] name = ze.getName().getBytes(); | |||
out.write((new ZipShort(name.length)).getBytes()); | |||
written += 2; | |||
// extra field length | |||
byte[] extra = ze.getLocalFileDataExtra(); | |||
out.write((new ZipShort(extra.length)).getBytes()); | |||
written += 2; | |||
// file name | |||
out.write(name); | |||
written += name.length; | |||
// extra field | |||
out.write(extra); | |||
written += extra.length; | |||
dataStart = written; | |||
} | |||
/** | |||
* Writes the data descriptor entry | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected void writeDataDescriptor(ZipEntry ze) throws IOException { | |||
if (ze.getMethod() != DEFLATED) { | |||
return; | |||
} | |||
out.write(DD_SIG.getBytes()); | |||
out.write((new ZipLong(entry.getCrc())).getBytes()); | |||
out.write((new ZipLong(entry.getCompressedSize())).getBytes()); | |||
out.write((new ZipLong(entry.getSize())).getBytes()); | |||
written += 16; | |||
} | |||
/** | |||
* Writes the central file header entry | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected void writeCentralFileHeader(ZipEntry ze) throws IOException { | |||
out.write(CFH_SIG.getBytes()); | |||
written += 4; | |||
// version made by | |||
out.write((new ZipShort(20)).getBytes()); | |||
written += 2; | |||
// version needed to extract | |||
// general purpose bit flag | |||
if (ze.getMethod() == DEFLATED) { | |||
// requires version 2 as we are going to store length info | |||
// in the data descriptor | |||
out.write((new ZipShort(20)).getBytes()); | |||
// bit3 set to signal, we use a data descriptor | |||
out.write((new ZipShort(8)).getBytes()); | |||
} else { | |||
out.write((new ZipShort(10)).getBytes()); | |||
out.write(ZERO); | |||
} | |||
written += 4; | |||
// compression method | |||
out.write((new ZipShort(ze.getMethod())).getBytes()); | |||
written += 2; | |||
// last mod. time and date | |||
out.write(toDosTime(new Date(ze.getTime())).getBytes()); | |||
written += 4; | |||
// CRC | |||
// compressed length | |||
// uncompressed length | |||
out.write((new ZipLong(ze.getCrc())).getBytes()); | |||
out.write((new ZipLong(ze.getCompressedSize())).getBytes()); | |||
out.write((new ZipLong(ze.getSize())).getBytes()); | |||
written += 12; | |||
// file name length | |||
byte[] name = ze.getName().getBytes(); | |||
out.write((new ZipShort(name.length)).getBytes()); | |||
written += 2; | |||
// extra field length | |||
byte[] extra = ze.getCentralDirectoryExtra(); | |||
out.write((new ZipShort(extra.length)).getBytes()); | |||
written += 2; | |||
// file comment length | |||
String comm = ze.getComment(); | |||
if (comm == null) { | |||
comm = ""; | |||
} | |||
byte[] comment = comm.getBytes(); | |||
out.write((new ZipShort(comment.length)).getBytes()); | |||
written += 2; | |||
// disk number start | |||
out.write(ZERO); | |||
written += 2; | |||
// internal file attributes | |||
out.write((new ZipShort(ze.getInternalAttributes())).getBytes()); | |||
written += 2; | |||
// external file attributes | |||
out.write((new ZipLong(ze.getExternalAttributes())).getBytes()); | |||
written += 4; | |||
// relative offset of LFH | |||
out.write(((ZipLong) offsets.get(ze)).getBytes()); | |||
written += 4; | |||
// file name | |||
out.write(name); | |||
written += name.length; | |||
// extra field | |||
out.write(extra); | |||
written += extra.length; | |||
// file comment | |||
out.write(comment); | |||
written += comment.length; | |||
} | |||
/** | |||
* Writes the "End of central dir record" | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected void writeCentralDirectoryEnd() throws IOException { | |||
out.write(EOCD_SIG.getBytes()); | |||
// disk numbers | |||
out.write(ZERO); | |||
out.write(ZERO); | |||
// number of entries | |||
byte[] num = (new ZipShort(entries.size())).getBytes(); | |||
out.write(num); | |||
out.write(num); | |||
// length and location of CD | |||
out.write(cdLength.getBytes()); | |||
out.write(cdOffset.getBytes()); | |||
// ZIP file comment | |||
byte[] data = comment.getBytes(); | |||
out.write((new ZipShort(data.length)).getBytes()); | |||
out.write(data); | |||
} | |||
/** | |||
* Smallest date/time ZIP can handle. | |||
* | |||
* @since 1.1 | |||
*/ | |||
private static final ZipLong DOS_TIME_MIN = new ZipLong(0x00002100L); | |||
/** | |||
* Convert a Date object to a DOS date/time field. | |||
* | |||
* <p>Stolen from InfoZip's <code>fileio.c</code></p> | |||
* | |||
* @since 1.1 | |||
*/ | |||
protected static ZipLong toDosTime(Date time) { | |||
int year = time.getYear() + 1900; | |||
int month = time.getMonth() + 1; | |||
if (year < 1980) { | |||
return DOS_TIME_MIN; | |||
} | |||
long value = ((year - 1980) << 25) | |||
| (month << 21) | |||
| (time.getDate() << 16) | |||
| (time.getHours() << 11) | |||
| (time.getMinutes() << 5) | |||
| (time.getSeconds() >> 1); | |||
byte[] result = new byte[4]; | |||
result[0] = (byte) ((value & 0xFF)); | |||
result[1] = (byte) ((value & 0xFF00) >> 8); | |||
result[2] = (byte) ((value & 0xFF0000) >> 16); | |||
result[3] = (byte) ((value & 0xFF000000l) >> 24); | |||
return new ZipLong(result); | |||
} | |||
} |
@@ -0,0 +1,138 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
/** | |||
* Utility class that represents a two byte integer with conversion | |||
* rules for the big endian byte order of ZIP files. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
*/ | |||
public class ZipShort implements Cloneable { | |||
private int value; | |||
/** | |||
* Create instance from a number. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipShort (int value) { | |||
this.value = value; | |||
} | |||
/** | |||
* Create instance from bytes. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipShort (byte[] bytes) { | |||
this(bytes, 0); | |||
} | |||
/** | |||
* Create instance from the two bytes starting at offset. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public ZipShort (byte[] bytes, int offset) { | |||
value = (bytes[offset+1] << 8) & 0xFF00; | |||
value += (bytes[offset] & 0xFF); | |||
} | |||
/** | |||
* Get value as two bytes in big endian byte order. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public byte[] getBytes() { | |||
byte[] result = new byte[2]; | |||
result[0] = (byte) (value & 0xFF); | |||
result[1] = (byte) ((value & 0xFF00) >> 8); | |||
return result; | |||
} | |||
/** | |||
* Get value as Java int. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public int getValue() { | |||
return value; | |||
} | |||
/** | |||
* Override to make two instances with same value equal. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public boolean equals(Object o) { | |||
if (o == null || !(o instanceof ZipShort)) { | |||
return false; | |||
} | |||
return value == ((ZipShort) o).getValue(); | |||
} | |||
/** | |||
* Override to make two instances with same value equal. | |||
* | |||
* @since 1.1 | |||
*/ | |||
public int hashCode() { | |||
return value; | |||
} | |||
}// ZipShort |
@@ -0,0 +1,178 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import junit.framework.TestCase; | |||
/** | |||
* JUnit 3 testcases for org.apache.tools.zip.AsiExtraField. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
*/ | |||
public class AsiExtraFieldTest extends TestCase implements UnixStat { | |||
public AsiExtraFieldTest(String name) { | |||
super(name); | |||
} | |||
/** | |||
* Test file mode magic. | |||
*/ | |||
public void testModes() { | |||
AsiExtraField a = new AsiExtraField(); | |||
a.setMode(0123); | |||
assertEquals("plain file", 0100123, a.getMode()); | |||
a.setDirectory(true); | |||
assertEquals("directory", 040123, a.getMode()); | |||
a.setLinkedFile("test"); | |||
assertEquals("symbolic link", 0120123, a.getMode()); | |||
} | |||
/** | |||
* Test content. | |||
*/ | |||
public void testContent() { | |||
AsiExtraField a = new AsiExtraField(); | |||
a.setMode(0123); | |||
a.setUserId(5); | |||
a.setGroupId(6); | |||
byte[] b = a.getLocalFileDataData(); | |||
// CRC manually calculated, sorry | |||
byte[] expect = {(byte)0xC6, 0x02, 0x78, (byte)0xB6, // CRC | |||
0123, (byte)0x80, // mode | |||
0, 0, 0, 0, // link length | |||
5, 0, 6, 0}; // uid, gid | |||
assertEquals("no link", expect.length, b.length); | |||
for (int i=0; i<expect.length; i++) { | |||
assertEquals("no link, byte "+i, expect[i], b[i]); | |||
} | |||
a.setLinkedFile("test"); | |||
expect = new byte[] {0x75, (byte)0x8E, 0x41, (byte)0xFD, // CRC | |||
0123, (byte)0xA0, // mode | |||
4, 0, 0, 0, // link length | |||
5, 0, 6, 0, // uid, gid | |||
(byte)'t', (byte)'e', (byte)'s', (byte)'t'}; | |||
b = a.getLocalFileDataData(); | |||
assertEquals("no link", expect.length, b.length); | |||
for (int i=0; i<expect.length; i++) { | |||
assertEquals("no link, byte "+i, expect[i], b[i]); | |||
} | |||
} | |||
/** | |||
* Test reparse | |||
*/ | |||
public void testReparse() throws Exception { | |||
// CRC manually calculated, sorry | |||
byte[] data = {(byte)0xC6, 0x02, 0x78, (byte)0xB6, // CRC | |||
0123, (byte)0x80, // mode | |||
0, 0, 0, 0, // link length | |||
5, 0, 6, 0}; // uid, gid | |||
AsiExtraField a = new AsiExtraField(); | |||
a.parseFromLocalFileData(data, 0, data.length); | |||
assertEquals("length plain file", data.length, | |||
a.getLocalFileDataLength().getValue()); | |||
assert("plain file, no link", !a.isLink()); | |||
assert("plain file, no dir", !a.isDirectory()); | |||
assertEquals("mode plain file", FILE_FLAG | 0123, a.getMode()); | |||
assertEquals("uid plain file", 5, a.getUserId()); | |||
assertEquals("gid plain file", 6, a.getGroupId()); | |||
data = new byte[] {0x75, (byte)0x8E, 0x41, (byte)0xFD, // CRC | |||
0123, (byte)0xA0, // mode | |||
4, 0, 0, 0, // link length | |||
5, 0, 6, 0, // uid, gid | |||
(byte)'t', (byte)'e', (byte)'s', (byte)'t'}; | |||
a = new AsiExtraField(); | |||
a.parseFromLocalFileData(data, 0, data.length); | |||
assertEquals("length link", data.length, | |||
a.getLocalFileDataLength().getValue()); | |||
assert("link, is link", a.isLink()); | |||
assert("link, no dir", !a.isDirectory()); | |||
assertEquals("mode link", LINK_FLAG | 0123, a.getMode()); | |||
assertEquals("uid link", 5, a.getUserId()); | |||
assertEquals("gid link", 6, a.getGroupId()); | |||
assertEquals("test", a.getLinkedFile()); | |||
data = new byte[] {(byte)0x8E, 0x01, (byte)0xBF, (byte)0x0E, // CRC | |||
0123, (byte)0x40, // mode | |||
0, 0, 0, 0, // link | |||
5, 0, 6, 0}; // uid, gid | |||
a = new AsiExtraField(); | |||
a.parseFromLocalFileData(data, 0, data.length); | |||
assertEquals("length dir", data.length, | |||
a.getLocalFileDataLength().getValue()); | |||
assert("dir, no link", !a.isLink()); | |||
assert("dir, is dir", a.isDirectory()); | |||
assertEquals("mode dir", DIR_FLAG | 0123, a.getMode()); | |||
assertEquals("uid dir", 5, a.getUserId()); | |||
assertEquals("gid dir", 6, a.getGroupId()); | |||
data = new byte[] {0, 0, 0, 0, // bad CRC | |||
0123, (byte)0x40, // mode | |||
0, 0, 0, 0, // link | |||
5, 0, 6, 0}; // uid, gid | |||
a = new AsiExtraField(); | |||
try { | |||
a.parseFromLocalFileData(data, 0, data.length); | |||
fail("should raise bad CRC exception"); | |||
} catch (Exception e) { | |||
assertEquals("bad CRC checksum 0 instead of ebf018e", | |||
e.getMessage()); | |||
} | |||
} | |||
} |
@@ -0,0 +1,151 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import junit.framework.TestCase; | |||
/** | |||
* JUnit 3 testcases for org.apache.tools.zip.ExtraFieldUtils. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
*/ | |||
public class ExtraFieldUtilsTest extends TestCase implements UnixStat { | |||
public ExtraFieldUtilsTest(String name) { | |||
super(name); | |||
} | |||
private AsiExtraField a; | |||
private UnrecognizedExtraField dummy; | |||
private byte[] data; | |||
private byte[] aLocal; | |||
public void setUp() { | |||
a = new AsiExtraField(); | |||
a.setMode(0755); | |||
a.setDirectory(true); | |||
dummy = new UnrecognizedExtraField(); | |||
dummy.setHeaderId(new ZipShort(1)); | |||
dummy.setLocalFileDataData(new byte[0]); | |||
dummy.setCentralDirectoryData(new byte[] {0}); | |||
aLocal = a.getLocalFileDataData(); | |||
byte[] dummyLocal = dummy.getLocalFileDataData(); | |||
data = new byte[4 + aLocal.length + 4 + dummyLocal.length]; | |||
System.arraycopy(a.getHeaderId().getBytes(), 0, data, 0, 2); | |||
System.arraycopy(a.getLocalFileDataLength().getBytes(), 0, data, 2, 2); | |||
System.arraycopy(aLocal, 0, data, 4, aLocal.length); | |||
System.arraycopy(dummy.getHeaderId().getBytes(), 0, data, | |||
4+aLocal.length, 2); | |||
System.arraycopy(dummy.getLocalFileDataLength().getBytes(), 0, data, | |||
4+aLocal.length+2, 2); | |||
System.arraycopy(dummyLocal, 0, data, | |||
4+aLocal.length+4, dummyLocal.length); | |||
} | |||
/** | |||
* test parser. | |||
*/ | |||
public void testParse() throws Exception { | |||
ZipExtraField[] ze = ExtraFieldUtils.parse(data); | |||
assertEquals("number of fields", 2, ze.length); | |||
assert("type field 1", ze[0] instanceof AsiExtraField); | |||
assertEquals("mode field 1", 040755, | |||
((AsiExtraField) ze[0]).getMode()); | |||
assert("type field 2", ze[1] instanceof UnrecognizedExtraField); | |||
assertEquals("data length field 2", 0, | |||
ze[1].getLocalFileDataLength().getValue()); | |||
byte[] data2 = new byte[data.length-1]; | |||
System.arraycopy(data, 0, data2, 0, data2.length); | |||
try { | |||
ExtraFieldUtils.parse(data2); | |||
fail("data should be invalid"); | |||
} catch (Exception e) { | |||
assertEquals("message", | |||
"data starting at "+(4+aLocal.length)+" is in unknown format", | |||
e.getMessage()); | |||
} | |||
} | |||
/** | |||
* Test merge methods | |||
*/ | |||
public void testMerge() { | |||
byte[] local = | |||
ExtraFieldUtils.mergeLocalFileDataData(new ZipExtraField[] {a, dummy}); | |||
assertEquals("local length", data.length, local.length); | |||
for (int i=0; i<local.length; i++) { | |||
assertEquals("local byte "+i, data[i], local[i]); | |||
} | |||
byte[] dummyCentral = dummy.getCentralDirectoryData(); | |||
byte[] data2 = new byte[4 + aLocal.length + 4 + dummyCentral.length]; | |||
System.arraycopy(data, 0, data2, 0, 4 + aLocal.length + 2); | |||
System.arraycopy(dummy.getCentralDirectoryLength().getBytes(), 0, | |||
data2, 4+aLocal.length+2, 2); | |||
System.arraycopy(dummyCentral, 0, data2, | |||
4+aLocal.length+4, dummyCentral.length); | |||
byte[] central = | |||
ExtraFieldUtils.mergeCentralDirectoryData(new ZipExtraField[] {a, dummy}); | |||
assertEquals("central length", data2.length, central.length); | |||
for (int i=0; i<central.length; i++) { | |||
assertEquals("central byte "+i, data2[i], central[i]); | |||
} | |||
} | |||
} |
@@ -0,0 +1,124 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import junit.framework.TestCase; | |||
/** | |||
* JUnit 3 testcases for org.apache.tools.zip.ZipEntry. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
*/ | |||
public class ZipEntryTest extends TestCase { | |||
public ZipEntryTest(String name) { | |||
super(name); | |||
} | |||
/** | |||
* test handling of extra fields | |||
* | |||
* @since 1.1 | |||
*/ | |||
public void testExtraFields() { | |||
AsiExtraField a = new AsiExtraField(); | |||
a.setDirectory(true); | |||
a.setMode(0755); | |||
UnrecognizedExtraField u = new UnrecognizedExtraField(); | |||
u.setHeaderId(new ZipShort(1)); | |||
u.setLocalFileDataData(new byte[0]); | |||
ZipEntry ze = new ZipEntry("test/"); | |||
ze.setExtraFields(new ZipExtraField[] {a, u}); | |||
byte[] data1 = ze.getExtra(); | |||
ZipExtraField[] result = ze.getExtraFields(); | |||
assertEquals("first pass", 2, result.length); | |||
assertSame(a, result[0]); | |||
assertSame(u, result[1]); | |||
UnrecognizedExtraField u2 = new UnrecognizedExtraField(); | |||
u2.setHeaderId(new ZipShort(1)); | |||
u2.setLocalFileDataData(new byte[] {1}); | |||
ze.addExtraField(u2); | |||
byte[] data2 = ze.getExtra(); | |||
result = ze.getExtraFields(); | |||
assertEquals("second pass", 2, result.length); | |||
assertSame(a, result[0]); | |||
assertSame(u2, result[1]); | |||
assertEquals("length second pass", data1.length+1, data2.length); | |||
UnrecognizedExtraField u3 = new UnrecognizedExtraField(); | |||
u3.setHeaderId(new ZipShort(2)); | |||
u3.setLocalFileDataData(new byte[] {1}); | |||
ze.addExtraField(u3); | |||
result = ze.getExtraFields(); | |||
assertEquals("third pass", 3, result.length); | |||
ze.removeExtraField(new ZipShort(1)); | |||
byte[] data3 = ze.getExtra(); | |||
result = ze.getExtraFields(); | |||
assertEquals("fourth pass", 2, result.length); | |||
assertSame(a, result[0]); | |||
assertSame(u3, result[1]); | |||
assertEquals("length fourth pass", data2.length, data3.length); | |||
try { | |||
ze.removeExtraField(new ZipShort(1)); | |||
fail("should be no such element"); | |||
} catch (java.util.NoSuchElementException nse) { | |||
} | |||
} | |||
} |
@@ -0,0 +1,119 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import junit.framework.TestCase; | |||
/** | |||
* JUnit 3 testcases for org.apache.tools.zip.ZipLong. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
*/ | |||
public class ZipLongTest extends TestCase { | |||
public ZipLongTest(String name) { | |||
super(name); | |||
} | |||
/** | |||
* Test conversion to bytes. | |||
*/ | |||
public void testToBytes() { | |||
ZipLong zl = new ZipLong(0x12345678); | |||
byte[] result = zl.getBytes(); | |||
assertEquals("length getBytes", 4, result.length); | |||
assertEquals("first byte getBytes", 0x78, result[0]); | |||
assertEquals("second byte getBytes", 0x56, result[1]); | |||
assertEquals("third byte getBytes", 0x34, result[2]); | |||
assertEquals("fourth byte getBytes", 0x12, result[3]); | |||
} | |||
/** | |||
* Test conversion from bytes. | |||
*/ | |||
public void testFromBytes() { | |||
byte[] val = new byte[] {0x78, 0x56, 0x34, 0x12}; | |||
ZipLong zl = new ZipLong(val); | |||
assertEquals("value from bytes", 0x12345678, zl.getValue()); | |||
} | |||
/** | |||
* Test the contract of the equals method. | |||
*/ | |||
public void testEquals() { | |||
ZipLong zl = new ZipLong(0x12345678); | |||
ZipLong zl2 = new ZipLong(0x12345678); | |||
ZipLong zl3 = new ZipLong(0x87654321); | |||
assert("reflexive", zl.equals(zl)); | |||
assert("works", zl.equals(zl2)); | |||
assert("works, part two", !zl.equals(zl3)); | |||
assert("symmetric", zl2.equals(zl)); | |||
assert("null handling", !zl.equals(null)); | |||
assert("non ZipLong handling", !zl.equals(new Integer(0x1234))); | |||
} | |||
/** | |||
* Test sign handling. | |||
*/ | |||
public void testSign() { | |||
ZipLong zl = new ZipLong(new byte[] {(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF}); | |||
assertEquals(0x00000000FFFFFFFFl, zl.getValue()); | |||
} | |||
} |
@@ -0,0 +1,117 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2001 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions 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. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.zip; | |||
import junit.framework.TestCase; | |||
/** | |||
* JUnit 3 testcases for org.apache.tools.zip.ZipShort. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
*/ | |||
public class ZipShortTest extends TestCase { | |||
public ZipShortTest(String name) { | |||
super(name); | |||
} | |||
/** | |||
* Test conversion to bytes. | |||
*/ | |||
public void testToBytes() { | |||
ZipShort zs = new ZipShort(0x1234); | |||
byte[] result = zs.getBytes(); | |||
assertEquals("length getBytes", 2, result.length); | |||
assertEquals("first byte getBytes", 0x34, result[0]); | |||
assertEquals("second byte getBytes", 0x12, result[1]); | |||
} | |||
/** | |||
* Test conversion from bytes. | |||
*/ | |||
public void testFromBytes() { | |||
byte[] val = new byte[] {0x34, 0x12}; | |||
ZipShort zs = new ZipShort(val); | |||
assertEquals("value from bytes", 0x1234, zs.getValue()); | |||
} | |||
/** | |||
* Test the contract of the equals method. | |||
*/ | |||
public void testEquals() { | |||
ZipShort zs = new ZipShort(0x1234); | |||
ZipShort zs2 = new ZipShort(0x1234); | |||
ZipShort zs3 = new ZipShort(0x5678); | |||
assert("reflexive", zs.equals(zs)); | |||
assert("works", zs.equals(zs2)); | |||
assert("works, part two", !zs.equals(zs3)); | |||
assert("symmetric", zs2.equals(zs)); | |||
assert("null handling", !zs.equals(null)); | |||
assert("non ZipShort handling", !zs.equals(new Integer(0x1234))); | |||
} | |||
/** | |||
* Test sign handling. | |||
*/ | |||
public void testSign() { | |||
ZipShort zs = new ZipShort(new byte[] {(byte)0xFF, (byte)0xFF}); | |||
assertEquals(0x0000FFFF, zs.getValue()); | |||
} | |||
} |