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