Browse Source

Reimplementation of ZipOutputStream along with a subclass of ZipEntry

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-ffa450edef68
master
Stefan Bodewig 24 years ago
parent
commit
bb58f9a943
19 changed files with 2806 additions and 5 deletions
  1. +3
    -0
      WHATSNEW
  2. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/Ear.java
  3. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/Jar.java
  4. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/War.java
  5. +8
    -2
      src/main/org/apache/tools/ant/taskdefs/Zip.java
  6. +366
    -0
      src/main/org/apache/tools/zip/AsiExtraField.java
  7. +203
    -0
      src/main/org/apache/tools/zip/ExtraFieldUtils.java
  8. +113
    -0
      src/main/org/apache/tools/zip/UnixStat.java
  9. +131
    -0
      src/main/org/apache/tools/zip/UnrecognizedExtraField.java
  10. +272
    -0
      src/main/org/apache/tools/zip/ZipEntry.java
  11. +119
    -0
      src/main/org/apache/tools/zip/ZipExtraField.java
  12. +142
    -0
      src/main/org/apache/tools/zip/ZipLong.java
  13. +619
    -0
      src/main/org/apache/tools/zip/ZipOutputStream.java
  14. +138
    -0
      src/main/org/apache/tools/zip/ZipShort.java
  15. +178
    -0
      src/testcases/org/apache/tools/zip/AsiExtraFieldTest.java
  16. +151
    -0
      src/testcases/org/apache/tools/zip/ExtraFieldUtilsTest.java
  17. +124
    -0
      src/testcases/org/apache/tools/zip/ZipEntryTest.java
  18. +119
    -0
      src/testcases/org/apache/tools/zip/ZipLongTest.java
  19. +117
    -0
      src/testcases/org/apache/tools/zip/ZipShortTest.java

+ 3
- 0
WHATSNEW View File

@@ -10,6 +10,9 @@ Changes that could break older environments:
rmic to use a new compiler a lot easier but may break custom
versions of this task that rely on the old implementation.

* several Zip methods have changed their signature as we now use a Zip
package of our own that handles Unix permissions for directories.

Other changes:
--------------



+ 1
- 1
src/main/org/apache/tools/ant/taskdefs/Ear.java View File

@@ -55,10 +55,10 @@ package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.*;
import org.apache.tools.ant.types.ZipFileSet;
import org.apache.tools.zip.*;

import java.io.*;
import java.util.Vector;
import java.util.zip.*;

/**
* Creates a EAR archive. Based on WAR task


+ 1
- 1
src/main/org/apache/tools/ant/taskdefs/Jar.java View File

@@ -56,9 +56,9 @@ package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.*;
import org.apache.tools.ant.types.ZipFileSet;
import org.apache.tools.zip.*;

import java.io.*;
import java.util.zip.*;

/**
* Creates a JAR archive.


+ 1
- 1
src/main/org/apache/tools/ant/taskdefs/War.java View File

@@ -56,10 +56,10 @@ package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.*;
import org.apache.tools.ant.types.ZipFileSet;
import org.apache.tools.zip.*;

import java.io.*;
import java.util.Vector;
import java.util.zip.*;

/**
* Creates a WAR archive.


+ 8
- 2
src/main/org/apache/tools/ant/taskdefs/Zip.java View File

@@ -59,10 +59,12 @@ import java.util.Hashtable;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.zip.*;
import java.util.zip.CRC32;
import java.util.zip.ZipInputStream;
import org.apache.tools.ant.*;
import org.apache.tools.ant.types.*;
import org.apache.tools.ant.util.*;
import org.apache.tools.zip.*;

/**
* Create a ZIP archive.
@@ -280,7 +282,7 @@ public class Zip extends MatchingTask {
try {
in = new ZipInputStream(new FileInputStream(zipSrc));

while ((entry = in.getNextEntry()) != null) {
while ((entry = new ZipEntry(in.getNextEntry())) != null) {
String vPath = entry.getName();
if (zipScanner.match(vPath)) {
addParentDirs(null, vPath, zOut, prefix);
@@ -414,6 +416,10 @@ public class Zip extends MatchingTask {
ze.setMethod (ZipEntry.STORED);
// This is faintly ridiculous:
ze.setCrc (emptyCrc);

// this is 040775 | MS-DOS directory flag in reverse byte order
ze.setExternalAttributes(0x41FD0010L);

zOut.putNextEntry (ze);
}



+ 366
- 0
src/main/org/apache/tools/zip/AsiExtraField.java View File

@@ -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);
}
}

+ 203
- 0
src/main/org/apache/tools/zip/ExtraFieldUtils.java View File

@@ -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;
}
}

+ 113
- 0
src/main/org/apache/tools/zip/UnixStat.java View File

@@ -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;
}

+ 131
- 0
src/main/org/apache/tools/zip/UnrecognizedExtraField.java View File

@@ -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);
}
}

+ 272
- 0
src/main/org/apache/tools/zip/ZipEntry.java View File

@@ -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());
}
}

+ 119
- 0
src/main/org/apache/tools/zip/ZipExtraField.java View File

@@ -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;
}

+ 142
- 0
src/main/org/apache/tools/zip/ZipLong.java View File

@@ -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

+ 619
- 0
src/main/org/apache/tools/zip/ZipOutputStream.java View File

@@ -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 &quot;End of central dir record&quot;
*
* @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);
}

}

+ 138
- 0
src/main/org/apache/tools/zip/ZipShort.java View File

@@ -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

+ 178
- 0
src/testcases/org/apache/tools/zip/AsiExtraFieldTest.java View File

@@ -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());
}
}
}

+ 151
- 0
src/testcases/org/apache/tools/zip/ExtraFieldUtilsTest.java View File

@@ -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]);
}
}
}

+ 124
- 0
src/testcases/org/apache/tools/zip/ZipEntryTest.java View File

@@ -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) {
}
}
}

+ 119
- 0
src/testcases/org/apache/tools/zip/ZipLongTest.java View File

@@ -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());
}

}

+ 117
- 0
src/testcases/org/apache/tools/zip/ZipShortTest.java View File

@@ -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());
}

}

Loading…
Cancel
Save