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 | rmic to use a new compiler a lot easier but may break custom | ||||
versions of this task that rely on the old implementation. | 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: | Other changes: | ||||
-------------- | -------------- | ||||
@@ -55,10 +55,10 @@ package org.apache.tools.ant.taskdefs; | |||||
import org.apache.tools.ant.*; | import org.apache.tools.ant.*; | ||||
import org.apache.tools.ant.types.ZipFileSet; | import org.apache.tools.ant.types.ZipFileSet; | ||||
import org.apache.tools.zip.*; | |||||
import java.io.*; | import java.io.*; | ||||
import java.util.Vector; | import java.util.Vector; | ||||
import java.util.zip.*; | |||||
/** | /** | ||||
* Creates a EAR archive. Based on WAR task | * 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.*; | ||||
import org.apache.tools.ant.types.ZipFileSet; | import org.apache.tools.ant.types.ZipFileSet; | ||||
import org.apache.tools.zip.*; | |||||
import java.io.*; | import java.io.*; | ||||
import java.util.zip.*; | |||||
/** | /** | ||||
* Creates a JAR archive. | * Creates a JAR archive. | ||||
@@ -56,10 +56,10 @@ package org.apache.tools.ant.taskdefs; | |||||
import org.apache.tools.ant.*; | import org.apache.tools.ant.*; | ||||
import org.apache.tools.ant.types.ZipFileSet; | import org.apache.tools.ant.types.ZipFileSet; | ||||
import org.apache.tools.zip.*; | |||||
import java.io.*; | import java.io.*; | ||||
import java.util.Vector; | import java.util.Vector; | ||||
import java.util.zip.*; | |||||
/** | /** | ||||
* Creates a WAR archive. | * Creates a WAR archive. | ||||
@@ -59,10 +59,12 @@ import java.util.Hashtable; | |||||
import java.util.Stack; | import java.util.Stack; | ||||
import java.util.StringTokenizer; | import java.util.StringTokenizer; | ||||
import java.util.Vector; | 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.*; | ||||
import org.apache.tools.ant.types.*; | import org.apache.tools.ant.types.*; | ||||
import org.apache.tools.ant.util.*; | import org.apache.tools.ant.util.*; | ||||
import org.apache.tools.zip.*; | |||||
/** | /** | ||||
* Create a ZIP archive. | * Create a ZIP archive. | ||||
@@ -280,7 +282,7 @@ public class Zip extends MatchingTask { | |||||
try { | try { | ||||
in = new ZipInputStream(new FileInputStream(zipSrc)); | in = new ZipInputStream(new FileInputStream(zipSrc)); | ||||
while ((entry = in.getNextEntry()) != null) { | |||||
while ((entry = new ZipEntry(in.getNextEntry())) != null) { | |||||
String vPath = entry.getName(); | String vPath = entry.getName(); | ||||
if (zipScanner.match(vPath)) { | if (zipScanner.match(vPath)) { | ||||
addParentDirs(null, vPath, zOut, prefix); | addParentDirs(null, vPath, zOut, prefix); | ||||
@@ -414,6 +416,10 @@ public class Zip extends MatchingTask { | |||||
ze.setMethod (ZipEntry.STORED); | ze.setMethod (ZipEntry.STORED); | ||||
// This is faintly ridiculous: | // This is faintly ridiculous: | ||||
ze.setCrc (emptyCrc); | ze.setCrc (emptyCrc); | ||||
// this is 040775 | MS-DOS directory flag in reverse byte order | |||||
ze.setExternalAttributes(0x41FD0010L); | |||||
zOut.putNextEntry (ze); | 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()); | |||||
} | |||||
} |