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