summaryrefslogtreecommitdiffstats
path: root/archive/src
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
commitadc854b798c1cfe3bfd4c27d68d5cee38ca617da (patch)
tree6aed8b4923ca428942cbaa7e848d50237a3d31e0 /archive/src
parent1c0fed63c71ddb230f3b304aac12caffbedf2f21 (diff)
downloadlibcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.zip
libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.gz
libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'archive/src')
-rw-r--r--archive/src/main/java/java/util/jar/Attributes.java548
-rw-r--r--archive/src/main/java/java/util/jar/InitManifest.java295
-rw-r--r--archive/src/main/java/java/util/jar/JarEntry.java224
-rw-r--r--archive/src/main/java/java/util/jar/JarException.java52
-rw-r--r--archive/src/main/java/java/util/jar/JarFile.java478
-rw-r--r--archive/src/main/java/java/util/jar/JarInputStream.java232
-rw-r--r--archive/src/main/java/java/util/jar/JarOutputStream.java88
-rw-r--r--archive/src/main/java/java/util/jar/JarVerifier.java510
-rw-r--r--archive/src/main/java/java/util/jar/Manifest.java344
-rw-r--r--archive/src/main/java/java/util/jar/Pack200.java398
-rw-r--r--archive/src/main/java/java/util/jar/package.html12
-rw-r--r--archive/src/main/java/java/util/zip/Adler32.java103
-rw-r--r--archive/src/main/java/java/util/zip/CRC32.java101
-rw-r--r--archive/src/main/java/java/util/zip/CheckedInputStream.java138
-rw-r--r--archive/src/main/java/java/util/zip/CheckedOutputStream.java98
-rw-r--r--archive/src/main/java/java/util/zip/Checksum.java65
-rw-r--r--archive/src/main/java/java/util/zip/DataFormatException.java50
-rw-r--r--archive/src/main/java/java/util/zip/Deflater.java533
-rw-r--r--archive/src/main/java/java/util/zip/DeflaterOutputStream.java208
-rw-r--r--archive/src/main/java/java/util/zip/GZIPInputStream.java224
-rw-r--r--archive/src/main/java/java/util/zip/GZIPOutputStream.java111
-rw-r--r--archive/src/main/java/java/util/zip/Inflater.java470
-rw-r--r--archive/src/main/java/java/util/zip/InflaterInputStream.java353
-rw-r--r--archive/src/main/java/java/util/zip/ZipConstants.java34
-rw-r--r--archive/src/main/java/java/util/zip/ZipEntry.java781
-rw-r--r--archive/src/main/java/java/util/zip/ZipException.java56
-rw-r--r--archive/src/main/java/java/util/zip/ZipFile.java433
-rw-r--r--archive/src/main/java/java/util/zip/ZipInputStream.java414
-rw-r--r--archive/src/main/java/java/util/zip/ZipOutputStream.java456
-rw-r--r--archive/src/main/java/java/util/zip/package.html9
-rw-r--r--archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java147
-rw-r--r--archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties67
-rw-r--r--archive/src/main/java/org/apache/harmony/archive/util/Util.java68
-rw-r--r--archive/src/main/native/hy2sie.h114
-rw-r--r--archive/src/main/native/hycomp.h1
-rw-r--r--archive/src/main/native/hymutex.h44
-rw-r--r--archive/src/main/native/hyport.h1
-rw-r--r--archive/src/main/native/java_util_zip_Adler32.c63
-rw-r--r--archive/src/main/native/java_util_zip_CRC32.c58
-rw-r--r--archive/src/main/native/java_util_zip_Deflater.c312
-rw-r--r--archive/src/main/native/java_util_zip_Inflater.c356
-rw-r--r--archive/src/main/native/sieb.c54
-rw-r--r--archive/src/main/native/sieb.h22
-rw-r--r--archive/src/main/native/sub.mk23
-rw-r--r--archive/src/main/native/zipalloc.c64
-rw-r--r--archive/src/main/native/zipsup.c2319
-rw-r--r--archive/src/main/native/zipsup.h250
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AllTests.java50
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesNameTest.java104
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java520
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/DalvikExecTest.java315
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java259
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarExceptionTest.java64
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarExecTest.java317
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java929
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarInputStreamTest.java653
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java209
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java513
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200PackerTest.java190
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200Test.java110
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200UnpackerTest.java239
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ZipExecTest.java324
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/Adler32Test.java224
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/AllTests.java55
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CRC32Test.java242
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CheckedInputStreamTest.java202
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CheckedOutputStreamTest.java191
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DataFormatExceptionTest.java53
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterOutputStreamTest.java461
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterTest.java1243
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java322
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java238
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterInputStreamTest.java514
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java1132
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipEntryTest.java646
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipExceptionTest.java53
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java515
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipInputStreamTest.java419
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java371
-rw-r--r--archive/src/test/java/tests/archive/AllTests.java39
80 files changed, 23497 insertions, 0 deletions
diff --git a/archive/src/main/java/java/util/jar/Attributes.java b/archive/src/main/java/java/util/jar/Attributes.java
new file mode 100644
index 0000000..5a4d923
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/Attributes.java
@@ -0,0 +1,548 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.jar;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.harmony.archive.util.Util;
+
+/**
+ * The {@code Attributes} class is used to store values for manifest entries.
+ * Attribute keys are generally instances of {@code Attributes.Name}. Values
+ * associated with attribute keys are of type {@code String}.
+ * @since Android 1.0
+ */
+public class Attributes implements Cloneable, Map<Object, Object> {
+
+ /**
+ * The {@code Attributes} as name/value pairs. Maps the attribute names (as
+ * {@link Attributes.Name}) of a JAR file manifest to arbitrary values. The
+ * attribute names thus are obtained from the {@link Manifest} for
+ * convenience.
+ *
+ * @since Android 1.0
+ */
+ protected Map<Object, Object> map;
+
+ /**
+ * The name part of the name/value pairs constituting an attribute as
+ * defined by the specification of the JAR manifest. May be composed of the
+ * following ASCII signs as defined in the EBNF below:
+ *
+ * <pre>
+ * name = alphanum *headerchar
+ * headerchar = alphanum | - | _
+ * alphanum = {A-Z} | {a-z} | {0-9}
+ * </pre>
+ *
+ * @since Android 1.0
+ */
+ public static class Name {
+ private final String name;
+
+ private int hashCode;
+
+ /**
+ * The class path (a main attribute).
+ *
+ * @since Android 1.0
+ */
+ public static final Name CLASS_PATH = new Name("Class-Path"); //$NON-NLS-1$
+
+ /**
+ * The version of the manifest file (a main attribute).
+ *
+ * @since Android 1.0
+ */
+ public static final Name MANIFEST_VERSION = new Name(
+ "Manifest-Version"); //$NON-NLS-1$
+
+ /**
+ * The main class's name (for stand-alone applications).
+ *
+ * @since Android 1.0
+ */
+ public static final Name MAIN_CLASS = new Name("Main-Class"); //$NON-NLS-1$
+
+ /**
+ * Defines the signature version of the JAR file.
+ *
+ * @since Android 1.0
+ */
+ public static final Name SIGNATURE_VERSION = new Name(
+ "Signature-Version"); //$NON-NLS-1$
+
+ /**
+ * The {@code Content-Type} manifest attribute.
+ */
+ public static final Name CONTENT_TYPE = new Name("Content-Type"); //$NON-NLS-1$
+
+ /**
+ * The {@code Sealed} manifest attribute which may have the value
+ * {@code true} for sealed archives.
+ *
+ * @since Android 1.0
+ */
+ public static final Name SEALED = new Name("Sealed"); //$NON-NLS-1$
+
+ /**
+ * The {@code Implementation-Title} attribute whose value is a string
+ * that defines the title of the extension implementation.
+ *
+ * @since Android 1.0
+ */
+ public static final Name IMPLEMENTATION_TITLE = new Name(
+ "Implementation-Title"); //$NON-NLS-1$
+
+ /**
+ * The {@code Implementation-Version} attribute defining the version of
+ * the extension implementation.
+ *
+ * @since Android 1.0
+ */
+ public static final Name IMPLEMENTATION_VERSION = new Name(
+ "Implementation-Version"); //$NON-NLS-1$
+
+ /**
+ * The {@code Implementation-Vendor} attribute defining the organization
+ * that maintains the extension implementation.
+ *
+ * @since Android 1.0
+ */
+ public static final Name IMPLEMENTATION_VENDOR = new Name(
+ "Implementation-Vendor"); //$NON-NLS-1$
+
+ /**
+ * The {@code Specification-Title} attribute defining the title of the
+ * extension specification.
+ *
+ * @since Android 1.0
+ */
+ public static final Name SPECIFICATION_TITLE = new Name(
+ "Specification-Title"); //$NON-NLS-1$
+
+ /**
+ * The {@code Specification-Version} attribute defining the version of
+ * the extension specification.
+ *
+ * @since Android 1.0
+ */
+ public static final Name SPECIFICATION_VERSION = new Name(
+ "Specification-Version"); //$NON-NLS-1$
+
+ /**
+ * The {@code Specification-Vendor} attribute defining the organization
+ * that maintains the extension specification.
+ *
+ * @since Android 1.0
+ */
+ public static final Name SPECIFICATION_VENDOR = new Name(
+ "Specification-Vendor"); //$NON-NLS-1$
+
+ /**
+ * The {@code Extension-List} attribute defining the extensions that are
+ * needed by the applet.
+ *
+ * @since Android 1.0
+ */
+ public static final Name EXTENSION_LIST = new Name("Extension-List"); //$NON-NLS-1$
+
+ /**
+ * The {@code Extension-Name} attribute which defines the unique name of
+ * the extension.
+ *
+ * @since Android 1.0
+ */
+ public static final Name EXTENSION_NAME = new Name("Extension-Name"); //$NON-NLS-1$
+
+ /**
+ * The {@code Extension-Installation} attribute.
+ *
+ * @since Android 1.0
+ */
+ public static final Name EXTENSION_INSTALLATION = new Name(
+ "Extension-Installation"); //$NON-NLS-1$
+
+ /**
+ * The {@code Implementation-Vendor-Id} attribute specifies the vendor
+ * of an extension implementation if the applet requires an
+ * implementation from a specific vendor.
+ *
+ * @since Android 1.0
+ */
+ public static final Name IMPLEMENTATION_VENDOR_ID = new Name(
+ "Implementation-Vendor-Id"); //$NON-NLS-1$
+
+ /**
+ * The {@code Implementation-URL} attribute specifying a URL that can be
+ * used to obtain the most recent version of the extension if the
+ * required version is not already installed.
+ *
+ * @since Android 1.0
+ */
+ public static final Name IMPLEMENTATION_URL = new Name(
+ "Implementation-URL"); //$NON-NLS-1$
+
+ /**
+ * A String which must satisfy the following EBNF grammar to specify an
+ * additional attribute:
+ *
+ * <pre>
+ * name = alphanum *headerchar
+ * headerchar = alphanum | - | _
+ * alphanum = {A-Z} | {a-z} | {0-9}
+ * </pre>
+ *
+ * @param s
+ * The Attribute string.
+ * @exception IllegalArgumentException
+ * if the string does not satisfy the EBNF grammar.
+ * @since Android 1.0
+ */
+ public Name(String s) {
+ int i = s.length();
+ if (i == 0 || i > 70) {
+ throw new IllegalArgumentException();
+ }
+ for (; --i >= 0;) {
+ char ch = s.charAt(i);
+ if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
+ || ch == '_' || ch == '-' || (ch >= '0' && ch <= '9'))) {
+ throw new IllegalArgumentException(s);
+ }
+ }
+ name = s;
+ }
+
+ /**
+ * Returns this attribute name.
+ *
+ * @return the attribute name.
+ * @since Android 1.0
+ */
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ /**
+ * returns whether the argument provided is the same as the attribute
+ * name.
+ *
+ * @return if the attribute names correspond.
+ * @param an
+ * An attribute name to be compared with this name.
+ * @since Android 1.0
+ */
+ @Override
+ public boolean equals(Object an) {
+ if (an == null) {
+ return false;
+ }
+ return an.getClass() == this.getClass()
+ && name.equalsIgnoreCase(((Name) an).name);
+ }
+
+ /**
+ * Computes a hash code of the name.
+ *
+ * @return the hash value computed from the name.
+ * @since Android 1.0
+ */
+ @Override
+ public int hashCode() {
+ if (hashCode == 0) {
+ hashCode = Util.toASCIILowerCase("name").hashCode();
+ }
+ return hashCode;
+ }
+ }
+
+ /**
+ * Constructs an {@code Attributes} instance.
+ *
+ * @since Android 1.0
+ */
+ public Attributes() {
+ map = new HashMap<Object, Object>();
+ }
+
+ /**
+ * Constructs an {@code Attributes} instance obtaining keys and values from
+ * the parameter {@code attrib}.
+ *
+ * @param attrib
+ * The attributes to obtain entries from.
+ * @since Android 1.0
+ */
+ @SuppressWarnings("unchecked")
+ public Attributes(Attributes attrib) {
+ map = (Map<Object, Object>)((HashMap) attrib.map).clone();
+ }
+
+ /**
+ * Constructs an {@code Attributes} instance with initial capacity of size
+ * {@code size}.
+ *
+ * @param size
+ * Initial size of this {@code Attributes} instance.
+ * @since Android 1.0
+ */
+ public Attributes(int size) {
+ map = new HashMap<Object, Object>(size);
+ }
+
+ /**
+ * Removes all key/value pairs from this {@code Attributes}.
+ *
+ * @since Android 1.0
+ */
+ public void clear() {
+ map.clear();
+ }
+
+ /**
+ * Determines whether this {@code Attributes} contains the specified key.
+ *
+ * @param key
+ * The key to search for.
+ * @return {@code true} if the key is found, {@code false} otherwise.
+ * @since Android 1.0
+ */
+ public boolean containsKey(Object key) {
+ return map.containsKey(key);
+ }
+
+ /**
+ * Determines whether this {@code Attributes} contains the specified value.
+ *
+ * @param value
+ * the value to search for.
+ * @return {@code true} if the value is found, {@code false} otherwise.
+ * @since Android 1.0
+ */
+ public boolean containsValue(Object value) {
+ return map.containsValue(value);
+ }
+
+ /**
+ * Returns a set containing map entries for each of the key/value pair
+ * contained in this {@code Attributes}.
+ *
+ * @return a set of Map.Entry's
+ * @since Android 1.0
+ */
+ public Set<Map.Entry<Object, Object>> entrySet() {
+ return map.entrySet();
+ }
+
+ /**
+ * Returns the value associated with the parameter key.
+ *
+ * @param key
+ * the key to search for.
+ * @return Object associated with key, or {@code null} if key does not
+ * exist.
+ * @since Android 1.0
+ */
+ public Object get(Object key) {
+ return map.get(key);
+ }
+
+ /**
+ * Determines whether this {@code Attributes} contains any keys.
+ *
+ * @return {@code true} if one or more keys exist, {@code false} otherwise.
+ * @since Android 1.0
+ */
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * Returns a {@code Set} containing all the keys found in this {@code
+ * Attributes}.
+ *
+ * @return a {@code Set} of all keys.
+ * @since Android 1.0
+ */
+ public Set<Object> keySet() {
+ return map.keySet();
+ }
+
+ /**
+ * Stores key/value pairs in this {@code Attributes}.
+ *
+ * @param key
+ * the key to associate with value.
+ * @param value
+ * the value to store in this {@code Attributes}.
+ * @return the value being stored.
+ * @exception ClassCastException
+ * when key is not an {@code Attributes.Name} or value is not
+ * a {@code String}.
+ *@since Android 1.0
+ */
+ @SuppressWarnings("cast") // Require cast to force ClassCastException
+ public Object put(Object key, Object value) {
+ return map.put((Name)key, (String)value);
+ }
+
+ /**
+ * Stores all the key/value pairs in the argument in this {@code Attributes}
+ * .
+ *
+ * @param attrib
+ * the associations to store (must be of type {@code Attributes}
+ * ).
+ * @since Android 1.0
+ */
+ public void putAll(Map<?, ?> attrib) {
+ if (attrib == null || !(attrib instanceof Attributes)) {
+ throw new ClassCastException();
+ }
+ this.map.putAll(attrib);
+ }
+
+ /**
+ * Deletes the key/value pair with key {@code key} from this {@code
+ * Attributes}.
+ *
+ * @param key
+ * the key to remove.
+ * @return the values associated with the removed key, {@code null} if not
+ * present.
+ * @since Android 1.0
+ */
+ public Object remove(Object key) {
+ return map.remove(key);
+ }
+
+ /**
+ * Returns the number of key/value pairs associated with this {@code
+ * Attributes}.
+ *
+ * @return the size of this {@code Attributes}.
+ * @since Android 1.0
+ */
+ public int size() {
+ return map.size();
+ }
+
+ /**
+ * Returns a collection of all the values present in this {@code Attributes}
+ * .
+ *
+ * @return a collection of all values present.
+ * @since Android 1.0
+ */
+ public Collection<Object> values() {
+ return map.values();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object clone() {
+ Attributes clone;
+ try {
+ clone = (Attributes) super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ clone.map = (Map<Object, Object>) ((HashMap) map).clone();
+ return clone;
+ }
+
+ /**
+ * Returns the hash code of this {@code Attributes}.
+ *
+ * @return the hash code of this object.
+ * @since Android 1.0
+ */
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+
+ /**
+ * Determines if this {@code Attributes} and the parameter {@code
+ * Attributes} are equal. Two {@code Attributes} instances are equal if they
+ * contain the same keys and values.
+ *
+ * @param obj
+ * the object with which this {@code Attributes} is compared.
+ * @return {@code true} if the {@code Attributes} are equal, {@code false}
+ * otherwise.
+ * @since Android 1.0
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof Attributes) {
+ return map.equals(((Attributes) obj).map);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the value associated with the parameter {@code Attributes.Name}
+ * key.
+ *
+ * @param name
+ * the key to obtain the value for.
+ * @return the {@code String} associated with name, or {@code null} if name
+ * is not a valid key.
+ * @since Android 1.0
+ */
+ public String getValue(Attributes.Name name) {
+ return (String) map.get(name);
+ }
+
+ /**
+ * Returns the string associated with the parameter name.
+ *
+ * @param name
+ * the key to obtain the value for.
+ * @return the string associated with name, or {@code null} if name is not a
+ * valid key.
+ * @since Android 1.0
+ */
+ public String getValue(String name) {
+ return (String) map.get(new Attributes.Name(name));
+ }
+
+ /**
+ * Stores the value {@code val} associated with the key {@code name} in this
+ * {@code Attributes}.
+ *
+ * @param name
+ * the key to store.
+ * @param val
+ * the value to store in this {@code Attributes}.
+ * @return the value being stored.
+ * @since Android 1.0
+ */
+ public String putValue(String name, String val) {
+ return (String) map.put(new Attributes.Name(name), val);
+ }
+}
diff --git a/archive/src/main/java/java/util/jar/InitManifest.java b/archive/src/main/java/java/util/jar/InitManifest.java
new file mode 100644
index 0000000..47fdf1c
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/InitManifest.java
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.jar;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UTFDataFormatException;
+import java.security.AccessController;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.harmony.archive.internal.nls.Messages;
+import org.apache.harmony.luni.util.PriviAction;
+import org.apache.harmony.luni.util.Util;
+
+class InitManifest {
+ private final byte[] inbuf = new byte[1024];
+
+ private int inbufCount = 0, inbufPos = 0;
+
+ private byte[] buffer = new byte[5];
+
+ private char[] charbuf = new char[0];
+
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream(256);
+
+ private String encoding;
+
+ private boolean usingUTF8 = true;
+
+ private final Map<String, Attributes.Name> attributeNames = new HashMap<String, Attributes.Name>();
+
+ private final byte[] mainAttributesChunk;
+
+ InitManifest(InputStream is, Attributes main, Map<String, Attributes> entries, Map<String, byte[]> chunks,
+ String verString) throws IOException {
+ encoding = AccessController.doPrivileged(new PriviAction<String>(
+ "manifest.read.encoding")); //$NON-NLS-1$
+ if ("".equals(encoding)) { //$NON-NLS-1$
+ encoding = null;
+ }
+
+ Attributes current = main;
+ ArrayList<String> list = new ArrayList<String>();
+
+ // Return the chunk of main attributes in the manifest.
+ mainAttributesChunk = nextChunk(is, list);
+
+ Iterator<String> it = list.iterator();
+ while (it.hasNext()) {
+ addAttribute(it.next(), current);
+ }
+
+ // Check for version attribute
+ if (verString != null && main.getValue(verString) == null) {
+ throw new IOException(Messages.getString("archive.2D", verString)); //$NON-NLS-1$
+ }
+
+ list.clear();
+ byte[] chunk = null;
+ while (chunks == null ? readLines(is, list) : (chunk = nextChunk(is,
+ list)) != null) {
+ it = list.iterator();
+ String line = it.next();
+ if (line.length() < 7
+ || !Util.toASCIILowerCase(line.substring(0, 5)).equals("name:")) { //$NON-NLS-1$
+ throw new IOException(Messages.getString("archive.23")); //$NON-NLS-1$
+ }
+ // Name: length required space char
+ String name = line.substring(6, line.length());
+ current = new Attributes(12);
+ if (chunks != null) {
+ chunks.put(name, chunk);
+ }
+ entries.put(name, current);
+ while (it.hasNext()) {
+ addAttribute(it.next(), current);
+ }
+ list.clear();
+ }
+
+ }
+
+ byte[] getMainAttributesChunk() {
+ return mainAttributesChunk;
+ }
+
+ private void addLine(int length, List<String> lines) throws IOException {
+ if (encoding != null) {
+ lines.add(new String(buffer, 0, length, encoding));
+ } else {
+ if (usingUTF8) {
+ try {
+ if (charbuf.length < length) {
+ charbuf = new char[length];
+ }
+ lines.add(Util.convertUTF8WithBuf(buffer, charbuf, 0,
+ length));
+ } catch (UTFDataFormatException e) {
+ usingUTF8 = false;
+ }
+ }
+ if (!usingUTF8) {
+ if (charbuf.length < length) {
+ charbuf = new char[length];
+ }
+ // If invalid UTF8, convert bytes to chars setting the upper
+ // bytes to zeros
+ int charOffset = 0;
+ int offset = 0;
+ for (int i = length; --i >= 0;) {
+ charbuf[charOffset++] = (char) (buffer[offset++] & 0xff);
+ }
+ lines.add(new String(charbuf, 0, length));
+ }
+ }
+ }
+
+ private byte[] nextChunk(InputStream in, List<String> lines)
+ throws IOException {
+ if (inbufCount == -1) {
+ return null;
+ }
+ byte next;
+ int pos = 0;
+ boolean blankline = false, lastCr = false;
+ out.reset();
+ while (true) {
+ if (inbufPos == inbufCount) {
+ if ((inbufCount = in.read(inbuf)) == -1) {
+ if (out.size() == 0) {
+ return null;
+ }
+ if (blankline) {
+ addLine(pos, lines);
+ }
+ return out.toByteArray();
+ }
+ if (inbufCount == inbuf.length && in.available() == 0) {
+ /* archive.2E = "line too long" */
+ throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
+ }
+ inbufPos = 0;
+ }
+ next = inbuf[inbufPos++];
+ if (lastCr) {
+ if (next != '\n') {
+ inbufPos--;
+ next = '\r';
+ } else {
+ if (out.size() == 0) {
+ continue;
+ }
+ out.write('\r');
+ }
+ lastCr = false;
+ } else if (next == '\r') {
+ lastCr = true;
+ continue;
+ }
+ if (blankline) {
+ if (next == ' ') {
+ out.write(next);
+ blankline = false;
+ continue;
+ }
+ addLine(pos, lines);
+ if (next == '\n') {
+ out.write(next);
+ return out.toByteArray();
+ }
+ pos = 0;
+ } else if (next == '\n') {
+ if (out.size() == 0) {
+ continue;
+ }
+ out.write(next);
+ blankline = true;
+ continue;
+ }
+ blankline = false;
+ out.write(next);
+ if (pos == buffer.length) {
+ byte[] newBuf = new byte[buffer.length * 2];
+ System.arraycopy(buffer, 0, newBuf, 0, buffer.length);
+ buffer = newBuf;
+ }
+ buffer[pos++] = next;
+ }
+ }
+
+ private boolean readLines(InputStream in, List<String> lines)
+ throws IOException {
+ if (inbufCount == -1) {
+ return false;
+ }
+ byte next;
+ int pos = 0;
+ boolean blankline = false, lastCr = false;
+ while (true) {
+ if (inbufPos == inbufCount) {
+ if ((inbufCount = in.read(inbuf)) == -1) {
+ if (blankline) {
+ addLine(pos, lines);
+ }
+ return lines.size() != 0;
+ }
+ if (inbufCount == inbuf.length && in.available() == 0) {
+ /* archive.2E = "line too long" */
+ throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
+ }
+ inbufPos = 0;
+ }
+ next = inbuf[inbufPos++];
+ if (lastCr) {
+ if (next != '\n') {
+ inbufPos--;
+ next = '\r';
+ }
+ lastCr = false;
+ } else if (next == '\r') {
+ lastCr = true;
+ continue;
+ }
+ if (blankline) {
+ if (next == ' ') {
+ blankline = false;
+ continue;
+ }
+ addLine(pos, lines);
+ if (next == '\n') {
+ return true;
+ }
+ pos = 0;
+ } else if (next == '\n') {
+ if (pos == 0 && lines.size() == 0) {
+ continue;
+ }
+ blankline = true;
+ continue;
+ }
+ blankline = false;
+ if (pos == buffer.length) {
+ byte[] newBuf = new byte[buffer.length * 2];
+ System.arraycopy(buffer, 0, newBuf, 0, buffer.length);
+ buffer = newBuf;
+ }
+ buffer[pos++] = next;
+ }
+ }
+
+ /* Get the next attribute and add it */
+ private void addAttribute(String line, Attributes current)
+ throws IOException {
+ String header;
+ int hdrIdx = line.indexOf(':');
+ if (hdrIdx < 1) {
+ throw new IOException(Messages.getString("archive.2F", line)); //$NON-NLS-1$
+ }
+ header = line.substring(0, hdrIdx);
+ Attributes.Name name = attributeNames.get(header);
+ if (name == null) {
+ try {
+ name = new Attributes.Name(header);
+ } catch (IllegalArgumentException e) {
+ throw new IOException(e.toString());
+ }
+ attributeNames.put(header, name);
+ }
+ if (hdrIdx + 1 >= line.length() || line.charAt(hdrIdx + 1) != ' ') {
+ throw new IOException(Messages.getString("archive.2F", line)); //$NON-NLS-1$
+ }
+ // +2 due to required SPACE char
+ current.put(name, line.substring(hdrIdx + 2, line.length()));
+ }
+}
diff --git a/archive/src/main/java/java/util/jar/JarEntry.java b/archive/src/main/java/java/util/jar/JarEntry.java
new file mode 100644
index 0000000..b8dabee
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/JarEntry.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.jar;
+
+import java.io.IOException;
+import java.security.CodeSigner;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Represents a single file in a JAR archive together with the manifest
+ * attributes and digital signatures associated with it.
+ *
+ * @since Android 1.0
+ */
+public class JarEntry extends ZipEntry {
+ private Attributes attributes;
+
+ JarFile parentJar;
+
+ CodeSigner signers[];
+
+ // Cached factory used to build CertPath-s in <code>getCodeSigners()</code>.
+ private CertificateFactory factory;
+
+ private boolean isFactoryChecked = false;
+
+ /**
+ * Creates a new {@code JarEntry} named name.
+ *
+ * @param name
+ * The name of the new {@code JarEntry}.
+ * @since Android 1.0
+ */
+ public JarEntry(String name) {
+ super(name);
+ }
+
+ /**
+ * Creates a new {@code JarEntry} using the values obtained from entry.
+ *
+ * @param entry
+ * The ZipEntry to obtain values from.
+ * @since Android 1.0
+ */
+ public JarEntry(ZipEntry entry) {
+ super(entry);
+ }
+
+ /**
+ * Returns the {@code Attributes} object associated with this entry or
+ * {@code null} if none exists.
+ *
+ * @return the {@code Attributes} for this entry.
+ * @exception IOException
+ * If an error occurs obtaining the {@code Attributes}.
+ * @see Attributes
+ * @since Android 1.0
+ */
+ public Attributes getAttributes() throws IOException {
+ if (attributes != null || parentJar == null) {
+ return attributes;
+ }
+ Manifest manifest = parentJar.getManifest();
+ if (manifest == null) {
+ return null;
+ }
+ return attributes = manifest.getAttributes(getName());
+ }
+
+ /**
+ * Returns an array of {@code Certificate} Objects associated with this
+ * entry or {@code null} if none exists. Make sure that the everything is
+ * read from the input stream before calling this method, or else the method
+ * returns {@code null}.
+ *
+ * @return the certificate for this entry.
+ * @see java.security.cert.Certificate
+ * @since Android 1.0
+ */
+ public Certificate[] getCertificates() {
+ if (null == parentJar) {
+ return null;
+ }
+ JarVerifier jarVerifier = parentJar.verifier;
+ if (null == jarVerifier) {
+ return null;
+ }
+ return jarVerifier.getCertificates(getName());
+ }
+
+ void setAttributes(Attributes attrib) {
+ attributes = attrib;
+ }
+
+ /**
+ * Create a new {@code JarEntry} using the values obtained from the
+ * argument.
+ *
+ * @param je
+ * The {@code JarEntry} to obtain values from.
+ * @since Android 1.0
+ */
+ public JarEntry(JarEntry je) {
+ super(je);
+ parentJar = je.parentJar;
+ attributes = je.attributes;
+ signers = je.signers;
+ }
+
+ /**
+ * Returns the code signers for the digital signatures associated with the
+ * JAR file. If there is no such code signer, it returns {@code null}. Make
+ * sure that the everything is read from the input stream before calling
+ * this method, or else the method returns {@code null}.
+ *
+ * @return the code signers for the JAR entry.
+ * @see CodeSigner
+ * @since Android 1.0
+ */
+ public CodeSigner[] getCodeSigners() {
+ if (null == signers) {
+ signers = getCodeSigners(getCertificates());
+ }
+ if (null == signers) {
+ return null;
+ }
+
+ CodeSigner[] tmp = new CodeSigner[signers.length];
+ System.arraycopy(signers, 0, tmp, 0, tmp.length);
+ return tmp;
+ }
+
+ private CodeSigner[] getCodeSigners(Certificate[] certs) {
+ if(null == certs) {
+ return null;
+ }
+
+ X500Principal prevIssuer = null;
+ ArrayList<Certificate> list = new ArrayList<Certificate>(certs.length);
+ ArrayList<CodeSigner> asigners = new ArrayList<CodeSigner>();
+
+ for (Certificate element : certs) {
+ if (!(element instanceof X509Certificate)) {
+ // Only X509Certificate-s are taken into account - see API spec.
+ continue;
+ }
+ X509Certificate x509 = (X509Certificate) element;
+ if (null != prevIssuer) {
+ X500Principal subj = x509.getSubjectX500Principal();
+ if (!prevIssuer.equals(subj)) {
+ // Ok, this ends the previous chain,
+ // so transform this one into CertPath ...
+ addCodeSigner(asigners, list);
+ // ... and start a new one
+ list.clear();
+ }// else { it's still the same chain }
+
+ }
+ prevIssuer = x509.getIssuerX500Principal();
+ list.add(x509);
+ }
+ if (!list.isEmpty()) {
+ addCodeSigner(asigners, list);
+ }
+ if (asigners.isEmpty()) {
+ // 'signers' is 'null' already
+ return null;
+ }
+
+ CodeSigner[] tmp = new CodeSigner[asigners.size()];
+ asigners.toArray(tmp);
+ return tmp;
+
+ }
+
+ private void addCodeSigner(ArrayList<CodeSigner> asigners,
+ List<Certificate> list) {
+ CertPath certPath = null;
+ if (!isFactoryChecked) {
+ try {
+ factory = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$
+ } catch (CertificateException ex) {
+ // do nothing
+ } finally {
+ isFactoryChecked = true;
+ }
+ }
+ if (null == factory) {
+ return;
+ }
+ try {
+ certPath = factory.generateCertPath(list);
+ } catch (CertificateException ex) {
+ // do nothing
+ }
+ if (null != certPath) {
+ asigners.add(new CodeSigner(certPath, null));
+ }
+ }
+}
diff --git a/archive/src/main/java/java/util/jar/JarException.java b/archive/src/main/java/java/util/jar/JarException.java
new file mode 100644
index 0000000..f18d639
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/JarException.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.jar;
+
+import java.util.zip.ZipException;
+
+/**
+ * This runtime exception is thrown when a problem occurs while reading a JAR
+ * file.
+ *
+ * @since Android 1.0
+ */
+public class JarException extends ZipException {
+
+ private static final long serialVersionUID = 7159778400963954473L;
+
+ /**
+ * Constructs a new {@code JarException} instance.
+ *
+ * @since Android 1.0
+ */
+ public JarException() {
+ super();
+ }
+
+ /**
+ * Constructs a new {@code JarException} instance with the specified
+ * message.
+ *
+ * @param detailMessage
+ * the detail message for the exception.
+ * @since Android 1.0
+ */
+ public JarException(String detailMessage) {
+ super(detailMessage);
+ }
+}
diff --git a/archive/src/main/java/java/util/jar/JarFile.java b/archive/src/main/java/java/util/jar/JarFile.java
new file mode 100644
index 0000000..9af9056
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/JarFile.java
@@ -0,0 +1,478 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.jar;
+
+// BEGIN android-removed
+// import java.io.ByteArrayInputStream;
+// END android-removed
+// BEGIN android-added
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+import java.util.ArrayList;
+// END android-added
+import java.io.File;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.apache.harmony.archive.util.Util;
+
+/**
+ * {@code JarFile} is used to read jar entries and their associated data from
+ * jar files.
+ *
+ * @see JarInputStream
+ * @see JarEntry
+ * @since Android 1.0
+ */
+public class JarFile extends ZipFile {
+
+ /**
+ * The MANIFEST file name.
+ *
+ * @since Android 1.0
+ */
+ public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; //$NON-NLS-1$
+
+ static final String META_DIR = "META-INF/"; //$NON-NLS-1$
+
+ private Manifest manifest;
+
+ private ZipEntry manifestEntry;
+
+ JarVerifier verifier;
+
+ // BEGIN android-added
+ private boolean closed = false;
+ // END android-added
+
+ static final class JarFileInputStream extends FilterInputStream {
+ private long count;
+
+ private ZipEntry zipEntry;
+
+ private JarVerifier verifier;
+
+ private JarVerifier.VerifierEntry entry;
+
+ private MessageDigest digest;
+
+ JarFileInputStream(InputStream is, ZipEntry ze, JarVerifier ver) {
+ super(is);
+ if (ver != null) {
+ zipEntry = ze;
+ verifier = ver;
+ count = zipEntry.getSize();
+ entry = verifier.initEntry(ze.getName());
+ if (entry != null) {
+ digest = entry.digest;
+ }
+ }
+ }
+
+ @Override
+ public int read() throws IOException {
+ int r = super.read();
+ if (entry != null) {
+ if (r != -1) {
+ digest.update((byte) r);
+ count--;
+ }
+ if (r == -1 || count <= 0) {
+ JarVerifier.VerifierEntry temp = entry;
+ entry = null;
+ verifier.verifySignatures(temp, zipEntry);
+ }
+ }
+ return r;
+ }
+
+ @Override
+ public int read(byte[] buf, int off, int nbytes) throws IOException {
+ int r = super.read(buf, off, nbytes);
+ if (entry != null) {
+ if (r != -1) {
+ int size = r;
+ if (count < size) {
+ size = (int) count;
+ }
+ digest.update(buf, off, size);
+ count -= r;
+ }
+ if (r == -1 || count <= 0) {
+ JarVerifier.VerifierEntry temp = entry;
+ entry = null;
+ verifier.verifySignatures(temp, zipEntry);
+ }
+ }
+ return r;
+ }
+
+ @Override
+ public long skip(long nbytes) throws IOException {
+ long cnt = 0, rem = 0;
+ byte[] buf = new byte[4096];
+ while (cnt < nbytes) {
+ int x = read(buf, 0,
+ (rem = nbytes - cnt) > buf.length ? buf.length
+ : (int) rem);
+ if (x == -1) {
+ return cnt;
+ }
+ cnt += x;
+ }
+ return cnt;
+ }
+ }
+
+ /**
+ * Create a new {@code JarFile} using the contents of the specified file.
+ *
+ * @param file
+ * the JAR file as {@link File}.
+ * @throws IOException
+ * If the file cannot be read.
+ * @since Android 1.0
+ */
+ public JarFile(File file) throws IOException {
+ this(file, true);
+ }
+
+ /**
+ * Create a new {@code JarFile} using the contents of the specified file.
+ *
+ * @param file
+ * the JAR file as {@link File}.
+ * @param verify
+ * if this JAR file is signed whether it must be verified.
+ * @throws IOException
+ * If the file cannot be read.
+ * @since Android 1.0
+ */
+ public JarFile(File file, boolean verify) throws IOException {
+ super(file);
+ if (verify) {
+ verifier = new JarVerifier(file.getPath());
+ }
+ readMetaEntries();
+ }
+
+ /**
+ * Create a new {@code JarFile} using the contents of file.
+ *
+ * @param file
+ * the JAR file as {@link File}.
+ * @param verify
+ * if this JAR filed is signed whether it must be verified.
+ * @param mode
+ * the mode to use, either {@link ZipFile#OPEN_READ OPEN_READ} or
+ * {@link ZipFile#OPEN_DELETE OPEN_DELETE}.
+ * @throws IOException
+ * If the file cannot be read.
+ * @since Android 1.0
+ */
+ public JarFile(File file, boolean verify, int mode) throws IOException {
+ super(file, mode);
+ if (verify) {
+ verifier = new JarVerifier(file.getPath());
+ }
+ readMetaEntries();
+ }
+
+ /**
+ * Create a new {@code JarFile} from the contents of the file specified by
+ * filename.
+ *
+ * @param filename
+ * the file name referring to the JAR file.
+ * @throws IOException
+ * if file name cannot be opened for reading.
+ * @since Android 1.0
+ */
+ public JarFile(String filename) throws IOException {
+ this(filename, true);
+
+ }
+
+ /**
+ * Create a new {@code JarFile} from the contents of the file specified by
+ * {@code filename}.
+ *
+ * @param filename
+ * the file name referring to the JAR file.
+ * @param verify
+ * if this JAR filed is signed whether it must be verified.
+ * @throws IOException
+ * If file cannot be opened or read.
+ * @since Android 1.0
+ */
+ public JarFile(String filename, boolean verify) throws IOException {
+ super(filename);
+ if (verify) {
+ verifier = new JarVerifier(filename);
+ }
+ readMetaEntries();
+ }
+
+ /**
+ * Return an enumeration containing the {@code JarEntrys} contained in this
+ * {@code JarFile}.
+ *
+ * @return the {@code Enumeration} containing the JAR entries.
+ * @throws IllegalStateException
+ * if this {@code JarFile} is closed.
+ * @since Android 1.0
+ */
+ @Override
+ public Enumeration<JarEntry> entries() {
+ class JarFileEnumerator implements Enumeration<JarEntry> {
+ Enumeration<? extends ZipEntry> ze;
+
+ JarFile jf;
+
+ JarFileEnumerator(Enumeration<? extends ZipEntry> zenum, JarFile jf) {
+ ze = zenum;
+ this.jf = jf;
+ }
+
+ public boolean hasMoreElements() {
+ return ze.hasMoreElements();
+ }
+
+ public JarEntry nextElement() {
+ JarEntry je = new JarEntry(ze.nextElement());
+ je.parentJar = jf;
+ return je;
+ }
+ }
+ return new JarFileEnumerator(super.entries(), this);
+ }
+
+ /**
+ * Return the {@code JarEntry} specified by its name or {@code null} if no
+ * such entry exists.
+ *
+ * @param name
+ * the name of the entry in the JAR file.
+ * @return the JAR entry defined by the name.
+ * @since Android 1.0
+ */
+ public JarEntry getJarEntry(String name) {
+ return (JarEntry) getEntry(name);
+ }
+
+
+ // BEGIN android-added
+ private byte[] getAllBytesFromStreamAndClose(InputStream is) throws IOException {
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ try {
+ byte[] buf = new byte[666];
+ int iRead; int off;
+ while (is.available() > 0) {
+ iRead = is.read(buf, 0, buf.length);
+ if (iRead > 0)
+ bs.write(buf, 0, iRead);
+ }
+ } finally {
+ is.close();
+ }
+ return bs.toByteArray();
+ }
+ // END android-added
+
+ /**
+ * Returns the {@code Manifest} object associated with this {@code JarFile}
+ * or {@code null} if no MANIFEST entry exists.
+ *
+ * @return the MANIFEST.
+ * @throws IOException
+ * if an error occurs reading the MANIFEST file.
+ * @throws IllegalStateException
+ * if the jar file is closed.
+ * @see Manifest
+ * @since Android 1.0
+ */
+ public Manifest getManifest() throws IOException {
+ // BEGIN android-added
+ if (closed) {
+ throw new IllegalStateException("JarFile has been closed.");
+ }
+ // END android-added
+ if (manifest != null) {
+ return manifest;
+ }
+ try {
+ // BEGIN android-modified
+ InputStream is = super.getInputStream(manifestEntry);
+ if (verifier != null) {
+ verifier.addMetaEntry(manifestEntry.getName(), getAllBytesFromStreamAndClose(is));
+ is = super.getInputStream(manifestEntry);
+ }
+ // END android-modified
+ try {
+ manifest = new Manifest(is, verifier != null);
+ } finally {
+ is.close();
+ }
+ manifestEntry = null;
+ } catch(NullPointerException e) {
+ manifestEntry = null;
+ }
+ return manifest;
+ }
+
+ private void readMetaEntries() throws IOException {
+ ZipEntry[] metaEntries = getMetaEntriesImpl(null);
+ int dirLength = META_DIR.length();
+
+ boolean signed = false;
+
+ if (null != metaEntries) {
+ for (ZipEntry entry : metaEntries) {
+ String entryName = entry.getName();
+ if (manifestEntry == null
+ && manifest == null
+ && Util.ASCIIIgnoreCaseRegionMatches(entryName,
+ dirLength, MANIFEST_NAME, dirLength,
+ MANIFEST_NAME.length() - dirLength)) {
+ manifestEntry = entry;
+ if (verifier == null) {
+ break;
+ }
+ } else if (verifier != null && entryName.length() > dirLength
+ && (Util.ASCIIIgnoreCaseRegionMatches(entryName, entryName.length() - 3, ".SF", 0 ,3) //$NON-NLS-1$
+ || Util.ASCIIIgnoreCaseRegionMatches(entryName, entryName.length() - 4, ".DSA", 0 ,4) //$NON-NLS-1$
+ || Util.ASCIIIgnoreCaseRegionMatches(entryName, entryName.length() - 4, ".RSA", 0 ,4))){ //$NON-NLS-1$
+ signed = true;
+ InputStream is = super.getInputStream(entry);
+ // BEGIN android-modified
+ byte[] buf = getAllBytesFromStreamAndClose(is);
+ // END android-modified
+ verifier.addMetaEntry(entryName, buf);
+ }
+ }
+ }
+ if (!signed) {
+ verifier = null;
+ }
+ }
+
+ /**
+ * Return an {@code InputStream} for reading the decompressed contents of
+ * ZIP entry.
+ *
+ * @param ze
+ * the ZIP entry to be read.
+ * @return the input stream to read from.
+ * @throws IOException
+ * if an error occurred while creating the input stream.
+ * @since Android 1.0
+ */
+ @Override
+ public InputStream getInputStream(ZipEntry ze) throws IOException {
+ if (manifestEntry != null) {
+ getManifest();
+ }
+ if (verifier != null) {
+ verifier.setManifest(getManifest());
+ if (manifest != null) {
+ verifier.mainAttributesChunk = manifest
+ .getMainAttributesChunk();
+ }
+ if (verifier.readCertificates()) {
+ verifier.removeMetaEntries();
+ if (manifest != null) {
+ manifest.removeChunks();
+ }
+ if (!verifier.isSignedJar()) {
+ verifier = null;
+ }
+ }
+ }
+ InputStream in = super.getInputStream(ze);
+ if (in == null) {
+ return null;
+ }
+ return new JarFileInputStream(in, ze, ze.getSize() >= 0 ? verifier
+ : null);
+ }
+
+ /**
+ * Return the {@code JarEntry} specified by name or {@code null} if no such
+ * entry exists.
+ *
+ * @param name
+ * the name of the entry in the JAR file.
+ * @return the ZIP entry extracted.
+ * @since Android 1.0
+ */
+ @Override
+ public ZipEntry getEntry(String name) {
+ ZipEntry ze = super.getEntry(name);
+ if (ze == null) {
+ return ze;
+ }
+ JarEntry je = new JarEntry(ze);
+ je.parentJar = this;
+ return je;
+ }
+
+ // BEGIN android-modified
+ private ZipEntry[] getMetaEntriesImpl(byte[] buf) {
+ int n = 0;
+
+ List<ZipEntry> list = new ArrayList<ZipEntry>();
+
+ Enumeration<? extends ZipEntry> allEntries = entries();
+ while (allEntries.hasMoreElements()) {
+ ZipEntry ze = allEntries.nextElement();
+ if (ze.getName().startsWith("META-INF/") && ze.getName().length() > 9) {
+ list.add(ze);
+ }
+ }
+ if (list.size() != 0) {
+ ZipEntry[] result = new ZipEntry[list.size()];
+ list.toArray(result);
+ return result;
+ }
+ else {
+ return null;
+ }
+ }
+ // END android-modified
+
+ // BEGIN android-added
+ /**
+ * Closes this {@code JarFile}.
+ *
+ * @throws IOException
+ * if an error occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public void close() throws IOException {
+ super.close();
+ closed = true;
+ }
+ // END android-added
+
+}
diff --git a/archive/src/main/java/java/util/jar/JarInputStream.java b/archive/src/main/java/java/util/jar/JarInputStream.java
new file mode 100644
index 0000000..ef353ab
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/JarInputStream.java
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.jar;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.harmony.archive.util.Util;
+
+/**
+ * The input stream from which the JAR file to be read may be fetched. It is
+ * used like the {@code ZipInputStream}.
+ *
+ * @see ZipInputStream
+ * @since Android 1.0
+ */
+public class JarInputStream extends ZipInputStream {
+
+ private Manifest manifest;
+
+ private boolean eos = false;
+
+ private JarEntry mEntry;
+
+ private JarEntry jarEntry;
+
+ private boolean isMeta;
+
+ private JarVerifier verifier;
+
+ private OutputStream verStream;
+
+ /**
+ * Constructs a new {@code JarInputStream} from an input stream.
+ *
+ * @param stream
+ * the input stream containing the JAR file.
+ * @param verify
+ * if the file should be verified with a {@code JarVerifier}.
+ * @throws IOException
+ * If an error occurs reading entries from the input stream.
+ * @see ZipInputStream#ZipInputStream(InputStream)
+ * @since Android 1.0
+ */
+ public JarInputStream(InputStream stream, boolean verify)
+ throws IOException {
+ super(stream);
+ if (verify) {
+ verifier = new JarVerifier("JarInputStream"); //$NON-NLS-1$
+ }
+ if ((mEntry = getNextJarEntry()) == null) {
+ return;
+ }
+ String name = Util.toASCIIUpperCase(mEntry.getName());
+ if (name.equals(JarFile.META_DIR)) {
+ mEntry = null; // modifies behavior of getNextJarEntry()
+ closeEntry();
+ mEntry = getNextJarEntry();
+ name = mEntry.getName().toUpperCase();
+ }
+ if (name.equals(JarFile.MANIFEST_NAME)) {
+ mEntry = null;
+ manifest = new Manifest(this, verify);
+ closeEntry();
+ if (verify) {
+ verifier.setManifest(manifest);
+ if (manifest != null) {
+ verifier.mainAttributesChunk = manifest
+ .getMainAttributesChunk();
+ }
+ }
+
+ } else {
+ Attributes temp = new Attributes(3);
+ temp.map.put("hidden", null); //$NON-NLS-1$
+ mEntry.setAttributes(temp);
+ /*
+ * if not from the first entry, we will not get enough
+ * information,so no verify will be taken out.
+ */
+ verifier = null;
+ }
+ }
+
+ /**
+ * Constructs a new {@code JarInputStream} from an input stream.
+ *
+ * @param stream
+ * the input stream containing the JAR file.
+ * @throws IOException
+ * If an error occurs reading entries from the input stream.
+ * @see ZipInputStream#ZipInputStream(InputStream)
+ * @since Android 1.0
+ */
+ public JarInputStream(InputStream stream) throws IOException {
+ this(stream, true);
+ }
+
+ /**
+ * Returns the {@code Manifest} object associated with this {@code
+ * JarInputStream} or {@code null} if no manifest entry exists.
+ *
+ * @return the MANIFEST specifying the contents of the JAR file.
+ * @since Android 1.0
+ */
+ public Manifest getManifest() {
+ return manifest;
+ }
+
+ /**
+ * Returns the next {@code JarEntry} contained in this stream or {@code
+ * null} if no more entries are present.
+ *
+ * @return the next JAR entry.
+ * @throws IOException
+ * if an error occurs while reading the entry.
+ * @since Android 1.0
+ */
+ public JarEntry getNextJarEntry() throws IOException {
+ return (JarEntry) getNextEntry();
+ }
+
+ /**
+ * Reads up to {@code length} of decompressed data and stores it in
+ * {@code buffer} starting at {@code offset}.
+ *
+ * @param buffer
+ * Buffer to store into
+ * @param offset
+ * offset in buffer to store at
+ * @param length
+ * number of bytes to store
+ * @return Number of uncompressed bytes read
+ * @throws IOException
+ * if an IOException occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public int read(byte[] buffer, int offset, int length) throws IOException {
+ if (mEntry != null) {
+ return -1;
+ }
+ int r = super.read(buffer, offset, length);
+ if (verStream != null && !eos) {
+ if (r == -1) {
+ eos = true;
+ if (verifier != null) {
+ if (isMeta) {
+ verifier.addMetaEntry(jarEntry.getName(),
+ ((ByteArrayOutputStream) verStream)
+ .toByteArray());
+ try {
+ verifier.readCertificates();
+ } catch (SecurityException e) {
+ verifier = null;
+ throw e;
+ }
+ } else {
+ verifier.verifySignatures(
+ (JarVerifier.VerifierEntry) verStream,
+ jarEntry);
+ }
+ }
+ } else {
+ verStream.write(buffer, offset, r);
+ }
+ }
+ return r;
+ }
+
+ /**
+ * Returns the next {@code ZipEntry} contained in this stream or {@code
+ * null} if no more entries are present.
+ *
+ * @return the next extracted ZIP entry.
+ * @throws IOException
+ * if an error occurs while reading the entry.
+ * @since Android 1.0
+ */
+ @Override
+ public ZipEntry getNextEntry() throws IOException {
+ if (mEntry != null) {
+ jarEntry = mEntry;
+ mEntry = null;
+ jarEntry.setAttributes(null);
+ } else {
+ jarEntry = (JarEntry) super.getNextEntry();
+ if (jarEntry == null) {
+ return null;
+ }
+ if (verifier != null) {
+ isMeta = Util.toASCIIUpperCase(jarEntry.getName()).startsWith(
+ JarFile.META_DIR);
+ if (isMeta) {
+ verStream = new ByteArrayOutputStream();
+ } else {
+ verStream = verifier.initEntry(jarEntry.getName());
+ }
+ }
+ }
+ eos = false;
+ return jarEntry;
+ }
+
+ @Override
+ protected ZipEntry createZipEntry(String name) {
+ JarEntry entry = new JarEntry(name);
+ if (manifest != null) {
+ entry.setAttributes(manifest.getAttributes(name));
+ }
+ return entry;
+ }
+}
diff --git a/archive/src/main/java/java/util/jar/JarOutputStream.java b/archive/src/main/java/java/util/jar/JarOutputStream.java
new file mode 100644
index 0000000..640f4ef
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/JarOutputStream.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.jar;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * The {@code JarOutputStream} is used to write data in the {@code JarFile}
+ * format to an arbitrary output stream
+ *
+ * @since Android 1.0
+ */
+public class JarOutputStream extends ZipOutputStream {
+
+ private Manifest manifest;
+
+ /**
+ * Constructs a new {@code JarOutputStream} using an output stream. The
+ * content of the {@code Manifest} must match the JAR entry information
+ * written subsequently to the stream.
+ *
+ * @param os
+ * the {@code OutputStream} to write to
+ * @param mf
+ * the {@code Manifest} to output for this JAR file.
+ * @throws IOException
+ * if an error occurs creating the {@code JarOutputStream}.
+ */
+ public JarOutputStream(OutputStream os, Manifest mf) throws IOException {
+ super(os);
+ if (mf == null) {
+ throw new NullPointerException();
+ }
+ manifest = mf;
+ ZipEntry ze = new ZipEntry(JarFile.MANIFEST_NAME);
+ putNextEntry(ze);
+ manifest.write(this);
+ closeEntry();
+ }
+
+ /**
+ * Constructs a new {@code JarOutputStream} using an arbitrary output
+ * stream.
+ *
+ * @param os
+ * the {@code OutputStream} to write to.
+ * @throws IOException
+ * if an error occurs creating the {@code JarOutputStream}.
+ */
+ @SuppressWarnings("unused")
+ public JarOutputStream(OutputStream os) throws IOException {
+ super(os);
+ }
+
+ /**
+ * Writes the specified ZIP entry to the underlying stream. The previous
+ * entry is closed if it is still open.
+ *
+ * @param ze
+ * the {@code ZipEntry} to write to.
+ * @throws IOException
+ * if an error occurs writing to the entry.
+ * @see ZipEntry
+ * @since Android 1.0
+ */
+ @Override
+ public void putNextEntry(ZipEntry ze) throws IOException {
+ super.putNextEntry(ze);
+ }
+}
diff --git a/archive/src/main/java/java/util/jar/JarVerifier.java b/archive/src/main/java/java/util/jar/JarVerifier.java
new file mode 100644
index 0000000..b9173f2
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/JarVerifier.java
@@ -0,0 +1,510 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.jar;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.zip.ZipEntry;
+
+import org.apache.harmony.archive.internal.nls.Messages;
+import org.apache.harmony.luni.util.Base64;
+import org.apache.harmony.security.utils.JarUtils;
+
+import org.apache.harmony.archive.util.Util;
+
+// BEGIN android-added
+import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK;
+// END android-added
+
+/**
+ * Non-public class used by {@link JarFile} and {@link JarInputStream} to manage
+ * the verification of signed JARs. {@code JarFile} and {@code JarInputStream}
+ * objects are expected to have a {@code JarVerifier} instance member which
+ * can be used to carry out the tasks associated with verifying a signed JAR.
+ * These tasks would typically include:
+ * <ul>
+ * <li>verification of all signed signature files
+ * <li>confirmation that all signed data was signed only by the party or parties
+ * specified in the signature block data
+ * <li>verification that the contents of all signature files (i.e. {@code .SF}
+ * files) agree with the JAR entries information found in the JAR manifest.
+ * </ul>
+ */
+class JarVerifier {
+
+ private final String jarName;
+
+ private Manifest man;
+
+ private HashMap<String, byte[]> metaEntries = new HashMap<String, byte[]>(5);
+
+ private final Hashtable<String, HashMap<String, Attributes>> signatures =
+ new Hashtable<String, HashMap<String, Attributes>>(5);
+
+ private final Hashtable<String, Certificate[]> certificates =
+ new Hashtable<String, Certificate[]>(5);
+
+ private final Hashtable<String, Certificate[]> verifiedEntries =
+ new Hashtable<String, Certificate[]>();
+
+ byte[] mainAttributesChunk;
+
+ // BEGIN android-added
+ private static long measureCount = 0;
+
+ private static long averageTime = 0;
+ // END android-added
+
+ /**
+ * TODO Type description
+ */
+ static class VerifierEntry extends OutputStream {
+
+ MessageDigest digest;
+
+ byte[] hash;
+
+ Certificate[] certificates;
+
+ VerifierEntry(MessageDigest digest, byte[] hash,
+ Certificate[] certificates) {
+ this.digest = digest;
+ this.hash = hash;
+ this.certificates = certificates;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.io.OutputStream#write(int)
+ */
+ @Override
+ public void write(int value) {
+ digest.update((byte) value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.io.OutputStream#write(byte[], int, int)
+ */
+ @Override
+ public void write(byte[] buf, int off, int nbytes) {
+ digest.update(buf, off, nbytes);
+ }
+ }
+
+ /**
+ * Constructs and returns a new instance of {@code JarVerifier}.
+ *
+ * @param name
+ * the name of the JAR file being verified.
+ */
+ JarVerifier(String name) {
+ jarName = name;
+ }
+
+ /**
+ * Invoked for each new JAR entry read operation from the input
+ * stream. This method constructs and returns a new {@link VerifierEntry}
+ * which contains the certificates used to sign the entry and its hash value
+ * as specified in the JAR MANIFEST format.
+ *
+ * @param name
+ * the name of an entry in a JAR file which is <b>not</b> in the
+ * {@code META-INF} directory.
+ * @return a new instance of {@link VerifierEntry} which can be used by
+ * callers as an {@link OutputStream}.
+ * @since Android 1.0
+ */
+ VerifierEntry initEntry(String name) {
+ // If no manifest is present by the time an entry is found,
+ // verification cannot occur. If no signature files have
+ // been found, do not verify.
+ if (man == null || signatures.size() == 0) {
+ return null;
+ }
+
+ Attributes attributes = man.getAttributes(name);
+ // entry has no digest
+ if (attributes == null) {
+ return null;
+ }
+
+ Vector<Certificate> certs = new Vector<Certificate>();
+ Iterator<Map.Entry<String, HashMap<String, Attributes>>> it =
+ signatures.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, HashMap<String, Attributes>> entry = it.next();
+ HashMap<String, Attributes> hm = entry.getValue();
+ if (hm.get(name) != null) {
+ // Found an entry for entry name in .SF file
+ String signatureFile = entry.getKey();
+
+ Vector<Certificate> newCerts = getSignerCertificates(
+ signatureFile, certificates);
+ Iterator<Certificate> iter = newCerts.iterator();
+ while (iter.hasNext()) {
+ certs.add(iter.next());
+ }
+ }
+ }
+
+ // entry is not signed
+ if (certs.size() == 0) {
+ return null;
+ }
+ Certificate[] certificatesArray = new Certificate[certs.size()];
+ certs.toArray(certificatesArray);
+
+ String algorithms = attributes.getValue("Digest-Algorithms"); //$NON-NLS-1$
+ if (algorithms == null) {
+ algorithms = "SHA SHA1"; //$NON-NLS-1$
+ }
+ StringTokenizer tokens = new StringTokenizer(algorithms);
+ while (tokens.hasMoreTokens()) {
+ String algorithm = tokens.nextToken();
+ String hash = attributes.getValue(algorithm + "-Digest"); //$NON-NLS-1$
+ if (hash == null) {
+ continue;
+ }
+ byte[] hashBytes;
+ try {
+ hashBytes = hash.getBytes("ISO8859_1"); //$NON-NLS-1$
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e.toString());
+ }
+
+ try {
+ // BEGIN android-changed
+ return new VerifierEntry(OpenSSLMessageDigestJDK.getInstance(algorithm),
+ hashBytes, certificatesArray);
+ // END android-changed
+ } catch (NoSuchAlgorithmException e) {
+ // Ignored
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Add a new meta entry to the internal collection of data held on each JAR
+ * entry in the {@code META-INF} directory including the manifest
+ * file itself. Files associated with the signing of a JAR would also be
+ * added to this collection.
+ *
+ * @param name
+ * the name of the file located in the {@code META-INF}
+ * directory.
+ * @param buf
+ * the file bytes for the file called {@code name}.
+ * @see #removeMetaEntries()
+ */
+ void addMetaEntry(String name, byte[] buf) {
+ metaEntries.put(Util.toASCIIUpperCase(name), buf);
+ }
+
+ /**
+ * If the associated JAR file is signed, check on the validity of all of the
+ * known signatures.
+ *
+ * @return {@code true} if the associated JAR is signed and an internal
+ * check verifies the validity of the signature(s). {@code false} if
+ * the associated JAR file has no entries at all in its {@code
+ * META-INF} directory. This situation is indicative of an invalid
+ * JAR file.
+ * <p>
+ * Will also return {@code true} if the JAR file is <i>not</i>
+ * signed.
+ * </p>
+ * @throws SecurityException
+ * if the JAR file is signed and it is determined that a
+ * signature block file contains an invalid signature for the
+ * corresponding signature file.
+ * @since Android 1.0
+ */
+ synchronized boolean readCertificates() {
+ if (metaEntries == null) {
+ return false;
+ }
+ Iterator<String> it = metaEntries.keySet().iterator();
+ while (it.hasNext()) {
+ String key = it.next();
+ if (key.endsWith(".DSA") || key.endsWith(".RSA")) { //$NON-NLS-1$ //$NON-NLS-2$
+ verifyCertificate(key);
+ // Check for recursive class load
+ if (metaEntries == null) {
+ return false;
+ }
+ it.remove();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @param certFile
+ */
+ private void verifyCertificate(String certFile) {
+ // Found Digital Sig, .SF should already have been read
+ String signatureFile = certFile.substring(0, certFile.lastIndexOf('.'))
+ + ".SF"; //$NON-NLS-1$
+ byte[] sfBytes = metaEntries.get(signatureFile);
+ if (sfBytes == null) {
+ return;
+ }
+
+ byte[] sBlockBytes = metaEntries.get(certFile);
+ try {
+ Certificate[] signerCertChain = JarUtils.verifySignature(
+ new ByteArrayInputStream(sfBytes),
+ new ByteArrayInputStream(sBlockBytes));
+ /*
+ * Recursive call in loading security provider related class which
+ * is in a signed JAR.
+ */
+ if (null == metaEntries) {
+ return;
+ }
+ if (signerCertChain != null) {
+ certificates.put(signatureFile, signerCertChain);
+ }
+ } catch (IOException e) {
+ return;
+ } catch (GeneralSecurityException e) {
+ /* [MSG "archive.30", "{0} failed verification of {1}"] */
+ throw new SecurityException(
+ Messages.getString("archive.30", jarName, signatureFile)); //$NON-NLS-1$
+ }
+
+ // Verify manifest hash in .sf file
+ Attributes attributes = new Attributes();
+ HashMap<String, Attributes> hm = new HashMap<String, Attributes>();
+ try {
+ new InitManifest(new ByteArrayInputStream(sfBytes), attributes, hm,
+ null, "Signature-Version"); //$NON-NLS-1$
+ } catch (IOException e) {
+ return;
+ }
+
+ boolean createdBySigntool = false;
+ String createdByValue = attributes.getValue("Created-By"); //$NON-NLS-1$
+ if (createdByValue != null) {
+ createdBySigntool = createdByValue.indexOf("signtool") != -1; //$NON-NLS-1$
+ }
+
+ // Use .SF to verify the mainAttributes of the manifest
+ // If there is no -Digest-Manifest-Main-Attributes entry in .SF
+ // file, such as those created before java 1.5, then we ignore
+ // such verification.
+ // FIXME: The meaning of createdBySigntool
+ if (mainAttributesChunk != null && !createdBySigntool) {
+ String digestAttribute = "-Digest-Manifest-Main-Attributes"; //$NON-NLS-1$
+ if (!verify(attributes, digestAttribute, mainAttributesChunk,
+ false, true)) {
+ /* [MSG "archive.30", "{0} failed verification of {1}"] */
+ throw new SecurityException(
+ Messages.getString("archive.30", jarName, signatureFile)); //$NON-NLS-1$
+ }
+ }
+
+ byte[] manifest = metaEntries.get(JarFile.MANIFEST_NAME);
+ if (manifest == null) {
+ return;
+ }
+ // Use .SF to verify the whole manifest
+ String digestAttribute = createdBySigntool ? "-Digest" //$NON-NLS-1$
+ : "-Digest-Manifest"; //$NON-NLS-1$
+ if (!verify(attributes, digestAttribute, manifest, false, false)) {
+ Iterator<Map.Entry<String, Attributes>> it = hm.entrySet()
+ .iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, Attributes> entry = it.next();
+ byte[] chunk = man.getChunk(entry.getKey());
+ if (chunk == null) {
+ return;
+ }
+ if (!verify(entry.getValue(), "-Digest", chunk, //$NON-NLS-1$
+ createdBySigntool, false)) {
+ /* [MSG "archive.31", "{0} has invalid digest for {1} in {2}"] */
+ throw new SecurityException(
+ Messages.getString("archive.31", //$NON-NLS-1$
+ new Object[] { signatureFile, entry.getKey(), jarName }));
+ }
+ }
+ }
+ metaEntries.put(signatureFile, null);
+ signatures.put(signatureFile, hm);
+ }
+
+ /**
+ * Associate this verifier with the specified {@link Manifest} object.
+ *
+ * @param mf
+ * a {@code java.util.jar.Manifest} object.
+ */
+ void setManifest(Manifest mf) {
+ man = mf;
+ }
+
+ /**
+ * Verifies that the digests stored in the manifest match the decrypted
+ * digests from the .SF file. This indicates the validity of the signing,
+ * not the integrity of the file, as it's digest must be calculated and
+ * verified when its contents are read.
+ *
+ * @param entry
+ * the {@link VerifierEntry} associated with the specified
+ * {@code zipEntry}.
+ * @param zipEntry
+ * an entry in the JAR file
+ * @throws SecurityException
+ * if the digest value stored in the manifest does <i>not</i>
+ * agree with the decrypted digest as recovered from the
+ * {@code .SF} file.
+ * @see #initEntry(String)
+ */
+ void verifySignatures(VerifierEntry entry, ZipEntry zipEntry) {
+ byte[] digest = entry.digest.digest();
+ if (!MessageDigest.isEqual(digest, Base64.decode(entry.hash))) {
+ /* [MSG "archive.31", "{0} has invalid digest for {1} in {2}"] */
+ throw new SecurityException(Messages.getString("archive.31", new Object[] { //$NON-NLS-1$
+ JarFile.MANIFEST_NAME, zipEntry.getName(), jarName }));
+ }
+ verifiedEntries.put(zipEntry.getName(), entry.certificates);
+ }
+
+ /**
+ * Returns a {@code boolean} indication of whether or not the
+ * associated JAR file is signed.
+ *
+ * @return {@code true} if the JAR is signed, {@code false}
+ * otherwise.
+ */
+ boolean isSignedJar() {
+ return certificates.size() > 0;
+ }
+
+ private boolean verify(Attributes attributes, String entry, byte[] data,
+ boolean ignoreSecondEndline, boolean ignorable) {
+ String algorithms = attributes.getValue("Digest-Algorithms"); //$NON-NLS-1$
+ if (algorithms == null) {
+ algorithms = "SHA SHA1"; //$NON-NLS-1$
+ }
+ StringTokenizer tokens = new StringTokenizer(algorithms);
+ while (tokens.hasMoreTokens()) {
+ String algorithm = tokens.nextToken();
+ String hash = attributes.getValue(algorithm + entry);
+ if (hash == null) {
+ continue;
+ }
+
+ MessageDigest md;
+ try {
+ // BEGIN android-changed
+ md = OpenSSLMessageDigestJDK.getInstance(algorithm);
+ // END android-changed
+ } catch (NoSuchAlgorithmException e) {
+ continue;
+ }
+ if (ignoreSecondEndline && data[data.length - 1] == '\n'
+ && data[data.length - 2] == '\n') {
+ md.update(data, 0, data.length - 1);
+ } else {
+ md.update(data, 0, data.length);
+ }
+ byte[] b = md.digest();
+ byte[] hashBytes;
+ try {
+ hashBytes = hash.getBytes("ISO8859_1"); //$NON-NLS-1$
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e.toString());
+ }
+ return MessageDigest.isEqual(b, Base64.decode(hashBytes));
+ }
+ return ignorable;
+ }
+
+ /**
+ * Returns all of the {@link java.security.cert.Certificate} instances that
+ * were used to verify the signature on the JAR entry called
+ * {@code name}.
+ *
+ * @param name
+ * the name of a JAR entry.
+ * @return an array of {@link java.security.cert.Certificate}.
+ */
+ Certificate[] getCertificates(String name) {
+ Certificate[] verifiedCerts = verifiedEntries.get(name);
+ if (verifiedCerts == null) {
+ return null;
+ }
+ return verifiedCerts.clone();
+ }
+
+ /**
+ * Remove all entries from the internal collection of data held about each
+ * JAR entry in the {@code META-INF} directory.
+ *
+ * @see #addMetaEntry(String, byte[])
+ */
+ void removeMetaEntries() {
+ metaEntries = null;
+ }
+
+ /**
+ * Returns a {@code Vector} of all of the
+ * {@link java.security.cert.Certificate}s that are associated with the
+ * signing of the named signature file.
+ *
+ * @param signatureFileName
+ * the name of a signature file.
+ * @param certificates
+ * a {@code Map} of all of the certificate chains discovered so
+ * far while attempting to verify the JAR that contains the
+ * signature file {@code signatureFileName}. This object is
+ * previously set in the course of one or more calls to
+ * {@link #verifyJarSignatureFile(String, String, String, Map, Map)}
+ * where it was passed as the last argument.
+ * @return all of the {@code Certificate} entries for the signer of the JAR
+ * whose actions led to the creation of the named signature file.
+ */
+ public static Vector<Certificate> getSignerCertificates(
+ String signatureFileName, Map<String, Certificate[]> certificates) {
+ Vector<Certificate> result = new Vector<Certificate>();
+ Certificate[] certChain = certificates.get(signatureFileName);
+ if (certChain != null) {
+ for (Certificate element : certChain) {
+ result.add(element);
+ }
+ }
+ return result;
+ }
+}
diff --git a/archive/src/main/java/java/util/jar/Manifest.java b/archive/src/main/java/java/util/jar/Manifest.java
new file mode 100644
index 0000000..3b0d89a
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/Manifest.java
@@ -0,0 +1,344 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.jar;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.security.AccessController;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.harmony.luni.util.PriviAction;
+
+/**
+ * The {@code Manifest} class is used to obtain attribute information for a
+ * {@code JarFile} and its entries.
+ *
+ * @since Android 1.0
+ */
+public class Manifest implements Cloneable {
+ private static final int LINE_LENGTH_LIMIT = 70;
+
+ private static final byte[] LINE_SEPARATOR = new byte[] { '\r', '\n' };
+
+ private static final Attributes.Name NAME_ATTRIBUTE = new Attributes.Name("Name"); //$NON-NLS-1$
+
+ private Attributes mainAttributes = new Attributes();
+
+ private HashMap<String, Attributes> entryAttributes = new HashMap<String, Attributes>();
+
+ private HashMap<String, byte[]> chunks;
+
+ /**
+ * The data chunk of main attributes in the manifest is needed in
+ * verification.
+ */
+ private byte[] mainAttributesChunk;
+
+ /**
+ * Creates a new {@code Manifest} instance.
+ *
+ * @since Android 1.0
+ */
+ public Manifest() {
+ super();
+ }
+
+ /**
+ * Creates a new {@code Manifest} instance using the attributes obtained
+ * from the input stream.
+ *
+ * @param is
+ * {@code InputStream} to parse for attributes.
+ * @throws IOException
+ * if an IO error occurs while creating this {@code Manifest}
+ * @since Android 1.0
+ */
+ public Manifest(InputStream is) throws IOException {
+ super();
+ read(is);
+ }
+
+ /**
+ * Creates a new {@code Manifest} instance. The new instance will have the
+ * same attributes as those found in the parameter {@code Manifest}.
+ *
+ * @param man
+ * {@code Manifest} instance to obtain attributes from.
+ * @since Android 1.0
+ */
+ @SuppressWarnings("unchecked")
+ public Manifest(Manifest man) {
+ mainAttributes = (Attributes) man.mainAttributes.clone();
+ entryAttributes = (HashMap<String, Attributes>) man.entryAttributes.clone();
+ }
+
+ Manifest(InputStream is, boolean readChunks) throws IOException {
+ if (readChunks) {
+ chunks = new HashMap<String, byte[]>();
+ }
+ read(is);
+ }
+
+ /**
+ * Resets the both the main attributes as well as the entry attributes
+ * associated with this {@code Manifest}.
+ *
+ * @since Android 1.0
+ */
+ public void clear() {
+ entryAttributes.clear();
+ mainAttributes.clear();
+ }
+
+ /**
+ * Returns the {@code Attributes} associated with the parameter entry
+ * {@code name}.
+ *
+ * @param name
+ * the name of the entry to obtain {@code Attributes} from.
+ * @return the Attributes for the entry or {@code null} if the entry does
+ * not exist.
+ * @since Android 1.0
+ */
+ public Attributes getAttributes(String name) {
+ return getEntries().get(name);
+ }
+
+ /**
+ * Returns a map containing the {@code Attributes} for each entry in the
+ * {@code Manifest}.
+ *
+ * @return the map of entry attributes.
+ * @since Android 1.0
+ */
+ public Map<String, Attributes> getEntries() {
+ return entryAttributes;
+ }
+
+ /**
+ * Returns the main {@code Attributes} of the {@code JarFile}.
+ *
+ * @return main {@code Attributes} associated with the source {@code
+ * JarFile}.
+ * @since Android 1.0
+ */
+ public Attributes getMainAttributes() {
+ return mainAttributes;
+ }
+
+ /**
+ * Creates a copy of this {@code Manifest}. The returned {@code Manifest}
+ * will equal the {@code Manifest} from which it was cloned.
+ *
+ * @return a copy of this instance.
+ * @since Android 1.0
+ */
+ @Override
+ public Object clone() {
+ return new Manifest(this);
+ }
+
+ /**
+ * Writes out the attribute information of the receiver to the specified
+ * {@code OutputStream}.
+ *
+ * @param os
+ * The {@code OutputStream} to write to.
+ * @throws IOException
+ * If an error occurs writing the {@code Manifest}.
+ * @since Android 1.0
+ */
+ public void write(OutputStream os) throws IOException {
+ write(this, os);
+ }
+
+ /**
+ * Constructs a new {@code Manifest} instance obtaining attribute
+ * information from the specified input stream.
+ *
+ * @param is
+ * The {@code InputStream} to read from.
+ * @throws IOException
+ * If an error occurs reading the {@code Manifest}.
+ * @since Android 1.0
+ */
+ public void read(InputStream is) throws IOException {
+ InitManifest initManifest = new InitManifest(is, mainAttributes, entryAttributes,
+ chunks, null);
+ mainAttributesChunk = initManifest.getMainAttributesChunk();
+ }
+
+ /**
+ * Returns the hash code for this instance.
+ *
+ * @return this {@code Manifest}'s hashCode.
+ * @since Android 1.0
+ */
+ @Override
+ public int hashCode() {
+ return mainAttributes.hashCode() ^ entryAttributes.hashCode();
+ }
+
+ /**
+ * Determines if the receiver is equal to the parameter object. Two {@code
+ * Manifest}s are equal if they have identical main attributes as well as
+ * identical entry attributes.
+ *
+ * @param o
+ * the object to compare against.
+ * @return {@code true} if the manifests are equal, {@code false} otherwise
+ * @since Android 1.0
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ }
+ if (o.getClass() != this.getClass()) {
+ return false;
+ }
+ if (!mainAttributes.equals(((Manifest) o).mainAttributes)) {
+ return false;
+ }
+ return entryAttributes.equals(((Manifest) o).entryAttributes);
+ }
+
+ byte[] getChunk(String name) {
+ return chunks.get(name);
+ }
+
+ void removeChunks() {
+ chunks = null;
+ }
+
+ byte[] getMainAttributesChunk() {
+ return mainAttributesChunk;
+ }
+
+ /**
+ * Writes out the attribute information of the specified manifest to the
+ * specified {@code OutputStream}
+ *
+ * @param manifest
+ * the manifest to write out.
+ * @param out
+ * The {@code OutputStream} to write to.
+ * @throws IOException
+ * If an error occurs writing the {@code Manifest}.
+ * @since Android 1.0
+ */
+ static void write(Manifest manifest, OutputStream out) throws IOException {
+ Charset charset = null;
+ String encoding = AccessController.doPrivileged(new PriviAction<String>(
+ "manifest.write.encoding")); //$NON-NLS-1$
+ if (encoding != null) {
+ if (encoding.length() == 0) {
+ encoding = "UTF8"; //$NON-NLS-1$
+ }
+ charset = Charset.forName(encoding);
+ }
+ String version = manifest.mainAttributes.getValue(Attributes.Name.MANIFEST_VERSION);
+ if (version != null) {
+ writeEntry(out, charset, Attributes.Name.MANIFEST_VERSION, version);
+ Iterator<?> entries = manifest.mainAttributes.keySet().iterator();
+ while (entries.hasNext()) {
+ Attributes.Name name = (Attributes.Name) entries.next();
+ if (!name.equals(Attributes.Name.MANIFEST_VERSION)) {
+ writeEntry(out, charset, name, manifest.mainAttributes.getValue(name));
+ }
+ }
+ }
+ out.write(LINE_SEPARATOR);
+ Iterator<String> i = manifest.entryAttributes.keySet().iterator();
+ while (i.hasNext()) {
+ String key = i.next();
+ writeEntry(out, charset, NAME_ATTRIBUTE, key);
+ Attributes attrib = manifest.entryAttributes.get(key);
+ Iterator<?> entries = attrib.keySet().iterator();
+ while (entries.hasNext()) {
+ Attributes.Name name = (Attributes.Name) entries.next();
+ writeEntry(out, charset, name, attrib.getValue(name));
+ }
+ out.write(LINE_SEPARATOR);
+ }
+ }
+
+ private static void writeEntry(OutputStream os, Charset charset, Attributes.Name name,
+ String value) throws IOException {
+ int offset = 0;
+ int limit = LINE_LENGTH_LIMIT;
+ byte[] out = (name.toString() + ": ").getBytes("ISO8859_1"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (out.length > limit) {
+ while (out.length - offset >= limit) {
+ int len = out.length - offset;
+ if (len > limit) {
+ len = limit;
+ }
+ if (offset > 0) {
+ os.write(' ');
+ }
+ os.write(out, offset, len);
+ os.write(LINE_SEPARATOR);
+ offset += len;
+ limit = LINE_LENGTH_LIMIT - 1;
+ }
+ }
+ int size = out.length - offset;
+ final byte[] outBuf = new byte[LINE_LENGTH_LIMIT];
+ System.arraycopy(out, offset, outBuf, 0, size);
+ for (int i = 0; i < value.length(); i++) {
+ char[] oneChar = new char[1];
+ oneChar[0] = value.charAt(i);
+ byte[] buf;
+ if (oneChar[0] < 128 || charset == null) {
+ byte[] oneByte = new byte[1];
+ oneByte[0] = (byte) oneChar[0];
+ buf = oneByte;
+ } else {
+ buf = charset.encode(CharBuffer.wrap(oneChar, 0, 1)).array();
+ }
+ if (size + buf.length > limit) {
+ if (limit != LINE_LENGTH_LIMIT) {
+ os.write(' ');
+ }
+ os.write(outBuf, 0, size);
+ os.write(LINE_SEPARATOR);
+ limit = LINE_LENGTH_LIMIT - 1;
+ size = 0;
+ }
+ if (buf.length == 1) {
+ outBuf[size] = buf[0];
+ } else {
+ System.arraycopy(buf, 0, outBuf, size, buf.length);
+ }
+ size += buf.length;
+ }
+ if (size > 0) {
+ if (limit != LINE_LENGTH_LIMIT) {
+ os.write(' ');
+ }
+ os.write(outBuf, 0, size);
+ os.write(LINE_SEPARATOR);
+ }
+ }
+}
diff --git a/archive/src/main/java/java/util/jar/Pack200.java b/archive/src/main/java/java/util/jar/Pack200.java
new file mode 100644
index 0000000..e0689e0
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/Pack200.java
@@ -0,0 +1,398 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package java.util.jar;
+
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.SortedMap;
+
+/**
+ * Class factory for {@link Pack200.Packer} and {@link Pack200.Unpacker}.
+ *
+ * @since Android 1.0
+ */
+public abstract class Pack200 {
+
+ private static final String SYSTEM_PROPERTY_PACKER = "java.util.jar.Pack200.Packer"; //$NON-NLS-1$
+
+ private static final String SYSTEM_PROPERTY_UNPACKER = "java.util.jar.Pack200.Unpacker"; //$NON-NLS-1$
+
+ /**
+ * Prevent this class from being instantiated.
+ */
+ private Pack200(){
+ //do nothing
+ }
+
+ /**
+ * Returns a new instance of a packer engine.
+ * <p>
+ * The implementation of the packer engine is defined by the system property
+ * {@code 'java.util.jar.Pack200.Packer'}. If this system property is
+ * defined an instance of the specified class is returned, otherwise the
+ * system's default implementation is returned.
+ * </p>
+ *
+ * @return an instance of {@code Packer}
+ * @since Android 1.0
+ */
+ public static Pack200.Packer newPacker() {
+ return (Packer) AccessController
+ .doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ String className = System
+ .getProperty(SYSTEM_PROPERTY_PACKER,
+ "org.apache.harmony.archive.internal.pack200.Pack200PackerAdapter"); //$NON-NLS-1$
+ try {
+ // TODO Not sure if this will cause problems with
+ // loading the packer
+ return ClassLoader.getSystemClassLoader()
+ .loadClass(className).newInstance();
+ } catch (Exception e) {
+ throw new Error("Can't load class " + className, e);
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Returns a new instance of a unpacker engine.
+ * <p>
+ * The implementation of the unpacker engine is defined by the system
+ * property {@code 'java.util.jar.Pack200.Unpacker'}. If this system
+ * property is defined an instance of the specified class is returned,
+ * otherwise the system's default implementation is returned.
+ * </p>
+ *
+ * @return a instance of {@code Unpacker}.
+ * @since Android 1.0
+ */
+ public static Pack200.Unpacker newUnpacker() {
+ return (Unpacker) AccessController
+ .doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ String className = System
+ .getProperty(SYSTEM_PROPERTY_UNPACKER,
+ "org.apache.harmony.archive.internal.pack200.Pack200UnpackerAdapter");//$NON-NLS-1$
+ try {
+ return ClassLoader.getSystemClassLoader()
+ .loadClass(className).newInstance();
+ } catch (Exception e) {
+ throw new Error("Can't load class " + className, e);
+ }
+ }
+ });
+ }
+
+ /**
+ * The interface defining the API for converting a JAR file to an output
+ * stream in the Pack200 format.
+ *
+ * @since Android 1.0
+ */
+ public static interface Packer {
+
+ /**
+ * the format of a class attribute name.
+ *
+ * @since Android 1.0
+ */
+ static final String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; //$NON-NLS-1$
+
+ /**
+ * the format of a code attribute name.
+ *
+ * @since Android 1.0
+ */
+ static final String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; //$NON-NLS-1$
+
+ /**
+ * the deflation hint to set in the output archive.
+ *
+ * @since Android 1.0
+ */
+ static final String DEFLATE_HINT = "pack.deflate.hint";//$NON-NLS-1$
+
+ /**
+ * the indicated amount of effort to use in compressing the archive.
+ *
+ * @since Android 1.0
+ */
+ static final String EFFORT = "pack.effort";//$NON-NLS-1$
+
+ /**
+ * a String representation for {@code error}.
+ *
+ * @since Android 1.0
+ */
+ static final String ERROR = "error";//$NON-NLS-1$
+
+ /**
+ * a String representation of {@code false}.
+ *
+ * @since Android 1.0
+ */
+ static final String FALSE = "false";//$NON-NLS-1$
+
+ /**
+ * the format of a field attribute name.
+ *
+ * @since Android 1.0
+ */
+ static final String FIELD_ATTRIBUTE_PFX = "pack.field.attribute.";//$NON-NLS-1$
+
+ /**
+ * a String representation for {@code keep}.
+ *
+ * @since Android 1.0
+ */
+ static final String KEEP = "keep";//$NON-NLS-1$
+
+ /**
+ * decide if all elements shall transmit in their original order.
+ *
+ * @since Android 1.0
+ */
+ static final String KEEP_FILE_ORDER = "pack.keep.file.order";//$NON-NLS-1$
+
+ /**
+ * a String representation for {@code latest}.
+ *
+ * @since Android 1.0
+ */
+ static final String LATEST = "latest";//$NON-NLS-1$
+
+ /**
+ * the format of a method attribute name.
+ *
+ * @since Android 1.0
+ */
+ static final String METHOD_ATTRIBUTE_PFX = "pack.method.attribute.";//$NON-NLS-1$
+
+ /**
+ * if it shall attempt to determine the latest modification time if this
+ * is set to {@code LATEST}.
+ *
+ * @since Android 1.0
+ */
+ static final String MODIFICATION_TIME = "pack.modification.time";//$NON-NLS-1$
+
+ /**
+ * a String representation of {@code pass}.
+ *
+ * @since Android 1.0
+ */
+ static final String PASS = "pass";//$NON-NLS-1$
+
+ /**
+ * the file that will not be compressed.
+ *
+ * @since Android 1.0
+ */
+ static final String PASS_FILE_PFX = "pack.pass.file.";//$NON-NLS-1$
+
+ /**
+ * packer progress as a percentage.
+ *
+ * @since Android 1.0
+ */
+ static final String PROGRESS = "pack.progress";//$NON-NLS-1$
+
+ /**
+ * The number of bytes of each archive segment.
+ *
+ * @since Android 1.0
+ */
+ static final String SEGMENT_LIMIT = "pack.segment.limit";//$NON-NLS-1$
+
+ /**
+ * a String representation of {@code strip}.
+ *
+ * @since Android 1.0
+ */
+ static final String STRIP = "strip";//$NON-NLS-1$
+
+ /**
+ * a String representation of {@code true}.
+ *
+ * @since Android 1.0
+ */
+ static final String TRUE = "true";//$NON-NLS-1$
+
+ /**
+ * the action to take if an unknown attribute is encountered.
+ *
+ * @since Android 1.0
+ */
+ static final String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute";//$NON-NLS-1$
+
+ /**
+ * Returns a sorted map of the properties of this packer.
+ *
+ * @return the properties of the packer.
+ * @since Android 1.0
+ */
+ SortedMap<String, String> properties();
+
+ /**
+ * Pack the specified JAR file to the specified output stream.
+ *
+ * @param in
+ * JAR file to be compressed.
+ * @param out
+ * stream of compressed data.
+ * @throws IOException
+ * if I/O exception occurs.
+ * @since Android 1.0
+ */
+ void pack(JarFile in, OutputStream out) throws IOException;
+
+ /**
+ * Pack the data from the specified jar input stream to the specified
+ * output stream.
+ *
+ * @param in
+ * stream of uncompressed JAR data.
+ * @param out
+ * stream of compressed data.
+ * @throws IOException
+ * if I/O exception occurs.
+ * @since Android 1.0
+ */
+ void pack(JarInputStream in, OutputStream out) throws IOException;
+
+ /**
+ * add a listener for PropertyChange events
+ *
+ * @param listener
+ * the listener to listen if PropertyChange events occurs
+ */
+ void addPropertyChangeListener(PropertyChangeListener listener);
+
+ /**
+ * remove a listener
+ *
+ * @param listener
+ * listener to remove
+ */
+ void removePropertyChangeListener(PropertyChangeListener listener);
+ }
+
+ /**
+ * The interface defining the API for converting a packed stream in the
+ * Pack200 format to a JAR file.
+ *
+ * @since Android 1.0
+ */
+ public static interface Unpacker {
+
+ /**
+ * The String indicating if the unpacker should ignore all transmitted
+ * values,can be replaced by either {@code true} or {@code false}.
+ *
+ * @since Android 1.0
+ */
+ static final String DEFLATE_HINT = "unpack.deflate.hint";//$NON-NLS-1$
+
+ /**
+ * a String representation of {@code false}.
+ *
+ * @since Android 1.0
+ */
+ static final String FALSE = "false";//$NON-NLS-1$
+
+ /**
+ * a String representation of {@code keep}.
+ *
+ * @since Android 1.0
+ */
+ static final String KEEP = "keep";//$NON-NLS-1$
+
+ /**
+ * the progress as a {@code percentage}.
+ *
+ * @since Android 1.0
+ */
+ static final String PROGRESS = "unpack.progress";//$NON-NLS-1$
+
+ /**
+ * a String representation of {@code true}.
+ *
+ * @since Android 1.0
+ */
+ static final String TRUE = "true";//$NON-NLS-1$
+
+ /**
+ * Returns a sorted map of the properties of this unpacker.
+ *
+ * @return the properties of unpacker.
+ * @since Android 1.0
+ */
+ SortedMap<String, String> properties();
+
+ /**
+ * Unpack the specified stream to the specified JAR output stream.
+ *
+ * @param in
+ * stream to uncompressed.
+ * @param out
+ * JAR output stream of uncompressed data.
+ * @throws IOException
+ * if I/O exception occurs.
+ * @since Android 1.0
+ */
+ void unpack(InputStream in, JarOutputStream out) throws IOException;
+
+ /**
+ * Unpack the contents of the specified {@code File} to the specified
+ * JAR output stream.
+ *
+ * @param in
+ * file to be uncompressed.
+ * @param out
+ * JAR output stream of uncompressed data.
+ * @throws IOException
+ * if I/O exception occurs.
+ * @since Android 1.0
+ */
+ void unpack(File in, JarOutputStream out) throws IOException;
+
+ /**
+ * add a listener for {@code PropertyChange} events.
+ *
+ * @param listener
+ * the listener to listen if {@code PropertyChange} events
+ * occurs.
+ */
+ void addPropertyChangeListener(PropertyChangeListener listener);
+
+ /**
+ * remove a listener.
+ *
+ * @param listener
+ * listener to remove.
+ */
+ void removePropertyChangeListener(PropertyChangeListener listener);
+ }
+
+}
diff --git a/archive/src/main/java/java/util/jar/package.html b/archive/src/main/java/java/util/jar/package.html
new file mode 100644
index 0000000..35eabe7
--- /dev/null
+++ b/archive/src/main/java/java/util/jar/package.html
@@ -0,0 +1,12 @@
+<html>
+ <body>
+ <p>
+ The java.jar package gives access to reading and writing a Java archive,
+ or JAR, files. These are
+ actually ZIP files with the possibility to add meta-information in the
+ form of a MANIFEST file. This manifest can also be used
+ to sign a JAR file.
+ </p>
+ @since Android 1.0
+ </body>
+</html>
diff --git a/archive/src/main/java/java/util/zip/Adler32.java b/archive/src/main/java/java/util/zip/Adler32.java
new file mode 100644
index 0000000..8eaa18e
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/Adler32.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+/**
+ * The Adler-32 class is used to compute the {@code Adler32} checksum from a set
+ * of data. Compared to the CRC-32 algorithm it trades reliabilty for speed.
+ * Refer to RFC 1950 for the specification.
+ *
+ * @see CRC32
+ * @since Android 1.0
+ */
+public class Adler32 implements java.util.zip.Checksum {
+
+ private long adler = 1;
+
+ /**
+ * Returns the {@code Adler32} checksum for all input received.
+ *
+ * @return The checksum for this instance.
+ * @since Android 1.0
+ */
+ public long getValue() {
+ return adler;
+ }
+
+ /**
+ * Reset this instance to its initial checksum.
+ *
+ * @since Android 1.0
+ */
+ public void reset() {
+ adler = 1;
+ }
+
+ /**
+ * Update this {@code Adler32} checksum with the single byte provided as
+ * argument.
+ *
+ * @param i
+ * the byte to update checksum with.
+ * @since Android 1.0
+ */
+ public void update(int i) {
+ adler = updateByteImpl(i, adler);
+ }
+
+ /**
+ * Update this {@code Adler32} checksum using the contents of {@code buf}.
+ *
+ * @param buf
+ * bytes to update checksum with.
+ * @since Android 1.0
+ */
+ public void update(byte[] buf) {
+ update(buf, 0, buf.length);
+ }
+
+ /**
+ * Update this {@code Adler32} checksum with the contents of {@code buf},
+ * starting from the offset provided and reading n bytes of data.
+ *
+ * @param buf
+ * buffer to obtain data from.
+ * @param off
+ * offset in {@code buf} to start reading from.
+ * @param nbytes
+ * number of bytes from {@code buf} to use.
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code offset > buf.length} or {@code nbytes} is negative
+ * or {@code offset + nbytes > buf.length}.
+ * @since Android 1.0
+ */
+ public void update(byte[] buf, int off, int nbytes) {
+ // avoid int overflow, check null buf
+ if (off <= buf.length && nbytes >= 0 && off >= 0
+ && buf.length - off >= nbytes) {
+ adler = updateImpl(buf, off, nbytes, adler);
+ } else {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ private native long updateImpl(byte[] buf, int off, int nbytes, long adler1);
+
+ private native long updateByteImpl(int val, long adler1);
+}
diff --git a/archive/src/main/java/java/util/zip/CRC32.java b/archive/src/main/java/java/util/zip/CRC32.java
new file mode 100644
index 0000000..36dc376
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/CRC32.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+/**
+ * The CRC32 class is used to compute a CRC32 checksum from data provided as
+ * input value.
+ *
+ * @since Android 1.0
+ */
+public class CRC32 implements java.util.zip.Checksum {
+
+ private long crc = 0L;
+
+ long tbytes = 0L;
+
+ /**
+ * Returns the CRC32 checksum for all input received.
+ *
+ * @return The checksum for this instance.
+ * @since Android 1.0
+ */
+ public long getValue() {
+ return crc;
+ }
+
+ /**
+ * Resets the CRC32 checksum to it initial state.
+ *
+ * @since Android 1.0
+ */
+ public void reset() {
+ tbytes = crc = 0;
+
+ }
+
+ /**
+ * Updates this checksum with the byte value provided as integer.
+ *
+ * @param val
+ * represents the byte to update the checksum.
+ * @since Android 1.0
+ */
+ public void update(int val) {
+ crc = updateByteImpl((byte) val, crc);
+ }
+
+ /**
+ * Updates this checksum with the bytes contained in buffer {@code buf}.
+ *
+ * @param buf
+ * the buffer holding the data to update the checksum with.
+ * @since Android 1.0
+ */
+ public void update(byte[] buf) {
+ update(buf, 0, buf.length);
+ }
+
+ /**
+ * Updates this checksum with n bytes of data obtained from buffer {@code
+ * buf}, starting at offset {@code off}.
+ *
+ * @param buf
+ * the buffer to update the checksum.
+ * @param off
+ * the offset in {@code buf} to obtain data from.
+ * @param nbytes
+ * the number of bytes to read from {@code buf}.
+ * @since Android 1.0
+ */
+ public void update(byte[] buf, int off, int nbytes) {
+ // avoid int overflow, check null buf
+ if (off <= buf.length && nbytes >= 0 && off >= 0
+ && buf.length - off >= nbytes) {
+ tbytes += nbytes;
+ crc = updateImpl(buf, off, nbytes, crc);
+ } else {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ private native long updateImpl(byte[] buf, int off, int nbytes, long crc1);
+
+ private native long updateByteImpl(byte val, long crc1);
+}
diff --git a/archive/src/main/java/java/util/zip/CheckedInputStream.java b/archive/src/main/java/java/util/zip/CheckedInputStream.java
new file mode 100644
index 0000000..659125a
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/CheckedInputStream.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * The {@code CheckedInputStream} class is used to maintain a checksum at the
+ * same time as the data, on which the checksum is computed, is read from a
+ * stream. The purpose of this checksum is to establish data integrity,
+ * comparing the computed checksum against a published checksum value.
+ *
+ * @since Android 1.0
+ */
+public class CheckedInputStream extends java.io.FilterInputStream {
+
+ private final Checksum check;
+
+ /**
+ * Constructs a new {@code CheckedInputStream} on {@code InputStream}
+ * {@code is}. The checksum will be calculated using the algorithm
+ * implemented by {@code csum}.
+ *
+ * @param is
+ * the input stream to calculate checksum from.
+ * @param csum
+ * an entity implementing the checksum algorithm.
+ * @since Android 1.0
+ */
+ public CheckedInputStream(InputStream is, Checksum csum) {
+ super(is);
+ check = csum;
+ }
+
+ /**
+ * Reads one byte of data from the underlying input stream and updates the
+ * checksum with the byte data.
+ *
+ * @return {@code -1} at the end of the stream, a single byte value
+ * otherwise.
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public int read() throws IOException {
+ int x = in.read();
+ if (x != -1) {
+ check.update(x);
+ }
+ return x;
+ }
+
+ /**
+ * Reads up to n bytes of data from the underlying input stream, storing it
+ * into {@code buf}, starting at offset {@code off}. The checksum is
+ * updated with the bytes read.
+ *
+ * @param buf
+ * the byte array in which to store the bytes read.
+ * @param off
+ * the initial position in {@code buf} to store the bytes read
+ * from this stream.
+ * @param nbytes
+ * the maximum number of bytes to store in {@code buf}.
+ * @return the number of bytes actually read or {@code -1} if arrived at the
+ * end of the filtered stream while reading the data.
+ * @throws IOException
+ * if this stream is closed or some I/O error occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public int read(byte[] buf, int off, int nbytes) throws IOException {
+ int x = in.read(buf, off, nbytes);
+ if (x != -1) {
+ check.update(buf, off, x);
+ }
+ return x;
+ }
+
+ /**
+ * Returns the checksum calculated on the stream read so far.
+ *
+ * @return the updated checksum.
+ * @since Android 1.0
+ */
+ public Checksum getChecksum() {
+ return check;
+ }
+
+ /**
+ * Skip up to n bytes of data on the underlying input stream. Any skipped
+ * bytes are added to the running checksum value.
+ *
+ * @param nbytes
+ * the number of bytes to skip.
+ * @throws IOException
+ * if this stream is closed or another I/O error occurs.
+ * @return the number of bytes skipped.
+ * @since Android 1.0
+ */
+ @Override
+ public long skip(long nbytes) throws IOException {
+ if (nbytes < 1) {
+ return 0;
+ }
+ long skipped = 0;
+ byte[] b = new byte[2048];
+ int x, v;
+ while (skipped != nbytes) {
+ x = in.read(b, 0,
+ (v = (int) (nbytes - skipped)) > b.length ? b.length : v);
+ if (x == -1) {
+ return skipped;
+ }
+ check.update(b, 0, x);
+ skipped += x;
+ }
+ return skipped;
+ }
+}
diff --git a/archive/src/main/java/java/util/zip/CheckedOutputStream.java b/archive/src/main/java/java/util/zip/CheckedOutputStream.java
new file mode 100644
index 0000000..9699492
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/CheckedOutputStream.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * The {@code CheckedOutputStream} class is used to maintain a running checksum
+ * of all data written to a stream. The purpose of this checksum is to establish
+ * data integrity, by publishing the checksum to other parties wanting to read
+ * the non corrupted data.
+ *
+ * @since Android 1.0
+ */
+public class CheckedOutputStream extends java.io.FilterOutputStream {
+
+ private final Checksum check;
+
+ /**
+ * Constructs a new {@code CheckedOutputStream} on {@code OutputStream}
+ * {@code os}. The checksum is calculated using the algorithm implemented
+ * by {@code csum}.
+ *
+ * @param os
+ * the output stream to calculate checksum for.
+ * @param cs
+ * an entity implementing the checksum algorithm.
+ * @since Android 1.0
+ */
+ public CheckedOutputStream(OutputStream os, Checksum cs) {
+ super(os);
+ check = cs;
+ }
+
+ /**
+ * Returns the checksum calculated on the stream read so far.
+ *
+ * @return the updated checksum.
+ * @since Android 1.0
+ */
+ public Checksum getChecksum() {
+ return check;
+ }
+
+ /**
+ * Writes the specified byte to the underlying stream. The checksum is
+ * updated with {@code val}.
+ *
+ * @param val
+ * the data value to written to the output stream.
+ * @throws IOException
+ * if an IO error has occurred.
+ * @since Android 1.0
+ */
+ @Override
+ public void write(int val) throws IOException {
+ out.write(val);
+ check.update(val);
+ }
+
+ /**
+ * Writes n bytes of data from {@code buf} starting at offset {@code off} to
+ * the underlying stream. The checksum is updated with the bytes written.
+ *
+ * @param buf
+ * data written to the output stream.
+ * @param off
+ * the offset to start reading the data from {@code buf} written
+ * to the output stream.
+ * @param nbytes
+ * number of bytes to write to the output stream.
+ * @throws IOException
+ * if an IO error has occurred.
+ * @since Android 1.0
+ */
+ @Override
+ public void write(byte[] buf, int off, int nbytes) throws IOException {
+ out.write(buf, off, nbytes);
+ check.update(buf, off, nbytes);
+ }
+}
diff --git a/archive/src/main/java/java/util/zip/Checksum.java b/archive/src/main/java/java/util/zip/Checksum.java
new file mode 100644
index 0000000..0405c08
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/Checksum.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+/**
+ * Holds information about a checksum which was computed with the methods
+ * implementing a checksum algorithm.
+ *
+ * @since Android 1.0
+ */
+public interface Checksum {
+
+ /**
+ * Returns the current calculated checksum value.
+ *
+ * @return the checksum.
+ * @since Android 1.0
+ */
+ public long getValue();
+
+ /**
+ * Resets the checksum value applied before beginning calculations on a new
+ * stream of data.
+ *
+ * @since Android 1.0
+ */
+ public void reset();
+
+ /**
+ * Updates the checksum value with the given byte.
+ *
+ * @param val
+ * the byte to update the checksum with.
+ * @since Android 1.0
+ */
+ public void update(int val);
+
+ /**
+ * Updates the checksum with the given bytes.
+ *
+ * @param buf
+ * the byte array from which to read the bytes.
+ * @param off
+ * the initial position in {@code buf} to read the bytes from.
+ * @param nbytes
+ * the number of bytes to read from {@code buf}.
+ * @since Android 1.0
+ */
+ public void update(byte[] buf, int off, int nbytes);
+}
diff --git a/archive/src/main/java/java/util/zip/DataFormatException.java b/archive/src/main/java/java/util/zip/DataFormatException.java
new file mode 100644
index 0000000..9ffe2ab
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/DataFormatException.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+/**
+ * {@code DataFormatException} is used to indicate an error in the format of a
+ * particular data stream which is to be uncompressed.
+ *
+ * @since Android 1.0
+ */
+public class DataFormatException extends Exception {
+
+ private static final long serialVersionUID = 2219632870893641452L;
+
+ /**
+ * Constructs a new {@code DataFormatException} instance.
+ *
+ * @since Android 1.0
+ */
+ public DataFormatException() {
+ super();
+ }
+
+ /**
+ * Constructs a new {@code DataFormatException} instance with the specified
+ * message.
+ *
+ * @param detailMessage
+ * the detail message for the exception.
+ * @since Android 1.0
+ */
+ public DataFormatException(String detailMessage) {
+ super(detailMessage);
+ }
+}
diff --git a/archive/src/main/java/java/util/zip/Deflater.java b/archive/src/main/java/java/util/zip/Deflater.java
new file mode 100644
index 0000000..f91f1ca
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/Deflater.java
@@ -0,0 +1,533 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+/**
+ * This class compresses data using the <i>DEFLATE</i> algorithm (see <a
+ * href="http://www.gzip.org/algorithm.txt">specification</a>).
+ * <p>
+ * Basically this class is part of the API to the stream based ZLIB compression
+ * library and is used as such by {@code DeflaterOutputStream} and its
+ * descendants.
+ * </p>
+ * <p>
+ * The typical usage of a {@code Deflater} instance outside this package
+ * consists of a specific call to one of its constructors before being passed to
+ * an instance of {@code DeflaterOutputStream}.
+ * </p>
+ *
+ * @see DeflaterOutputStream
+ * @see Inflater
+ * @since Android 1.0
+ */
+public class Deflater {
+
+ /**
+ * Upper bound for the compression level range.
+ *
+ * @since Android 1.0
+ */
+ public static final int BEST_COMPRESSION = 9;
+
+ /**
+ * Lower bound for compression level range.
+ *
+ * @since Android 1.0
+ */
+ public static final int BEST_SPEED = 1;
+
+ /**
+ * Usage of the default compression level.
+ *
+ * @since Android 1.0
+ */
+ public static final int DEFAULT_COMPRESSION = -1;
+
+ /**
+ * Default value for compression strategy.
+ *
+ * @since Android 1.0
+ */
+ public static final int DEFAULT_STRATEGY = 0;
+
+ /**
+ * Default value for compression method.
+ *
+ * @since Android 1.0
+ */
+ public static final int DEFLATED = 8;
+
+ /**
+ * Possible value for compression strategy.
+ *
+ * @since Android 1.0
+ */
+ public static final int FILTERED = 1;
+
+ /**
+ * Possible value for compression strategy.
+ *
+ * @since Android 1.0
+ */
+ public static final int HUFFMAN_ONLY = 2;
+
+ /**
+ * Possible value for compression level.
+ *
+ * @since Android 1.0
+ */
+ public static final int NO_COMPRESSION = 0;
+
+ private static final int Z_NO_FLUSH = 0;
+
+ private static final int Z_FINISH = 4;
+
+ // Fill in the JNI id caches
+ private static native void oneTimeInitialization();
+
+ // A stub buffer used when deflate() called while inputBuffer has not been set.
+ private static final byte[] STUB_INPUT_BUFFER = new byte[0];
+
+ static {
+ oneTimeInitialization();
+ }
+
+ private int flushParm = Z_NO_FLUSH;
+
+ private boolean finished;
+
+ private int compressLevel = DEFAULT_COMPRESSION;
+
+ private int strategy = DEFAULT_STRATEGY;
+
+ private long streamHandle = -1;
+
+ private byte[] inputBuffer;
+
+ private int inRead;
+
+ private int inLength;
+
+ /**
+ * Constructs a new {@code Deflater} instance with default compression
+ * level. The strategy can be specified with {@link #setStrategy}, only. A
+ * header is added to the output by default; use constructor {@code
+ * Deflater(level, boolean)} if you need to omit the header.
+ *
+ * @since Android 1.0
+ */
+ public Deflater() {
+ this(DEFAULT_COMPRESSION, false);
+ }
+
+ /**
+ * Constructs a new {@code Deflater} instance with a specific compression
+ * level. The strategy can be specified with {@code setStrategy}, only. A
+ * header is added to the output by default; use
+ * {@code Deflater(level, boolean)} if you need to omit the header.
+ *
+ * @param level
+ * the compression level in the range between 0 and 9.
+ * @since Android 1.0
+ */
+ public Deflater(int level) {
+ this(level, false);
+ }
+
+ /**
+ * Constructs a new {@code Deflater} instance with a specific compression
+ * level. If noHeader is passed as true no ZLib header is added to the
+ * output. In a ZIP archive every entry (compressed file) comes with such a
+ * header. The strategy can be specified with the setStrategy method, only.
+ *
+ * @param level
+ * the compression level in the range between 0 and 9.
+ * @param noHeader
+ * {@code true} indicates that no ZLIB header should be written.
+ * @since Android 1.0
+ */
+ public Deflater(int level, boolean noHeader) {
+ super();
+ if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
+ throw new IllegalArgumentException();
+ }
+ compressLevel = level;
+ streamHandle = createStream(compressLevel, strategy, noHeader);
+ }
+
+ /**
+ * Deflates the data (previously passed to {@code setInput}) into the
+ * supplied buffer.
+ *
+ * @param buf
+ * buffer to write compressed data to.
+ * @return number of bytes of compressed data written to {@code buf}.
+ * @see #deflate(byte[], int, int)
+ * @since Android 1.0
+ */
+ public int deflate(byte[] buf) {
+ return deflate(buf, 0, buf.length);
+ }
+
+ /**
+ * Deflates data (previously passed to {@code setInput}) into a specific
+ * region within the supplied buffer.
+ *
+ * @param buf
+ * the buffer to write compressed data to.
+ * @param off
+ * the offset within {@code buf} at which to start writing to.
+ * @param nbytes
+ * maximum number of bytes of compressed data to be written.
+ * @return the number of bytes of compressed data written to {@code buf}.
+ * @since Android 1.0
+ */
+ public synchronized int deflate(byte[] buf, int off, int nbytes) {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+ // avoid int overflow, check null buf
+ if (off <= buf.length && nbytes >= 0 && off >= 0
+ && buf.length - off >= nbytes) {
+ // put a stub buffer, no effect.
+ if (null == inputBuffer) {
+ setInput(STUB_INPUT_BUFFER);
+ }
+ return deflateImpl(buf, off, nbytes, streamHandle, flushParm);
+ }
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ private synchronized native int deflateImpl(byte[] buf, int off,
+ int nbytes, long handle, int flushParm1);
+
+ private synchronized native void endImpl(long handle);
+
+ /**
+ * Frees all resources held onto by this deflating algorithm. Any unused
+ * input or output is discarded. While this method is used by {@code
+ * finalize()}, it can be called explicitly in order to free native
+ * resources before the next GC cycle. After {@code end()} was called other
+ * methods will typically throw an {@code IllegalStateException}.
+ *
+ * @since Android 1.0
+ */
+ public synchronized void end() {
+ if (streamHandle != -1) {
+ endImpl(streamHandle);
+ inputBuffer = null;
+ streamHandle = -1;
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ end();
+ }
+
+ /**
+ * Indicates to the {@code Deflater} that all uncompressed input has been provided
+ * to it.
+ *
+ * @see #finished
+ * @since Android 1.0
+ */
+ public synchronized void finish() {
+ flushParm = Z_FINISH;
+ }
+
+ /**
+ * Returns whether or not all provided data has been successfully
+ * compressed.
+ *
+ * @return true if all data has been compressed, false otherwise.
+ * @since Android 1.0
+ */
+ public synchronized boolean finished() {
+ return finished;
+ }
+
+ /**
+ * Returns the Adler32 checksum of uncompressed data currently read. If a
+ * preset dictionary is used getAdler() will return the Adler32 checksum of
+ * the dictionary used.
+ *
+ * @return the Adler32 checksum of uncompressed data or preset dictionary if
+ * used.
+ * @see #setDictionary(byte[])
+ * @see #setDictionary(byte[], int, int)
+ * @since Android 1.0
+ */
+ public synchronized int getAdler() {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+
+ return getAdlerImpl(streamHandle);
+ }
+
+ private synchronized native int getAdlerImpl(long handle);
+
+ /**
+ * Returns the total number of bytes of input consumed by the {@code Deflater}.
+ *
+ * @return number of bytes of input read.
+ * @since Android 1.0
+ */
+ public synchronized int getTotalIn() {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+
+ return (int)getTotalInImpl(streamHandle);
+ }
+
+ private synchronized native long getTotalInImpl(long handle);
+
+ /**
+ * Returns the total number of compressed bytes output by this {@code Deflater}.
+ *
+ * @return number of compressed bytes output.
+ * @since Android 1.0
+ */
+ public synchronized int getTotalOut() {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+
+ return (int)getTotalOutImpl(streamHandle);
+ }
+
+ private synchronized native long getTotalOutImpl(long handle);
+
+ /**
+ * Counterpart to setInput(). Indicates whether or not all bytes of
+ * uncompressed input have been consumed by the {@code Deflater}. If needsInput()
+ * returns true setInput() must be called before deflation can continue. If
+ * all bytes of uncompressed data have been provided to the {@code Deflater}
+ * finish() must be called to ensure the compressed data is output.
+ *
+ * @return {@code true} if input is required for deflation to continue,
+ * {@code false} otherwise.
+ * @see #finished()
+ * @see #setInput(byte[])
+ * @see #setInput(byte[], int, int)
+ * @since Android 1.0
+ */
+ public synchronized boolean needsInput() {
+ if (inputBuffer == null) {
+ return true;
+ }
+ return inRead == inLength;
+ }
+
+ /**
+ * Resets the {@code Deflater} to accept new input without affecting any
+ * previously made settings for the compression strategy or level. This
+ * operation <i>must</i> be called after {@code finished()} returns
+ * {@code true} if the {@code Deflater} is to be reused.
+ *
+ * @see #finished
+ * @since Android 1.0
+ */
+ public synchronized void reset() {
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+
+ flushParm = Z_NO_FLUSH;
+ finished = false;
+ resetImpl(streamHandle);
+ inputBuffer = null;
+ }
+
+ private synchronized native void resetImpl(long handle);
+
+ /**
+ * Sets the dictionary to be used for compression by this {@code Deflater}.
+ * setDictionary() can only be called if this {@code Deflater} supports the writing
+ * of ZLIB headers. This is the default behaviour but can be overridden
+ * using {@code Deflater(int, boolean)}.
+ *
+ * @param buf
+ * the buffer containing the dictionary data bytes.
+ * @see Deflater#Deflater(int, boolean)
+ * @since Android 1.0
+ */
+ public void setDictionary(byte[] buf) {
+ setDictionary(buf, 0, buf.length);
+ }
+
+ /**
+ * Sets the dictionary to be used for compression by this {@code Deflater}.
+ * setDictionary() can only be called if this {@code Deflater} supports the writing
+ * of ZLIB headers. This is the default behaviour but can be overridden
+ * using {@code Deflater(int, boolean)}.
+ *
+ * @param buf
+ * the buffer containing the dictionary data bytes.
+ * @param off
+ * the offset of the data.
+ * @param nbytes
+ * the length of the data.
+ * @see Deflater#Deflater(int, boolean)
+ * @since Android 1.0
+ */
+ public synchronized void setDictionary(byte[] buf, int off, int nbytes) {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+ // avoid int overflow, check null buf
+ if (off <= buf.length && nbytes >= 0 && off >= 0
+ && buf.length - off >= nbytes) {
+ setDictionaryImpl(buf, off, nbytes, streamHandle);
+ } else {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ private synchronized native void setDictionaryImpl(byte[] buf, int off,
+ int nbytes, long handle);
+
+ /**
+ * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes
+ * for later compression.
+ *
+ * @param buf
+ * the buffer.
+ * @since Android 1.0
+ */
+ public void setInput(byte[] buf) {
+ setInput(buf, 0, buf.length);
+ }
+
+ /**
+ * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes
+ * for later compression. Input will be taken from the buffer region
+ * starting at off and ending at nbytes - 1.
+ *
+ * @param buf
+ * the buffer containing the input data bytes.
+ * @param off
+ * the offset of the data.
+ * @param nbytes
+ * the length of the data.
+ * @since Android 1.0
+ */
+ public synchronized void setInput(byte[] buf, int off, int nbytes) {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+ // avoid int overflow, check null buf
+ if (off <= buf.length && nbytes >= 0 && off >= 0
+ && buf.length - off >= nbytes) {
+ inLength = nbytes;
+ inRead = 0;
+ if (inputBuffer == null) {
+ setLevelsImpl(compressLevel, strategy, streamHandle);
+ }
+ inputBuffer = buf;
+ setInputImpl(buf, off, nbytes, streamHandle);
+ } else {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ private synchronized native void setLevelsImpl(int level, int strategy,
+ long handle);
+
+ private synchronized native void setInputImpl(byte[] buf, int off,
+ int nbytes, long handle);
+
+ /**
+ * Sets the compression level to be used when compressing data. The
+ * compression level must be a value between 0 and 9. This value must be set
+ * prior to calling setInput().
+ *
+ * @param level
+ * compression level to use
+ * @exception IllegalArgumentException
+ * If the compression level is invalid.
+ * @since Android 1.0
+ */
+ public synchronized void setLevel(int level) {
+ if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
+ throw new IllegalArgumentException();
+ }
+ if (inputBuffer != null) {
+ throw new IllegalStateException();
+ }
+ compressLevel = level;
+ }
+
+ /**
+ * Sets the compression strategy to be used. The strategy must be one of
+ * FILTERED, HUFFMAN_ONLY or DEFAULT_STRATEGY.This value must be set prior
+ * to calling setInput().
+ *
+ * @param strategy
+ * compression strategy to use
+ * @exception IllegalArgumentException
+ * If the strategy specified is not one of FILTERED,
+ * HUFFMAN_ONLY or DEFAULT_STRATEGY.
+ * @since Android 1.0
+ */
+ public synchronized void setStrategy(int strategy) {
+ if (strategy < DEFAULT_STRATEGY || strategy > HUFFMAN_ONLY) {
+ throw new IllegalArgumentException();
+ }
+ if (inputBuffer != null) {
+ throw new IllegalStateException();
+ }
+ this.strategy = strategy;
+ }
+
+ /**
+ * Returns a long int of total number of bytes read by the {@code Deflater}. This
+ * method performs the same as {@code getTotalIn} except it returns a long value
+ * instead of an integer
+ *
+ * @return total number of bytes read by {@code Deflater}.
+ * @since Android 1.0
+ */
+ public synchronized long getBytesRead() {
+ // Throw NPE here
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+ return getTotalInImpl(streamHandle);
+ }
+
+ /**
+ * Returns a long int of total number of bytes of read by the {@code Deflater}. This
+ * method performs the same as {@code getTotalOut} except it returns a long
+ * value instead of an integer
+ *
+ * @return bytes exactly write by {@code Deflater}
+ * @since Android 1.0
+ */
+ public synchronized long getBytesWritten() {
+ // Throw NPE here
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+ return getTotalOutImpl(streamHandle);
+ }
+
+ private native long createStream(int level, int strategy1, boolean noHeader1);
+}
diff --git a/archive/src/main/java/java/util/zip/DeflaterOutputStream.java b/archive/src/main/java/java/util/zip/DeflaterOutputStream.java
new file mode 100644
index 0000000..773e4c4
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/DeflaterOutputStream.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.harmony.archive.internal.nls.Messages;
+
+/**
+ * This class provides an implementation of {@code FilterOutputStream} that
+ * compresses data using the <i>DEFLATE</i> algorithm. Basically it wraps the
+ * {@code Deflater} class and takes care of the buffering.
+ *
+ * @see Deflater
+ * @since Android 1.0
+ */
+public class DeflaterOutputStream extends FilterOutputStream {
+ static final int BUF_SIZE = 512;
+
+ /**
+ * The buffer for the data to be written to.
+ *
+ * @since Android 1.0
+ */
+ protected byte[] buf;
+
+ /**
+ * The deflater used.
+ *
+ * @since Android 1.0
+ */
+ protected Deflater def;
+
+ boolean done = false;
+
+ /**
+ * This constructor lets you pass the {@code Deflater} specifying the
+ * compression algorithm.
+ *
+ * @param os
+ * is the {@code OutputStream} where to write the compressed data
+ * to.
+ * @param def
+ * is the specific {@code Deflater} that is used to compress
+ * data.
+ * @since Android 1.0
+ */
+ public DeflaterOutputStream(OutputStream os, Deflater def) {
+ this(os, def, BUF_SIZE);
+ }
+
+ /**
+ * This is the most basic constructor. You only need to pass the {@code
+ * OutputStream} to which the compressed data shall be written to. The
+ * default settings for the {@code Deflater} and internal buffer are used.
+ * In particular the {@code Deflater} produces a ZLIB header in the output
+ * stream.
+ *
+ * @param os
+ * is the OutputStream where to write the compressed data to.
+ * @since Android 1.0
+ */
+ public DeflaterOutputStream(OutputStream os) {
+ this(os, new Deflater());
+ }
+
+ /**
+ * This constructor lets you specify both the compression algorithm as well
+ * as the internal buffer size to be used.
+ *
+ * @param os
+ * is the {@code OutputStream} where to write the compressed data
+ * to.
+ * @param def
+ * is the specific {@code Deflater} that will be used to compress
+ * data.
+ * @param bsize
+ * is the size to be used for the internal buffer.
+ * @since Android 1.0
+ */
+ public DeflaterOutputStream(OutputStream os, Deflater def, int bsize) {
+ super(os);
+ if (os == null || def == null) {
+ throw new NullPointerException();
+ }
+ if (bsize <= 0) {
+ throw new IllegalArgumentException();
+ }
+ this.def = def;
+ buf = new byte[bsize];
+ }
+
+ /**
+ * Compress the data in the input buffer and write it to the underlying
+ * stream.
+ *
+ * @throws IOException
+ * If an error occurs during deflation.
+ * @since Android 1.0
+ */
+ protected void deflate() throws IOException {
+ int x = 0;
+ do {
+ x = def.deflate(buf);
+ out.write(buf, 0, x);
+ } while (!def.needsInput());
+ }
+
+ /**
+ * Writes any unwritten compressed data to the underlying stream, the closes
+ * all underlying streams. This stream can no longer be used after close()
+ * has been called.
+ *
+ * @throws IOException
+ * If an error occurs while closing the data compression
+ * process.
+ * @since Android 1.0
+ */
+ @Override
+ public void close() throws IOException {
+ if (!def.finished()) {
+ finish();
+ }
+ def.end();
+ out.close();
+ }
+
+ /**
+ * Writes any unwritten data to the underlying stream. Does not close the
+ * stream.
+ *
+ * @throws IOException
+ * If an error occurs.
+ * @since Android 1.0
+ */
+ public void finish() throws IOException {
+ if (done) {
+ return;
+ }
+ def.finish();
+ int x = 0;
+ while (!def.finished()) {
+ if (def.needsInput()) {
+ def.setInput(buf, 0, 0);
+ }
+ x = def.deflate(buf);
+ out.write(buf, 0, x);
+ }
+ done = true;
+ }
+
+ @Override
+ public void write(int i) throws IOException {
+ byte[] b = new byte[1];
+ b[0] = (byte) i;
+ write(b, 0, 1);
+ }
+
+ /**
+ * Compresses {@code nbytes} of data from {@code buf} starting at
+ * {@code off} and writes it to the underlying stream.
+ *
+ * @param buffer
+ * the buffer of data to compress.
+ * @param off
+ * offset in buffer to extract data from.
+ * @param nbytes
+ * the number of bytes of data to read from the buffer.
+ * @throws IOException
+ * If an error occurs during writing.
+ * @since Android 1.0
+ */
+ @Override
+ public void write(byte[] buffer, int off, int nbytes) throws IOException {
+ if (done) {
+ throw new IOException(Messages.getString("archive.26")); //$NON-NLS-1$
+ }
+ // avoid int overflow, check null buf
+ if (off <= buffer.length && nbytes >= 0 && off >= 0
+ && buffer.length - off >= nbytes) {
+ if (!def.needsInput()) {
+ throw new IOException();
+ }
+ def.setInput(buffer, off, nbytes);
+ deflate();
+ } else {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+}
diff --git a/archive/src/main/java/java/util/zip/GZIPInputStream.java b/archive/src/main/java/java/util/zip/GZIPInputStream.java
new file mode 100644
index 0000000..fc70d62
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/GZIPInputStream.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.harmony.archive.internal.nls.Messages;
+
+/**
+ * The {@code GZIPInputStream} class is used to read data stored in the GZIP
+ * format, reading and decompressing GZIP data from the underlying stream into
+ * its buffer.
+ *
+ * @since Android 1.0
+ */
+public class GZIPInputStream extends java.util.zip.InflaterInputStream {
+
+ /**
+ * The checksum algorithm used when handling uncompressed data.
+ *
+ * @since Android 1.0
+ */
+ protected CRC32 crc = new CRC32();
+
+ /**
+ * Indicates the end of the input stream.
+ *
+ * @since Android 1.0
+ */
+ protected boolean eos = false;
+
+ /**
+ * The magic header for the GZIP format.
+ *
+ * @since Android 1.0
+ */
+ public final static int GZIP_MAGIC = 0x8b1f;
+
+ private static final int FHCRC = 2;
+
+ private static final int FEXTRA = 4;
+
+ private static final int FNAME = 8;
+
+ private static final int FCOMMENT = 16;
+
+ /**
+ * Construct a {@code GZIPInputStream} to read from GZIP data from the
+ * underlying stream.
+ *
+ * @param is
+ * the {@code InputStream} to read data from.
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ public GZIPInputStream(InputStream is) throws IOException {
+ this(is, BUF_SIZE);
+ }
+
+ /**
+ * Construct a {@code GZIPInputStream} to read from GZIP data from the
+ * underlying stream. Set the internal buffer size to {@code size}.
+ *
+ * @param is
+ * the {@code InputStream} to read data from.
+ * @param size
+ * the internal read buffer size.
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ public GZIPInputStream(InputStream is, int size) throws IOException {
+ super(is, new Inflater(true), size);
+ byte[] header = new byte[10];
+ readFully(header, 0, header.length);
+ if (getShort(header, 0) != GZIP_MAGIC) {
+ throw new IOException(Messages.getString("archive.1F")); //$NON-NLS-1$;
+ }
+ int flags = header[3];
+ boolean hcrc = (flags & FHCRC) != 0;
+ if (hcrc) {
+ crc.update(header, 0, header.length);
+ }
+ if ((flags & FEXTRA) != 0) {
+ readFully(header, 0, 2);
+ if (hcrc) {
+ crc.update(header, 0, 2);
+ }
+ int length = getShort(header, 0);
+ while (length > 0) {
+ int max = length > buf.length ? buf.length : length;
+ int result = in.read(buf, 0, max);
+ if (result == -1) {
+ throw new EOFException();
+ }
+ if (hcrc) {
+ crc.update(buf, 0, result);
+ }
+ length -= result;
+ }
+ }
+ if ((flags & FNAME) != 0) {
+ readZeroTerminated(hcrc);
+ }
+ if ((flags & FCOMMENT) != 0) {
+ readZeroTerminated(hcrc);
+ }
+ if (hcrc) {
+ readFully(header, 0, 2);
+ int crc16 = getShort(header, 0);
+ if ((crc.getValue() & 0xffff) != crc16) {
+ throw new IOException(Messages.getString("archive.20")); //$NON-NLS-1$
+ }
+ crc.reset();
+ }
+ }
+
+ private long getLong(byte[] buffer, int off) {
+ long l = 0;
+ l |= (buffer[off] & 0xFF);
+ l |= (buffer[off + 1] & 0xFF) << 8;
+ l |= (buffer[off + 2] & 0xFF) << 16;
+ l |= ((long) (buffer[off + 3] & 0xFF)) << 24;
+ return l;
+ }
+
+ private int getShort(byte[] buffer, int off) {
+ return (buffer[off] & 0xFF) | ((buffer[off + 1] & 0xFF) << 8);
+ }
+
+ @Override
+ public int read(byte[] buffer, int off, int nbytes) throws IOException {
+ if (closed) {
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+ if(eof){
+ return -1;
+ }
+ // avoid int overflow, check null buffer
+ if (off <= buffer.length && nbytes >= 0 && off >= 0
+ && buffer.length - off >= nbytes) {
+ int val = super.read(buffer, off, nbytes);
+ if (val != -1) {
+ crc.update(buffer, off, val);
+ } else if (!eos) {
+ eos = true;
+ // Get non-compressed bytes read by fill
+ // BEGIN android-changed
+ // copied from newer version of harmony
+ int size = inf.getRemaining();
+ final int trailerSize = 8; // crc (4 bytes) + total out (4
+ // bytes)
+ byte[] b = new byte[trailerSize];
+ int copySize = (size > trailerSize) ? trailerSize : size;
+
+ System.arraycopy(buf, len - size, b, 0, copySize);
+ readFully(b, copySize, trailerSize - copySize);
+ // END android-changed
+ if (getLong(b, 0) != crc.getValue()) {
+ throw new IOException(Messages.getString("archive.20")); //$NON-NLS-1$
+ }
+ if ((int) getLong(b, 4) != inf.getTotalOut()) {
+ throw new IOException(Messages.getString("archive.21")); //$NON-NLS-1$
+ }
+ }
+ return val;
+ }
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ @Override
+ public void close() throws IOException {
+ eos = true;
+ super.close();
+ }
+
+ private void readFully(byte[] buffer, int offset, int length)
+ throws IOException {
+ int result;
+ while (length > 0) {
+ result = in.read(buffer, offset, length);
+ if (result == -1) {
+ throw new EOFException();
+ }
+ offset += result;
+ length -= result;
+ }
+ }
+
+ private void readZeroTerminated(boolean hcrc) throws IOException {
+ int result;
+ while ((result = in.read()) > 0) {
+ if (hcrc) {
+ crc.update(result);
+ }
+ }
+ if (result == -1) {
+ throw new EOFException();
+ }
+ // Add the zero
+ if (hcrc) {
+ crc.update(result);
+ }
+ }
+}
diff --git a/archive/src/main/java/java/util/zip/GZIPOutputStream.java b/archive/src/main/java/java/util/zip/GZIPOutputStream.java
new file mode 100644
index 0000000..fa41e19
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/GZIPOutputStream.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * The {@code GZIPOutputStream} class is used to write data to a stream in the
+ * GZIP storage format.
+ *
+ * @since Android 1.0
+ */
+public class GZIPOutputStream extends DeflaterOutputStream {
+
+ /**
+ * The checksum algorithm used when treating uncompressed data.
+ *
+ * @since Android 1.0
+ */
+ protected CRC32 crc = new CRC32();
+
+ /**
+ * Construct a new {@code GZIPOutputStream} to write data in GZIP format to
+ * the underlying stream.
+ *
+ * @param os
+ * the {@code OutputStream} to write data to.
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ public GZIPOutputStream(OutputStream os) throws IOException {
+ this(os, BUF_SIZE);
+ }
+
+ /**
+ * Construct a new {@code GZIPOutputStream} to write data in GZIP format to
+ * the underlying stream. Set the internal compression buffer to size
+ * {@code size}.
+ *
+ * @param os
+ * the {@code OutputStream} to write to.
+ * @param size
+ * the internal buffer size.
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ public GZIPOutputStream(OutputStream os, int size) throws IOException {
+ super(os, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size);
+ writeShort(GZIPInputStream.GZIP_MAGIC);
+ out.write(Deflater.DEFLATED);
+ out.write(0); // flags
+ writeLong(0); // mod time
+ out.write(0); // extra flags
+ out.write(0); // operating system
+ }
+
+ /**
+ * Indicates to the stream that all data has been written out, and any GZIP
+ * terminal data can now be written.
+ *
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public void finish() throws IOException {
+ super.finish();
+ writeLong(crc.getValue());
+ writeLong(crc.tbytes);
+ }
+
+ @Override
+ public void write(byte[] buffer, int off, int nbytes) throws IOException {
+ super.write(buffer, off, nbytes);
+ crc.update(buffer, off, nbytes);
+ }
+
+ private int writeShort(int i) throws IOException {
+ out.write(i & 0xFF);
+ out.write((i >> 8) & 0xFF);
+ return i;
+ }
+
+ private long writeLong(long i) throws IOException {
+ // Write out the long value as an unsigned int
+ out.write((int) (i & 0xFF));
+ out.write((int) (i >> 8) & 0xFF);
+ out.write((int) (i >> 16) & 0xFF);
+ out.write((int) (i >> 24) & 0xFF);
+ return i;
+ }
+}
diff --git a/archive/src/main/java/java/util/zip/Inflater.java b/archive/src/main/java/java/util/zip/Inflater.java
new file mode 100644
index 0000000..9b93e54
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/Inflater.java
@@ -0,0 +1,470 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+import org.apache.harmony.archive.internal.nls.Messages;
+
+// BEGIN android-added
+import java.io.FileDescriptor;
+// END android-added
+
+/**
+ * This class uncompresses data that was compressed using the <i>DEFLATE</i>
+ * algorithm (see <a href="http://www.gzip.org/algorithm.txt">specification</a>).
+ * <p>
+ * Basically this class is part of the API to the stream based ZLIB compression
+ * library and is used as such by {@code InflaterInputStream} and its
+ * descendants.
+ * </p>
+ * <p>
+ * The typical usage of a {@code Inflater} outside this package consists of a
+ * specific call to one of its constructors before being passed to an instance
+ * of {@code InflaterInputStream}.
+ * </p>
+ *
+ * @see InflaterInputStream
+ * @see Deflater
+ * @since Android 1.0
+ */
+public class Inflater {
+
+ private boolean finished; // Set by the inflateImpl native
+
+ private boolean needsDictionary; // Set by the inflateImpl native
+
+ private long streamHandle = -1;
+
+ int inRead;
+
+ int inLength;
+
+ // Fill in the JNI id caches
+ private static native void oneTimeInitialization();
+
+ static {
+ oneTimeInitialization();
+ }
+
+ private static final byte MAGIC_NUMBER = 120;
+ private boolean gotFirstByte = false;
+ private boolean pass_magic_number_check = true;
+
+ /**
+ * Release any resources associated with this {@code Inflater}. Any unused
+ * input/output is discarded. This is also called by the finalize method.
+ *
+ * @since Android 1.0
+ */
+ public synchronized void end() {
+ if (streamHandle != -1) {
+ endImpl(streamHandle);
+ inRead = 0;
+ inLength = 0;
+ streamHandle = -1;
+ }
+ }
+
+ private native synchronized void endImpl(long handle);
+
+ @Override
+ protected void finalize() {
+ end();
+ }
+
+ /**
+ * Indicates if the {@code Inflater} has inflated the entire deflated
+ * stream. If deflated bytes remain and {@code needsInput()} returns {@code
+ * true} this method will return {@code false}. This method should be
+ * called after all deflated input is supplied to the {@code Inflater}.
+ *
+ * @return {@code true} if all input has been inflated, {@code false}
+ * otherwise.
+ * @since Android 1.0
+ */
+ public synchronized boolean finished() {
+ return finished;
+ }
+
+ /**
+ * Returns the <i>Adler32</i> checksum of either all bytes inflated, or the
+ * checksum of the preset dictionary if one has been supplied.
+ *
+ * @return The <i>Adler32</i> checksum associated with this
+ * {@code Inflater}.
+ * @since Android 1.0 .
+ */
+ public synchronized int getAdler() {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+ return getAdlerImpl(streamHandle);
+ }
+
+ private native synchronized int getAdlerImpl(long handle);
+
+ /**
+ * Returns the number of bytes of current input remaining to be read by the
+ * inflater.
+ *
+ * @return the number of bytes of unread input.
+ * @since Android 1.0
+ */
+ public synchronized int getRemaining() {
+ return inLength - inRead;
+ }
+
+ /**
+ * Returns total number of bytes of input read by the {@code Inflater}. The
+ * result value is limited by {@code Integer.MAX_VALUE}.
+ *
+ * @return the total number of bytes read.
+ * @since Android 1.0
+ */
+ public synchronized int getTotalIn() {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+ long totalIn = getTotalInImpl(streamHandle);
+ return (totalIn <= Integer.MAX_VALUE ? (int) totalIn
+ : Integer.MAX_VALUE);
+ }
+
+ private synchronized native long getTotalInImpl(long handle);
+
+ /**
+ * Returns total number of bytes written to the output buffer by the {@code
+ * Inflater}. The result value is limited by {@code Integer.MAX_VALUE}.
+ *
+ * @return the total bytes of output data written.
+ * @since Android 1.0
+ */
+ public synchronized int getTotalOut() {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+ long totalOut = getTotalOutImpl(streamHandle);
+ return (totalOut <= Integer.MAX_VALUE ? (int) totalOut
+ : Integer.MAX_VALUE);
+ }
+
+ private native synchronized long getTotalOutImpl(long handle);
+
+ /**
+ * Inflates bytes from current input and stores them in {@code buf}.
+ *
+ * @param buf
+ * the buffer where decompressed data bytes are written.
+ * @return the number of bytes inflated.
+ * @throws DataFormatException
+ * if the underlying stream is corrupted or was not compressed
+ * using a {@code Deflater}.
+ * @since Android 1.0
+ */
+ public int inflate(byte[] buf) throws DataFormatException {
+ return inflate(buf, 0, buf.length);
+ }
+
+ /**
+ * Inflates up to n bytes from the current input and stores them in {@code
+ * buf} starting at {@code off}.
+ *
+ * @param buf
+ * the buffer to write inflated bytes to.
+ * @param off
+ * the offset in buffer where to start writing decompressed data.
+ * @param nbytes
+ * the number of inflated bytes to write to {@code buf}.
+ * @throws DataFormatException
+ * if the underlying stream is corrupted or was not compressed
+ * using a {@code Deflater}.
+ * @return the number of bytes inflated.
+ */
+ public synchronized int inflate(byte[] buf, int off, int nbytes)
+ throws DataFormatException {
+ // avoid int overflow, check null buf
+ if (off <= buf.length && nbytes >= 0 && off >= 0
+ && buf.length - off >= nbytes) {
+ if (nbytes == 0)
+ return 0;
+
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+
+ if (!pass_magic_number_check) {
+ throw new DataFormatException();
+ }
+
+ if (needsInput()) {
+ return 0;
+ }
+
+ boolean neededDict = needsDictionary;
+ needsDictionary = false;
+ int result = inflateImpl(buf, off, nbytes, streamHandle);
+ if (needsDictionary && neededDict) {
+ throw new DataFormatException(Messages.getString("archive.27")); //$NON-NLS-1$
+ }
+ return result;
+ }
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ private native synchronized int inflateImpl(byte[] buf, int off,
+ int nbytes, long handle);
+
+ /**
+ * This constructor creates an inflater that expects a header from the input
+ * stream. Use {@code Inflater(boolean)} if the input comes without a ZLIB
+ * header.
+ *
+ * @since Android 1.0
+ * @since Android 1.0
+ */
+ public Inflater() {
+ this(false);
+ }
+
+ /**
+ * This constructor allows to create an inflater that expects no header from
+ * the input stream.
+ *
+ * @param noHeader
+ * {@code true} indicates that no ZLIB header comes with the
+ * input.
+ * @since Android 1.0
+ */
+ public Inflater(boolean noHeader) {
+ streamHandle = createStream(noHeader);
+ }
+
+ /**
+ * Indicates whether the input bytes were compressed with a preset
+ * dictionary. This method should be called prior to {@code inflate()} to
+ * determine whether a dictionary is required. If so {@code setDictionary()}
+ * should be called with the appropriate dictionary prior to calling {@code
+ * inflate()}.
+ *
+ * @return {@code true} if a preset dictionary is required for inflation.
+ * @see #setDictionary(byte[])
+ * @see #setDictionary(byte[], int, int)
+ * @since Android 1.0
+ */
+ public synchronized boolean needsDictionary() {
+ return needsDictionary;
+ }
+
+ /**
+ * Indicates that input has to be passed to the inflater.
+ *
+ * @return {@code true} if {@code setInput} has to be called before
+ * inflation can proceed.
+ * @see #setInput(byte[])
+ * @since Android 1.0
+ */
+ public synchronized boolean needsInput() {
+ return inRead == inLength;
+ }
+
+ /**
+ * Resets the {@code Inflater}. Should be called prior to inflating a new
+ * set of data.
+ *
+ * @since Android 1.0
+ */
+ public synchronized void reset() {
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+ finished = false;
+ needsDictionary = false;
+ inLength = inRead = 0;
+ resetImpl(streamHandle);
+ }
+
+ private native synchronized void resetImpl(long handle);
+
+ /**
+ * Sets the preset dictionary to be used for inflation to {@code buf}.
+ * {@code needsDictionary()} can be called to determine whether the current
+ * input was deflated using a preset dictionary.
+ *
+ * @param buf
+ * The buffer containing the dictionary bytes.
+ * @see #needsDictionary
+ * @since Android 1.0
+ */
+ public synchronized void setDictionary(byte[] buf) {
+ setDictionary(buf, 0, buf.length);
+ }
+
+ /**
+ * Like {@code setDictionary(byte[])}, allowing to define a specific region
+ * inside {@code buf} to be used as a dictionary.
+ *
+ * @param buf
+ * the buffer containing the dictionary data bytes.
+ * @param off
+ * the offset of the data.
+ * @param nbytes
+ * the length of the data.
+ * @see #needsDictionary
+ * @since Android 1.0
+ */
+ public synchronized void setDictionary(byte[] buf, int off, int nbytes) {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+ // avoid int overflow, check null buf
+ if (off <= buf.length && nbytes >= 0 && off >= 0
+ && buf.length - off >= nbytes) {
+ setDictionaryImpl(buf, off, nbytes, streamHandle);
+ } else {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ private native synchronized void setDictionaryImpl(byte[] buf, int off,
+ int nbytes, long handle);
+
+ /**
+ * Sets the current input to to be decrompressed. This method should only be
+ * called if {@code needsInput()} returns {@code true}.
+ *
+ * @param buf
+ * the input buffer.
+ * @see #needsInput
+ * @since Android 1.0
+ */
+ public synchronized void setInput(byte[] buf) {
+ setInput(buf, 0, buf.length);
+ }
+
+ /**
+ * Sets the current input to the region of the input buffer starting at
+ * {@code off} and ending at {@code nbytes - 1} where data is written after
+ * decompression. This method should only be called if {@code needsInput()}
+ * returns {@code true}.
+ *
+ * @param buf
+ * the input buffer.
+ * @param off
+ * the offset to read from the input buffer.
+ * @param nbytes
+ * the number of bytes to read.
+ * @see #needsInput
+ * @since Android 1.0
+ */
+ public synchronized void setInput(byte[] buf, int off, int nbytes) {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+ // avoid int overflow, check null buf
+ if (off <= buf.length && nbytes >= 0 && off >= 0
+ && buf.length - off >= nbytes) {
+ inRead = 0;
+ inLength = nbytes;
+ setInputImpl(buf, off, nbytes, streamHandle);
+ } else {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ // BEGIN android-note
+ // Note: pass_magic_number_check is set to false when setInput is
+ // called for the first time and for a single byte.
+ // Since setInput is called only by InflaterInputStream.fill
+ // with an arbitrary byte len this check seems quite useless.
+ // FIXME: We should find out whether the first byte has to be the magic
+ // number in all cases and correct the check as well as place it
+ // in setFileInput accordingly.
+ // And at a first glance it doesn't look like the first byte has
+ // to be 120.
+ // END android-note
+ if(!gotFirstByte && nbytes>0)
+ {
+ pass_magic_number_check = (buf[off] == MAGIC_NUMBER || nbytes > 1);
+ gotFirstByte = true;
+ }
+ }
+
+ // BEGIN android-added
+ /**
+ * Sets the current input to the region within a file starting at {@code
+ * off} and ending at {@code nbytes - 1}. This method should only be called
+ * if {@code needsInput()} returns {@code true}.
+ *
+ * @param file
+ * the input file.
+ * @param off
+ * the offset to read from in buffer.
+ * @param nbytes
+ * the number of bytes to read.
+ * @see #needsInput
+ * @since Android 1.0
+ */
+ synchronized int setFileInput(FileDescriptor fd, long off, int nbytes) {
+ if (streamHandle == -1) {
+ throw new IllegalStateException();
+ }
+ inRead = 0;
+ inLength = setFileInputImpl(fd, off, nbytes, streamHandle);
+ return inLength;
+ }
+ // END android-added
+
+ /**
+ * Returns the total number of bytes read by the {@code Inflater}. This
+ * method performs the same as {@code getTotalIn()} except that it returns a
+ * {@code long} value instead of an integer.
+ *
+ * @return the total number of bytes read.
+ * @since Android 1.0
+ */
+ public synchronized long getBytesRead() {
+ // Throw NPE here
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+ return getTotalInImpl(streamHandle);
+ }
+
+ /**
+ * Returns a the total number of bytes read by the {@code Inflater}. This
+ * method performs the same as {@code getTotalOut} except it returns a
+ * {@code long} value instead of an integer.
+ *
+ * @return the total bytes written to the output buffer.
+ * @since Android 1.0
+ */
+ public synchronized long getBytesWritten() {
+ // Throw NPE here
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+ return getTotalOutImpl(streamHandle);
+ }
+
+ private native synchronized void setInputImpl(byte[] buf, int off,
+ int nbytes, long handle);
+
+ // BEGIN android-added
+ private native synchronized int setFileInputImpl(FileDescriptor fd, long off,
+ int nbytes, long handle);
+ // END android-added
+
+ private native long createStream(boolean noHeader1);
+}
diff --git a/archive/src/main/java/java/util/zip/InflaterInputStream.java b/archive/src/main/java/java/util/zip/InflaterInputStream.java
new file mode 100644
index 0000000..5d3bda0
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/InflaterInputStream.java
@@ -0,0 +1,353 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.harmony.archive.internal.nls.Messages;
+
+/**
+ * This class provides an implementation of {@code FilterInputStream} that
+ * uncompresses data that was compressed using the <i>DEFLATE</i> algorithm
+ * (see <a href="http://www.gzip.org/algorithm.txt">specification</a>).
+ * Basically it wraps the {@code Inflater} class and takes care of the
+ * buffering.
+ *
+ * @see Inflater
+ * @see DeflaterOutputStream
+ * @since Android 1.0
+ */
+public class InflaterInputStream extends FilterInputStream {
+
+ /**
+ * The inflater used for this stream.
+ *
+ * @since Android 1.0
+ */
+ protected Inflater inf;
+
+ /**
+ * The input buffer used for decompression.
+ *
+ * @since Android 1.0
+ */
+ protected byte[] buf;
+
+ /**
+ * The length of the buffer.
+ *
+ * @since Android 1.0
+ */
+ protected int len;
+
+ boolean closed;
+
+ boolean eof;
+
+ static final int BUF_SIZE = 512;
+
+ // BEGIN android-added
+ int nativeEndBufSize = 0;
+ // END android-added
+
+ /**
+ * This is the most basic constructor. You only need to pass the {@code
+ * InputStream} from which the compressed data is to be read from. Default
+ * settings for the {@code Inflater} and internal buffer are be used. In
+ * particular the Inflater expects a ZLIB header from the input stream.
+ *
+ * @param is
+ * the {@code InputStream} to read data from.
+ * @since Android 1.0
+ */
+ public InflaterInputStream(InputStream is) {
+ this(is, new Inflater(), BUF_SIZE);
+ }
+
+ /**
+ * This constructor lets you pass a specifically initialized Inflater,
+ * for example one that expects no ZLIB header.
+ *
+ * @param is
+ * the {@code InputStream} to read data from.
+ * @param inf
+ * the specific {@code Inflater} for uncompressing data.
+ * @since Android 1.0
+ */
+ public InflaterInputStream(InputStream is, Inflater inf) {
+ this(is, inf, BUF_SIZE);
+ }
+
+ /**
+ * This constructor lets you specify both the {@code Inflater} as well as
+ * the internal buffer size to be used.
+ *
+ * @param is
+ * the {@code InputStream} to read data from.
+ * @param inf
+ * the specific {@code Inflater} for uncompressing data.
+ * @param bsize
+ * the size to be used for the internal buffer.
+ * @since Android 1.0
+ */
+ public InflaterInputStream(InputStream is, Inflater inf, int bsize) {
+ super(is);
+ if (is == null || inf == null) {
+ throw new NullPointerException();
+ }
+ if (bsize <= 0) {
+ throw new IllegalArgumentException();
+ }
+ this.inf = inf;
+ // BEGIN android-changed
+ if (is instanceof ZipFile.RAFStream) {
+ nativeEndBufSize = bsize;
+ } else {
+ buf = new byte[bsize];
+ }
+ // END android-changed
+ }
+
+ /**
+ * Reads a single byte of decompressed data.
+ *
+ * @return the byte read.
+ * @throws IOException
+ * if an error occurs reading the byte.
+ * @since Android 1.0
+ */
+ @Override
+ public int read() throws IOException {
+ byte[] b = new byte[1];
+ if (read(b, 0, 1) == -1) {
+ return -1;
+ }
+ return b[0] & 0xff;
+ }
+
+ /**
+ * Reads up to {@code nbytes} of decompressed data and stores it in
+ * {@code buffer} starting at {@code off}.
+ *
+ * @param buffer
+ * the buffer to write data to.
+ * @param off
+ * offset in buffer to start writing.
+ * @param nbytes
+ * number of bytes to read.
+ * @return Number of uncompressed bytes read
+ * @throws IOException
+ * if an IOException occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public int read(byte[] buffer, int off, int nbytes) throws IOException {
+ /* archive.1E=Stream is closed */
+ if (closed) {
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+
+ if (null == buffer) {
+ throw new NullPointerException();
+ }
+
+ if (off < 0 || nbytes < 0 || off + nbytes > buffer.length) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ if (nbytes == 0) {
+ return 0;
+ }
+
+ if (inf.finished()) {
+ eof = true;
+ return -1;
+ }
+
+ // avoid int overflow, check null buffer
+ if (off <= buffer.length && nbytes >= 0 && off >= 0
+ && buffer.length - off >= nbytes) {
+ do {
+ if (inf.needsInput()) {
+ fill();
+ }
+ int result;
+ try {
+ result = inf.inflate(buffer, off, nbytes);
+ } catch (DataFormatException e) {
+ if (len == -1) {
+ throw new EOFException();
+ }
+ throw (IOException)(new IOException().initCause(e));
+ }
+ if (result > 0) {
+ return result;
+ } else if (inf.finished()) {
+ eof = true;
+ return -1;
+ } else if (inf.needsDictionary()) {
+ return -1;
+ } else if (len == -1) {
+ throw new EOFException();
+ // If result == 0, fill() and try again
+ }
+ } while (true);
+ }
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+
+ /**
+ * Fills the input buffer with data to be decompressed.
+ *
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ protected void fill() throws IOException {
+ if (closed) {
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+ // BEGIN android-changed
+ if (nativeEndBufSize > 0) {
+ ZipFile.RAFStream is = (ZipFile.RAFStream)in;
+ synchronized (is.mSharedRaf) {
+ long len = is.mLength - is.mOffset;
+ if (len > nativeEndBufSize) len = nativeEndBufSize;
+ int cnt = inf.setFileInput(is.mSharedRaf.getFD(), is.mOffset, (int)nativeEndBufSize);
+ is.skip(cnt);
+ }
+ } else {
+ if ((len = in.read(buf)) > 0) {
+ inf.setInput(buf, 0, len);
+ }
+ }
+ // END android-changed
+ }
+
+ /**
+ * Skips up to n bytes of uncompressed data.
+ *
+ * @param nbytes
+ * the number of bytes to skip.
+ * @return the number of uncompressed bytes skipped.
+ * @throws IOException
+ * if an error occurs skipping.
+ * @since Android 1.0
+ */
+ @Override
+ public long skip(long nbytes) throws IOException {
+ if (nbytes >= 0) {
+ long count = 0, rem = 0;
+ while (count < nbytes) {
+ int x = read(buf, 0,
+ (rem = nbytes - count) > buf.length ? buf.length
+ : (int) rem);
+ if (x == -1) {
+ eof = true;
+ return count;
+ }
+ count += x;
+ }
+ return count;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * Returns whether data can be read from this stream.
+ *
+ * @return 0 if this stream has been closed, 1 otherwise.
+ * @throws IOException
+ * If an error occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public int available() throws IOException {
+ if (closed) {
+ // archive.1E=Stream is closed
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+ if (eof) {
+ return 0;
+ }
+ return 1;
+ }
+
+ /**
+ * Closes the input stream.
+ *
+ * @throws IOException
+ * If an error occurs closing the input stream.
+ * @since Android 1.0
+ */
+ @Override
+ public void close() throws IOException {
+ if (!closed) {
+ inf.end();
+ closed = true;
+ eof = true;
+ super.close();
+ }
+ }
+
+ /**
+ * This implementation overrides the super type implementation to do nothing
+ * at all.
+ *
+ * @param readlimit
+ * of no use.
+ * @since Android 1.0
+ */
+ @Override
+ @SuppressWarnings("unused")
+ public void mark(int readlimit) {
+ // do nothing
+ }
+
+ /**
+ * Reset the position of the stream to the last marked position. This
+ * implementation overrides the supertype implementation and always throws
+ * an {@link IOException IOException} when called.
+ *
+ * @throws IOException
+ * if the method is called
+ * @since Android 1.0
+ */
+ @Override
+ public void reset() throws IOException{
+ throw new IOException();
+ }
+
+ /**
+ * Returns whether the receiver implements {@code mark} semantics. This type
+ * does not support {@code mark()}, so always responds {@code false}.
+ *
+ * @return false, always
+ * @since Android 1.0
+ */
+ @Override
+ public boolean markSupported() {
+ return false;
+ }
+
+}
diff --git a/archive/src/main/java/java/util/zip/ZipConstants.java b/archive/src/main/java/java/util/zip/ZipConstants.java
new file mode 100644
index 0000000..d804b0e
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/ZipConstants.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+interface ZipConstants {
+
+ public static final long LOCSIG = 0x4034b50, EXTSIG = 0x8074b50,
+ CENSIG = 0x2014b50, ENDSIG = 0x6054b50;
+
+ public static final int LOCHDR = 30, EXTHDR = 16, CENHDR = 46, ENDHDR = 22,
+ LOCVER = 4, LOCFLG = 6, LOCHOW = 8, LOCTIM = 10, LOCCRC = 14,
+ LOCSIZ = 18, LOCLEN = 22, LOCNAM = 26, LOCEXT = 28, EXTCRC = 4,
+ EXTSIZ = 8, EXTLEN = 12, CENVEM = 4, CENVER = 6, CENFLG = 8,
+ CENHOW = 10, CENTIM = 12, CENCRC = 16, CENSIZ = 20, CENLEN = 24,
+ CENNAM = 28, CENEXT = 30, CENCOM = 32, CENDSK = 34, CENATT = 36,
+ CENATX = 38, CENOFF = 42, ENDSUB = 8, ENDTOT = 10, ENDSIZ = 12,
+ ENDOFF = 16, ENDCOM = 20;
+}
diff --git a/archive/src/main/java/java/util/zip/ZipEntry.java b/archive/src/main/java/java/util/zip/ZipEntry.java
new file mode 100644
index 0000000..2cc7a9c
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/ZipEntry.java
@@ -0,0 +1,781 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+// BEGIN android-added
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+// END android-added
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+/**
+ * An instance of {@code ZipEntry} represents an entry within a <i>ZIP-archive</i>.
+ * An entry has attributes such as name (= path) or the size of its data. While
+ * an entry identifies data stored in an archive, it does not hold the data
+ * itself. For example when reading a <i>ZIP-file</i> you will first retrieve
+ * all its entries in a collection and then read the data for a specific entry
+ * through an input stream.
+ *
+ * @see ZipFile
+ * @see ZipOutputStream
+ * @since Android 1.0
+ */
+public class ZipEntry implements ZipConstants, Cloneable {
+ String name, comment;
+
+ long compressedSize = -1, crc = -1, size = -1;
+ // BEGIN android-removed
+ // long dataOffset = -1;
+ // END android-removed
+
+ int compressionMethod = -1, time = -1, modDate = -1;
+
+ byte[] extra;
+
+ // BEGIN android-added
+ /*
+ * Fields, present in the Central Directory Entry and Local File Entry.
+ *
+ * Not all of these are part of the interface, but we need them if we
+ * want to be able to copy entries from one archive to another without
+ * losing any meta-data.
+ *
+ * We use over-sized fields so we can indicate whether a field has been
+ * initialized or not.
+ */
+ private int mVersionMadeBy; // CDE
+ private int mVersionToExtract; // CDE, LFE
+ private int mGPBitFlag; // CDE, LFE
+ // private int mCompressionMethod; // CDE, LFE = compressionMethod
+ // private int mLastModFileTime; // CDE, LFE = time
+ // private int mLastModFileDate; // CDE, LFE = modDate
+ // private long mCRC32; // CDE, LFE = crc
+ // private long mCompressedSize; // CDE, LFE = compressedSize
+ // private long mUncompressedSize; // CDE, LFE = size
+ int nameLen, extraLen, commentLen;
+ //private int mFileNameLength; // CDE, LFE
+ //private int mExtraFieldLength; // CDE, LFE
+ //private int mFileCommentLength; // CDE
+ private int mDiskNumberStart; // CDE
+ private int mInternalAttrs; // CDE
+ private long mExternalAttrs; // CDE
+ long mLocalHeaderRelOffset; // CDE ? dataOffset
+ // private String mFileName; // CDE, LFE = name
+ // private byte[] mExtraField; // CDE, LFE = extra
+ // private String mFileComment; // CDE = comment
+
+
+ // GPBitFlag 3: uses a Data Descriptor block (need for deflated data)
+ /*package*/ static final int USES_DATA_DESCR = 0x0008;
+
+ // private static Calendar mCalendar = Calendar.getInstance();
+ // END android-added
+
+ /**
+ * Zip entry state: Deflated.
+ *
+ * @since Android 1.0
+ */
+ public static final int DEFLATED = 8;
+
+ /**
+ * Zip entry state: Stored.
+ *
+ * @since Android 1.0
+ */
+ public static final int STORED = 0;
+
+ /**
+ * Constructs a new {@code ZipEntry} with the specified name.
+ *
+ * @param name
+ * the name of the ZIP entry.
+ * @throws IllegalArgumentException
+ * if the name length is outside the range (> 0xFFFF).
+ * @since Android 1.0
+ */
+ public ZipEntry(String name) {
+ if (name == null) {
+ throw new NullPointerException();
+ }
+ if (name.length() > 0xFFFF) {
+ throw new IllegalArgumentException();
+ }
+ this.name = name;
+
+ // BEGIN android-added
+ mVersionMadeBy = 0x0317; // 03=UNIX, 17=spec v2.3
+ mVersionToExtract = 20; // need deflate, not much else
+ mGPBitFlag = 0;
+ compressionMethod = -1;
+ time = -1;
+ modDate = -1;
+ crc = -1L;
+ compressedSize = -1L;
+ size = -1L;
+ extraLen = -1;
+ nameLen = -1;
+ mDiskNumberStart = 0;
+ mInternalAttrs = 0;
+ mExternalAttrs = 0x81b60020L; // matches WinZip
+ mLocalHeaderRelOffset = -1;
+ extra = null;
+ comment = null;
+ // END android-added
+ }
+
+ /**
+ * Gets the comment for this {@code ZipEntry}.
+ *
+ * @return the comment for this {@code ZipEntry}, or {@code null} if there
+ * is no comment. If we're reading an archive with
+ * {@code ZipInputStream} the comment is not available.
+ * @since Android 1.0
+ */
+ public String getComment() {
+ return comment;
+ }
+
+ /**
+ * Gets the compressed size of this {@code ZipEntry}.
+ *
+ * @return the compressed size, or -1 if the compressed size has not been
+ * set.
+ * @since Android 1.0
+ */
+ public long getCompressedSize() {
+ return compressedSize;
+ }
+
+ /**
+ * Gets the checksum for this {@code ZipEntry}.
+ *
+ * @return the checksum, or -1 if the checksum has not been set.
+ * @since Android 1.0
+ */
+ public long getCrc() {
+ return crc;
+ }
+
+ /**
+ * Gets the extra information for this {@code ZipEntry}.
+ *
+ * @return a byte array containing the extra information, or {@code null} if
+ * there is none.
+ * @since Android 1.0
+ */
+ public byte[] getExtra() {
+ return extra;
+ }
+
+ /**
+ * Gets the compression method for this {@code ZipEntry}.
+ *
+ * @return the compression method, either {@code DEFLATED}, {@code STORED}
+ * or -1 if the compression method has not been set.
+ * @since Android 1.0
+ */
+ public int getMethod() {
+ return compressionMethod;
+ }
+
+ /**
+ * Gets the name of this {@code ZipEntry}.
+ *
+ * @return the entry name.
+ * @since Android 1.0
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the uncompressed size of this {@code ZipEntry}.
+ *
+ * @return the uncompressed size, or {@code -1} if the size has not been
+ * set.
+ * @since Android 1.0
+ */
+ public long getSize() {
+ return size;
+ }
+
+ /**
+ * Gets the last modification time of this {@code ZipEntry}.
+ *
+ * @return the last modification time as the number of milliseconds since
+ * Jan. 1, 1970.
+ * @since Android 1.0
+ */
+ public long getTime() {
+ if (time != -1) {
+ GregorianCalendar cal = new GregorianCalendar();
+ cal.set(Calendar.MILLISECOND, 0);
+ cal.set(1980 + ((modDate >> 9) & 0x7f), ((modDate >> 5) & 0xf) - 1,
+ modDate & 0x1f, (time >> 11) & 0x1f, (time >> 5) & 0x3f,
+ (time & 0x1f) << 1);
+ return cal.getTime().getTime();
+ }
+ return -1;
+ }
+
+ /**
+ * Determine whether or not this {@code ZipEntry} is a directory.
+ *
+ * @return {@code true} when this {@code ZipEntry} is a directory, {@code
+ * false} otherwise.
+ * @since Android 1.0
+ */
+ public boolean isDirectory() {
+ return name.charAt(name.length() - 1) == '/';
+ }
+
+ /**
+ * Sets the comment for this {@code ZipEntry}.
+ *
+ * @param string
+ * the comment for this entry.
+ * @since Android 1.0
+ */
+ public void setComment(String string) {
+ if (string == null || string.length() <= 0xFFFF) {
+ comment = string;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Sets the compressed size for this {@code ZipEntry}.
+ *
+ * @param value
+ * the compressed size (in bytes).
+ * @since Android 1.0
+ */
+ public void setCompressedSize(long value) {
+ compressedSize = value;
+ }
+
+ /**
+ * Sets the checksum for this {@code ZipEntry}.
+ *
+ * @param value
+ * the checksum for this entry.
+ * @throws IllegalArgumentException
+ * if {@code value} is < 0 or > 0xFFFFFFFFL.
+ * @since Android 1.0
+ */
+ public void setCrc(long value) {
+ if (value >= 0 && value <= 0xFFFFFFFFL) {
+ crc = value;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Sets the extra information for this {@code ZipEntry}.
+ *
+ * @param data
+ * a byte array containing the extra information.
+ * @throws IllegalArgumentException
+ * when the length of data is greater than 0xFFFF bytes.
+ * @since Android 1.0
+ */
+ public void setExtra(byte[] data) {
+ if (data == null || data.length <= 0xFFFF) {
+ extra = data;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Sets the compression method for this {@code ZipEntry}.
+ *
+ * @param value
+ * the compression method, either {@code DEFLATED} or {@code
+ * STORED}.
+ * @throws IllegalArgumentException
+ * when value is not {@code DEFLATED} or {@code STORED}.
+ * @since Android 1.0
+ */
+ public void setMethod(int value) {
+ if (value != STORED && value != DEFLATED) {
+ throw new IllegalArgumentException();
+ }
+ compressionMethod = value;
+ }
+
+ /**
+ * Sets the uncompressed size of this {@code ZipEntry}.
+ *
+ * @param value
+ * the uncompressed size for this entry.
+ * @throws IllegalArgumentException
+ * if {@code value} < 0 or {@code value} > 0xFFFFFFFFL.
+ * @since Android 1.0
+ */
+ public void setSize(long value) {
+ if (value >= 0 && value <= 0xFFFFFFFFL) {
+ size = value;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Sets the modification time of this {@code ZipEntry}.
+ *
+ * @param value
+ * the modification time as the number of milliseconds since Jan.
+ * 1, 1970.
+ * @since Android 1.0
+ */
+ public void setTime(long value) {
+ GregorianCalendar cal = new GregorianCalendar();
+ cal.setTime(new Date(value));
+ int year = cal.get(Calendar.YEAR);
+ if (year < 1980) {
+ modDate = 0x21;
+ time = 0;
+ } else {
+ modDate = cal.get(Calendar.DATE);
+ modDate = (cal.get(Calendar.MONTH) + 1 << 5) | modDate;
+ modDate = ((cal.get(Calendar.YEAR) - 1980) << 9) | modDate;
+ time = cal.get(Calendar.SECOND) >> 1;
+ time = (cal.get(Calendar.MINUTE) << 5) | time;
+ time = (cal.get(Calendar.HOUR_OF_DAY) << 11) | time;
+ }
+ }
+
+ /**
+ * Returns the string representation of this {@code ZipEntry}.
+ *
+ * @return the string representation of this {@code ZipEntry}.
+ * @since Android 1.0
+ */
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ // BEGIN android-removed
+ // ZipEntry(String name, String comment, byte[] extra, long modTime,
+ // long size, long compressedSize, long crc, int compressionMethod,
+ // long modDate, long offset) {
+ // this.name = name;
+ // this.comment = comment;
+ // this.extra = extra;
+ // time = (int) modTime;
+ // this.size = size;
+ // this.compressedSize = compressedSize;
+ // this.crc = crc;
+ // this.compressionMethod = compressionMethod;
+ // this.modDate = (int) modDate;
+ // dataOffset = offset;
+ // }
+ // END android-removed
+
+ /**
+ * Constructs a new {@code ZipEntry} using the values obtained from {@code
+ * ze}.
+ *
+ * @param ze
+ * the {@code ZipEntry} from which to obtain values.
+ * @since Android 1.0
+ */
+ public ZipEntry(ZipEntry ze) {
+ name = ze.name;
+ comment = ze.comment;
+ time = ze.time;
+ size = ze.size;
+ compressedSize = ze.compressedSize;
+ crc = ze.crc;
+ compressionMethod = ze.compressionMethod;
+ modDate = ze.modDate;
+ extra = ze.extra;
+ // BEGIN android-removed
+ // dataOffset = ze.dataOffset;
+ // END android-removed
+ // BEGIN android-added
+ mVersionMadeBy = ze.mVersionMadeBy;
+ mVersionToExtract = ze.mVersionToExtract;
+ mGPBitFlag = ze.mGPBitFlag;
+ extraLen = ze.extraLen;
+ nameLen = ze.nameLen;
+ mDiskNumberStart = ze.mDiskNumberStart;
+ mInternalAttrs = ze.mInternalAttrs;
+ mExternalAttrs = ze.mExternalAttrs;
+ mLocalHeaderRelOffset = ze.mLocalHeaderRelOffset;
+ // END android-added
+ }
+
+ /**
+ * Returns a shallow copy of this entry.
+ *
+ * @return a copy of this entry.
+ * @since Android 1.0
+ */
+ @Override
+ public Object clone() {
+ return new ZipEntry(this);
+ }
+
+ /**
+ * Returns the hash code for this {@code ZipEntry}.
+ *
+ * @return the hash code of the entry.
+ * @since Android 1.0
+ */
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ // BEGIN android-added
+ // readShortLE is not used.
+ // readIntLE is used only once in ZipFile.
+ /*
+ * Internal constructor. Creates a new ZipEntry by reading the
+ * Central Directory Entry from "in", which must be positioned at
+ * the CDE signature.
+ *
+ * On exit, "in" will be positioned at the start of the next entry.
+ */
+ /*package*/ ZipEntry(LittleEndianReader ler, InputStream in) throws IOException {
+
+ /*
+ * We're seeing performance issues when we call readShortLE and
+ * readIntLE, so we're going to read the entire header at once
+ * and then parse the results out without using any function calls.
+ * Uglier, but should be much faster.
+ *
+ * Note that some lines look a bit different, because the corresponding
+ * fields or locals are long and so we need to do & 0xffffffffl to avoid
+ * problems induced by sign extension.
+ */
+
+ byte[] hdrBuf = ler.hdrBuf;
+ myReadFully(in, hdrBuf);
+
+ long sig = (hdrBuf[0] & 0xff) | ((hdrBuf[1] & 0xff) << 8) |
+ ((hdrBuf[2] & 0xff) << 16) | ((hdrBuf[3] << 24) & 0xffffffffL);
+ if (sig != CENSIG)
+ throw new ZipException("Central Directory Entry not found");
+
+ mVersionMadeBy = (hdrBuf[4] & 0xff) | ((hdrBuf[5] & 0xff) << 8);
+ mVersionToExtract = (hdrBuf[6] & 0xff) | ((hdrBuf[7] & 0xff) << 8);
+ mGPBitFlag = (hdrBuf[8] & 0xff) | ((hdrBuf[9] & 0xff) << 8);
+ compressionMethod = (hdrBuf[10] & 0xff) | ((hdrBuf[11] & 0xff) << 8);
+ time = (hdrBuf[12] & 0xff) | ((hdrBuf[13] & 0xff) << 8);
+ modDate = (hdrBuf[14] & 0xff) | ((hdrBuf[15] & 0xff) << 8);
+ crc = (hdrBuf[16] & 0xff) | ((hdrBuf[17] & 0xff) << 8)
+ | ((hdrBuf[18] & 0xff) << 16)
+ | ((hdrBuf[19] << 24) & 0xffffffffL);
+ compressedSize = (hdrBuf[20] & 0xff) | ((hdrBuf[21] & 0xff) << 8)
+ | ((hdrBuf[22] & 0xff) << 16)
+ | ((hdrBuf[23] << 24) & 0xffffffffL);
+ size = (hdrBuf[24] & 0xff) | ((hdrBuf[25] & 0xff) << 8)
+ | ((hdrBuf[26] & 0xff) << 16)
+ | ((hdrBuf[27] << 24) & 0xffffffffL);
+ nameLen = (hdrBuf[28] & 0xff) | ((hdrBuf[29] & 0xff) << 8);
+ extraLen = (hdrBuf[30] & 0xff) | ((hdrBuf[31] & 0xff) << 8);
+ commentLen = (hdrBuf[32] & 0xff) | ((hdrBuf[33] & 0xff) << 8);
+ mDiskNumberStart = (hdrBuf[34] & 0xff) | ((hdrBuf[35] & 0xff) << 8);
+ mInternalAttrs = (hdrBuf[36] & 0xff) | ((hdrBuf[37] & 0xff) << 8);
+ mExternalAttrs = (hdrBuf[38] & 0xff) | ((hdrBuf[39] & 0xff) << 8)
+ | ((hdrBuf[40] & 0xff) << 16)
+ | ((hdrBuf[41] << 24) & 0xffffffffL);
+ mLocalHeaderRelOffset = (hdrBuf[42] & 0xff) | ((hdrBuf[43] & 0xff) << 8)
+ | ((hdrBuf[44] & 0xff) << 16)
+ | ((hdrBuf[45] << 24) & 0xffffffffL);
+
+ byte[] nameBytes = new byte[nameLen];
+ myReadFully(in, nameBytes);
+
+ byte[] commentBytes = null;
+ if (commentLen > 0) {
+ commentBytes = new byte[commentLen];
+ myReadFully(in, commentBytes);
+ }
+
+ if (extraLen > 0) {
+ extra = new byte[extraLen];
+ myReadFully(in, extra);
+ }
+
+ try {
+ /*
+ * The actual character set is "IBM Code Page 437". As of
+ * Sep 2006, the Zip spec (APPNOTE.TXT) supports UTF-8. When
+ * bit 11 of the GP flags field is set, the file name and
+ * comment fields are UTF-8.
+ *
+ * TODO: add correct UTF-8 support.
+ */
+ name = new String(nameBytes, "ISO-8859-1");
+ if (commentBytes != null)
+ comment = new String(commentBytes, "ISO-8859-1");
+ else
+ comment = null;
+ }
+ catch (UnsupportedEncodingException uee) {
+ throw new InternalError(uee.getMessage());
+ }
+ }
+ private void myReadFully(InputStream in, byte[] b) throws IOException {
+ int count;
+ int len = b.length;
+ int off = 0;
+
+ while (len > 0) {
+ count = in.read(b, off, len);
+ if (count <= 0)
+ throw new EOFException();
+ off += count;
+ len -= count;
+ }
+ }
+
+ /*package*/ void setVersionToExtract(int version) {
+ mVersionToExtract = version;
+ }
+
+ /*package*/ int getGPBitFlag() {
+ return mGPBitFlag;
+ }
+ /*package*/ void setGPBitFlag(int flags) {
+ mGPBitFlag = flags;
+ }
+
+ /*package*/ long getLocalHeaderRelOffset() {
+ return mLocalHeaderRelOffset;
+ }
+ /*package*/ void setLocalHeaderRelOffset(long offset) {
+ mLocalHeaderRelOffset = offset;
+ }
+
+ /*package*/ void setDateTime(int lastModFileDate, int lastModFileTime) {
+ time = lastModFileTime;
+ modDate = lastModFileDate;
+ }
+
+ /*
+ * Read a two-byte short in little-endian order.
+ *
+ * The DataInput interface, which RandomAccessFile implements, provides
+ * a readInt() function. Unfortunately, it's defined to use big-endian.
+ */
+ /*package*/ static int readShortLE(RandomAccessFile raf) throws IOException
+ {
+ int b0, b1;
+
+ b0 = raf.read();
+ b1 = raf.read();
+ if (b1 < 0)
+ throw new EOFException("in ZipEntry.readShortLE(RandomAccessFile)");
+ return b0 | (b1 << 8);
+ }
+
+ /*
+ * Read a four-byte int in little-endian order.
+ */
+ /*package*/ static long readIntLE(RandomAccessFile raf) throws IOException
+ {
+ int b0, b1, b2, b3;
+
+ b0 = raf.read();
+ b1 = raf.read();
+ b2 = raf.read();
+ b3 = raf.read();
+ if (b3 < 0)
+ throw new EOFException("in ZipEntry.readIntLE(RandomAccessFile)");
+ return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); // ATTENTION: DOES SIGN EXTENSION: IS THIS WANTED?
+ }
+
+ static class LittleEndianReader {
+ private byte[] b = new byte[4];
+ byte[] hdrBuf = new byte[CENHDR];
+
+ /*
+ * Read a two-byte short in little-endian order.
+ */
+ int readShortLE(InputStream in) throws IOException {
+ if (in.read(b, 0, 2) == 2) {
+ return (b[0] & 0XFF) | ((b[1] & 0XFF) << 8);
+ } else {
+ throw new EOFException("in ZipEntry.readShortLE(InputStream)");
+ }
+ }
+
+ /*
+ * Read a four-byte int in little-endian order.
+ */
+ long readIntLE(InputStream in) throws IOException {
+ if (in.read(b, 0, 4) == 4) {
+ return ( ((b[0] & 0XFF))
+ | ((b[1] & 0XFF) << 8)
+ | ((b[2] & 0XFF) << 16)
+ | ((b[3] & 0XFF) << 24))
+ & 0XFFFFFFFFL; // Here for sure NO sign extension is wanted.
+ } else {
+ throw new EOFException("in ZipEntry.readIntLE(InputStream)");
+ }
+ }
+ }
+
+ /*
+ * Write a two-byte short in little-endian order.
+ */
+ /*package*/ static void writeShortLE(OutputStream out, int val)
+ throws IOException
+ {
+ out.write(val & 0xff);
+ out.write((val >> 8) & 0xff);
+ }
+
+ /*
+ * Write a 4-byte int in little-endian order. This takes a long because
+ * all of our 4-byte values are stored locally in longs.
+ */
+ /*package*/ static void writeIntLE(OutputStream out, long val)
+ throws IOException
+ {
+ if (val < 0)
+ throw new InternalError();
+ out.write((int) val & 0xff);
+ out.write(((int) val >> 8) & 0xff);
+ out.write(((int) val >> 16) & 0xff);
+ out.write(((int) val >> 24) & 0xff);
+ }
+
+ /*
+ * Write the Local File Header for this entry to the specified stream.
+ *
+ * Returns the #of bytes written.
+ */
+ /*package*/ int writeLFH(OutputStream out) throws IOException {
+ if (compressionMethod < 0 ||
+ time < 0 ||
+ modDate < 0 ||
+ crc < 0 ||
+ compressedSize < 0 ||
+ size < 0)
+ throw new InternalError();
+
+ writeIntLE(out, LOCSIG);
+ writeShortLE(out, mVersionToExtract);
+ writeShortLE(out, mGPBitFlag);
+ writeShortLE(out, compressionMethod);
+ writeShortLE(out, time);
+ writeShortLE(out, modDate);
+ writeIntLE(out, crc);
+ writeIntLE(out, compressedSize);
+ writeIntLE(out, size);
+
+ byte[] nameBytes;
+ try {
+ nameBytes = name.getBytes("ISO-8859-1");
+ }
+ catch (UnsupportedEncodingException uee) {
+ throw new InternalError(uee.getMessage());
+ }
+
+ int extraLen = 0;
+ if (extra != null)
+ extraLen = extra.length;
+
+ writeShortLE(out, nameBytes.length);
+ writeShortLE(out, extraLen);
+ out.write(nameBytes);
+ if (extra != null)
+ out.write(extra);
+
+ return LOCHDR + nameBytes.length + extraLen;
+ }
+
+ /*
+ * Write the Data Descriptor for this entry to the specified stream.
+ *
+ * Returns the #of bytes written.
+ */
+ /*package*/ int writeDD(OutputStream out) throws IOException {
+ writeIntLE(out, EXTSIG);
+ writeIntLE(out, crc);
+ writeIntLE(out, compressedSize);
+ writeIntLE(out, size);
+ return EXTHDR;
+ }
+
+ /*
+ * Write the Central Directory Entry for this entry.
+ *
+ * Returns the #of bytes written.
+ */
+ /*package*/ int writeCDE(OutputStream out) throws IOException {
+ writeIntLE(out, CENSIG);
+ writeShortLE(out, mVersionMadeBy);
+ writeShortLE(out, mVersionToExtract);
+ writeShortLE(out, mGPBitFlag);
+ writeShortLE(out, compressionMethod);
+ writeShortLE(out, time);
+ writeShortLE(out, modDate);
+ writeIntLE(out, crc);
+ writeIntLE(out, compressedSize);
+ writeIntLE(out, size);
+
+ byte[] nameBytes = null, commentBytes = null;
+ try {
+ nameBytes = name.getBytes("ISO-8859-1");
+ if (comment != null)
+ commentBytes = comment.getBytes("ISO-8859-1");
+ }
+ catch (UnsupportedEncodingException uee) {
+ throw new InternalError(uee.getMessage());
+ }
+
+ int extraLen = 0, commentLen = 0;
+ if (extra != null)
+ extraLen = extra.length;
+ if (commentBytes != null)
+ commentLen = commentBytes.length;
+
+ writeShortLE(out, nameBytes.length);
+ writeShortLE(out, extraLen);
+ writeShortLE(out, commentLen);
+ writeShortLE(out, mDiskNumberStart);
+ writeShortLE(out, mInternalAttrs);
+ writeIntLE(out, mExternalAttrs);
+ writeIntLE(out, mLocalHeaderRelOffset);
+ out.write(nameBytes);
+ if (extra != null)
+ out.write(extra);
+ if (commentBytes != null)
+ out.write(commentBytes);
+
+ return CENHDR + nameBytes.length + extraLen + commentLen;
+ }
+ // END android-added
+}
diff --git a/archive/src/main/java/java/util/zip/ZipException.java b/archive/src/main/java/java/util/zip/ZipException.java
new file mode 100644
index 0000000..590117b
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/ZipException.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+import java.io.IOException;
+
+/**
+ * This runtime exception is thrown by {@code ZipFile} and {@code
+ * ZipInputStream} when the file or stream is not a valid ZIP file.
+ *
+ * @see ZipFile
+ * @see ZipInputStream
+ * @since Android 1.0
+ */
+public class ZipException extends IOException {
+
+ private static final long serialVersionUID = 8000196834066748623L;
+
+ /**
+ * Constructs a new {@code ZipException} instance.
+ *
+ * @since Android 1.0
+ */
+ public ZipException() {
+ super();
+ }
+
+ /**
+ * Constructs a new {@code ZipException} instance with the specified
+ * message.
+ *
+ * @param detailMessage
+ * the detail message for the exception.
+ * @since Android 1.0
+ */
+ public ZipException(String detailMessage) {
+ super(detailMessage);
+ }
+
+}
diff --git a/archive/src/main/java/java/util/zip/ZipFile.java b/archive/src/main/java/java/util/zip/ZipFile.java
new file mode 100644
index 0000000..f1415d9
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/ZipFile.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.NoSuchElementException;
+
+/**
+ * This class provides random read access to a <i>ZIP-archive</i> file.
+ * <p>
+ * While {@code ZipInputStream} provides stream based read access to a
+ * <i>ZIP-archive</i>, this class implements more efficient (file based) access
+ * and makes use of the <i>central directory</i> within a <i>ZIP-archive</i>.
+ * </p>
+ * <p>
+ * Use {@code ZipOutputStream} if you want to create an archive.
+ * </p>
+ * <p>
+ * A temporary ZIP file can be marked for automatic deletion upon closing it.
+ * </p>
+ *
+ * @see ZipEntry
+ * @see ZipOutputStream
+ * @since Android 1.0
+ */
+public class ZipFile implements ZipConstants {
+
+ String fileName;
+
+ File fileToDeleteOnClose;
+
+ /**
+ * Open zip file for read.
+ *
+ * @since Android 1.0
+ */
+ public static final int OPEN_READ = 1;
+
+ /**
+ * Delete zip file when closed.
+ *
+ * @since Android 1.0
+ */
+ public static final int OPEN_DELETE = 4;
+
+ /**
+ * Constructs a new {@code ZipFile} with the specified file.
+ *
+ * @param file
+ * the file to read from.
+ * @throws ZipException
+ * if a ZIP error occurs.
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ public ZipFile(File file) throws ZipException, IOException {
+ this(file, OPEN_READ);
+ }
+
+ /**
+ * Opens a file as <i>ZIP-archive</i>. "mode" must be {@code OPEN_READ} or
+ * {@code OPEN_DELETE} . The latter sets the "delete on exit" flag through a
+ * file.
+ *
+ * @param file
+ * the ZIP file to read.
+ * @param mode
+ * the mode of the file open operation.
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ public ZipFile(File file, int mode) throws IOException {
+ if (mode == (OPEN_READ | OPEN_DELETE))
+ fileToDeleteOnClose = file; // file.deleteOnExit();
+ else if (mode != OPEN_READ)
+ throw new IllegalArgumentException("invalid mode");
+
+ fileName = file.getPath();
+ mRaf = new RandomAccessFile(fileName, "r");
+
+ mEntryList = new ArrayList<ZipEntry>();
+
+ readCentralDir();
+
+ /*
+ * No LinkedHashMap yet, so optimize lookup-by-name by creating
+ * a parallel data structure.
+ */
+ mFastLookup = new HashMap<String, ZipEntry>(mEntryList.size() * 2);
+ for (int i = 0; i < mEntryList.size(); i++) {
+ ZipEntry entry = mEntryList.get(i);
+
+ mFastLookup.put(entry.getName(), entry);
+ }
+ }
+
+ /**
+ * Opens a ZIP archived file.
+ *
+ * @param name
+ * the name of the ZIP file.
+ * @throws IOException
+ * if an IOException occurs.
+ * @since Android 1.0
+ */
+ public ZipFile(String name) throws IOException {
+ this(new File(name), OPEN_READ);
+ }
+
+ @Override
+ protected void finalize() throws IOException {
+ close();
+ }
+
+ /**
+ * Closes this ZIP file.
+ *
+ * @throws IOException
+ * if an IOException occurs.
+ * @since Android 1.0
+ */
+ public void close() throws IOException {
+ RandomAccessFile raf = mRaf;
+
+ if (raf != null) { // Only close initialized instances
+ synchronized(raf) {
+ mRaf = null;
+ raf.close();
+ }
+ if (fileToDeleteOnClose != null) {
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ new File(fileName).delete();
+ return null;
+ }
+ });
+ // fileToDeleteOnClose.delete();
+ fileToDeleteOnClose = null;
+ }
+ }
+ }
+
+ /**
+ * Returns an enumeration of the entries. The entries are listed in the
+ * order in which they appear in the ZIP archive.
+ *
+ * @return the enumeration of the entries.
+ * @since Android 1.0
+ */
+ public Enumeration<? extends ZipEntry> entries() {
+ return new Enumeration<ZipEntry>() {
+ private int i = 0;
+
+ public boolean hasMoreElements() {
+ if (mRaf == null) throw new IllegalStateException("Zip File closed.");
+ return i < mEntryList.size();
+ }
+
+ public ZipEntry nextElement() {
+ if (mRaf == null) throw new IllegalStateException("Zip File closed.");
+ if (i >= mEntryList.size())
+ throw new NoSuchElementException();
+ return (ZipEntry) mEntryList.get(i++);
+ }
+ };
+ }
+
+ /**
+ * Gets the ZIP entry with the specified name from this {@code ZipFile}.
+ *
+ * @param entryName
+ * the name of the entry in the ZIP file.
+ * @return a {@code ZipEntry} or {@code null} if the entry name does not
+ * exist in the ZIP file.
+ * @since Android 1.0
+ */
+ public ZipEntry getEntry(String entryName) {
+ if (entryName != null) {
+ ZipEntry ze = mFastLookup.get(entryName);
+ if (ze == null) ze = mFastLookup.get(entryName + "/");
+ return ze;
+ }
+ throw new NullPointerException();
+ }
+
+ /**
+ * Returns an input stream on the data of the specified {@code ZipEntry}.
+ *
+ * @param entry
+ * the ZipEntry.
+ * @return an input stream of the data contained in the {@code ZipEntry}.
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ public InputStream getInputStream(ZipEntry entry) throws IOException {
+ /*
+ * Make sure this ZipEntry is in this Zip file. We run it through
+ * the name lookup.
+ */
+ entry = getEntry(entry.getName());
+ if (entry == null)
+ return null;
+
+ /*
+ * Create a ZipInputStream at the right part of the file.
+ */
+ RandomAccessFile raf = mRaf;
+ if (raf != null) {
+ synchronized (raf) {
+ // Unfortunately we don't know the entry data's start position.
+ // All we have is the position of the entry's local header.
+ // At position 28 we find the length of the extra data.
+ // In some cases this length differs from the one coming in
+ // the central header!!!
+ RAFStream rafstrm = new RAFStream(raf, entry.mLocalHeaderRelOffset + 28);
+ int localExtraLenOrWhatever = ler.readShortLE(rafstrm);
+ // Now we need to skip the name
+ // and this "extra" data or whatever it is:
+ rafstrm.skip(entry.nameLen + localExtraLenOrWhatever);
+ rafstrm.mLength = rafstrm.mOffset + entry.compressedSize;
+ if (entry.compressionMethod == ZipEntry.DEFLATED) {
+ return new InflaterInputStream(rafstrm, new Inflater(true));
+ } else {
+ return rafstrm;
+ }
+ }
+ }
+ throw new IllegalStateException("Zip File closed");
+ }
+
+ /**
+ * Gets the file name of this {@code ZipFile}.
+ *
+ * @return the file name of this {@code ZipFile}.
+ * @since Android 1.0
+ */
+ public String getName() {
+ return fileName;
+ }
+
+ /**
+ * Returns the number of {@code ZipEntries} in this {@code ZipFile}.
+ *
+ * @return the number of entries in this file.
+ * @since Android 1.0
+ */
+ public int size() {
+ return mEntryList.size();
+ }
+
+ /*
+ * Find the central directory and read the contents.
+ *
+ * The central directory can be followed by a variable-length comment
+ * field, so we have to scan through it backwards. The comment is at
+ * most 64K, plus we have 18 bytes for the end-of-central-dir stuff
+ * itself, plus apparently sometimes people throw random junk on the end
+ * just for the fun of it.
+ *
+ * This is all a little wobbly. If the wrong value ends up in the EOCD
+ * area, we're hosed. This appears to be the way that everbody handles
+ * it though, so we're in pretty good company if this fails.
+ */
+ private void readCentralDir() throws IOException {
+ long scanOffset, stopOffset;
+ long sig;
+
+ /*
+ * Scan back, looking for the End Of Central Directory field. If
+ * the archive doesn't have a comment, we'll hit it on the first
+ * try.
+ *
+ * No need to synchronize mRaf here -- we only do this when we
+ * first open the Zip file.
+ */
+ scanOffset = mRaf.length() - ENDHDR;
+ if (scanOffset < 0)
+ throw new ZipException("too short to be Zip");
+
+ stopOffset = scanOffset - 65536;
+ if (stopOffset < 0)
+ stopOffset = 0;
+
+ while (true) {
+ mRaf.seek(scanOffset);
+ if (ZipEntry.readIntLE(mRaf) == 101010256L)
+ break;
+
+ //System.out.println("not found at " + scanOffset);
+ scanOffset--;
+ if (scanOffset < stopOffset)
+ throw new ZipException("EOCD not found; not a Zip archive?");
+ }
+
+ /*
+ * Found it, read the EOCD.
+ *
+ * For performance we want to use buffered I/O when reading the
+ * file. We wrap a buffered stream around the random-access file
+ * object. If we just read from the RandomAccessFile we'll be
+ * doing a read() system call every time.
+ */
+ RAFStream rafs = new RAFStream(mRaf, mRaf.getFilePointer());
+ BufferedInputStream bin = new BufferedInputStream(rafs, ENDHDR);
+ int diskNumber, diskWithCentralDir, numEntries, totalNumEntries;
+ //long centralDirSize;
+ long centralDirOffset;
+ //int commentLen;
+
+ diskNumber = ler.readShortLE(bin);
+ diskWithCentralDir = ler.readShortLE(bin);
+ numEntries = ler.readShortLE(bin);
+ totalNumEntries = ler.readShortLE(bin);
+ /*centralDirSize =*/ ler.readIntLE(bin);
+ centralDirOffset = ler.readIntLE(bin);
+ /*commentLen =*/ ler.readShortLE(bin);
+
+ if (numEntries != totalNumEntries ||
+ diskNumber != 0 ||
+ diskWithCentralDir != 0)
+ throw new ZipException("spanned archives not supported");
+
+ /*
+ * Seek to the first CDE and read all entries.
+ */
+ rafs = new RAFStream(mRaf, centralDirOffset);
+ bin = new BufferedInputStream(rafs, 4096);
+ for (int i = 0; i < numEntries; i++) {
+ ZipEntry newEntry;
+
+ newEntry = new ZipEntry(ler, bin);
+ mEntryList.add(newEntry);
+ }
+ }
+
+ /*
+ * Local data items.
+ */
+ private RandomAccessFile mRaf;
+
+ ZipEntry.LittleEndianReader ler = new ZipEntry.LittleEndianReader();
+
+ /*
+ * What we really want here is a LinkedHashMap, because we want fast
+ * lookups by name, but we want to preserve the ordering of the archive
+ * entries. Unfortunately we don't yet have a LinkedHashMap
+ * implementation.
+ */
+ private ArrayList<ZipEntry> mEntryList;
+ private HashMap<String, ZipEntry> mFastLookup;
+
+ /*
+ * Wrap a stream around a RandomAccessFile. The RandomAccessFile
+ * is shared among all streams returned by getInputStream(), so we
+ * have to synchronize access to it. (We can optimize this by
+ * adding buffering here to reduce collisions.)
+ *
+ * We could support mark/reset, but we don't currently need them.
+ */
+ static class RAFStream extends InputStream {
+ public RAFStream(RandomAccessFile raf, long pos) throws IOException {
+ mSharedRaf = raf;
+ mOffset = pos;
+ mLength = raf.length();
+ }
+
+ @Override
+ public int available() throws IOException {
+ return (mOffset < mLength ? 1 : 0);
+ }
+
+ public int read() throws IOException {
+ if (read(singleByteBuf, 0, 1) == 1) return singleByteBuf[0] & 0XFF;
+ else return -1;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ int count;
+ synchronized (mSharedRaf) {
+ mSharedRaf.seek(mOffset);
+ if (mOffset + len > mLength) len = (int) (mLength - mOffset);
+ count = mSharedRaf.read(b, off, len);
+ if (count > 0) {
+ mOffset += count;
+ }
+ else return -1;
+ }
+ return count;
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ if (mOffset + n > mLength)
+ n = mLength - mOffset;
+ mOffset += n;
+ return n;
+ }
+
+ RandomAccessFile mSharedRaf;
+ long mOffset;
+ long mLength;
+ private byte[] singleByteBuf = new byte[1];
+ }
+}
diff --git a/archive/src/main/java/java/util/zip/ZipInputStream.java b/archive/src/main/java/java/util/zip/ZipInputStream.java
new file mode 100644
index 0000000..262fa3f
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/ZipInputStream.java
@@ -0,0 +1,414 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+
+import org.apache.harmony.archive.internal.nls.Messages;
+import org.apache.harmony.luni.util.Util;
+
+/**
+ * This class provides an implementation of {@code FilterInputStream} that
+ * uncompresses data from a <i>ZIP-archive</i> input stream.
+ * <p>
+ * A <i>ZIP-archive</i> is a collection of compressed (or uncompressed) files -
+ * the so called ZIP entries. Therefore when reading from a {@code
+ * ZipInputStream} first the entry's attributes will be retrieved with {@code
+ * getNextEntry} before its data is read.
+ * </p>
+ * <p>
+ * While {@code InflaterInputStream} can read a compressed <i>ZIP-archive</i>
+ * entry, this extension can read uncompressed entries as well.
+ * </p>
+ * <p>
+ * Use {@code ZipFile} if you can access the archive as a file directly.
+ * </p>
+ *
+ * @see ZipEntry
+ * @see ZipFile
+ * @since Android 1.0
+ */
+public class ZipInputStream extends InflaterInputStream implements ZipConstants {
+ static final int DEFLATED = 8;
+
+ static final int STORED = 0;
+
+ static final int ZIPDataDescriptorFlag = 8;
+
+ static final int ZIPLocalHeaderVersionNeeded = 20;
+
+ // BEGI android-removed
+ // private boolean zipClosed = false;
+ // END android-removed
+
+ private boolean entriesEnd = false;
+
+ private boolean hasDD = false;
+
+ private int entryIn = 0;
+
+ private int inRead, lastRead = 0;
+
+ ZipEntry currentEntry;
+
+ private final byte[] hdrBuf = new byte[LOCHDR - LOCVER];
+
+ private final CRC32 crc = new CRC32();
+
+ private byte[] nameBuf = new byte[256];
+
+ private char[] charBuf = new char[256];
+
+ /**
+ * Constructs a new {@code ZipInputStream} from the specified input stream.
+ *
+ * @param stream
+ * the input stream to representing a ZIP archive.
+ * @since Android 1.0
+ */
+ public ZipInputStream(InputStream stream) {
+ super(new PushbackInputStream(stream, BUF_SIZE), new Inflater(true));
+ if (stream == null) {
+ throw new NullPointerException();
+ }
+ }
+
+ /**
+ * Closes this {@code ZipInputStream}.
+ *
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public void close() throws IOException {
+ // BEGIN android-changed
+ if (closed != true) {
+ closeEntry(); // Close the current entry
+ super.close();
+ }
+ // END android-changed
+ }
+
+ /**
+ * Closes the current ZIP entry and positions to read the next entry.
+ *
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ public void closeEntry() throws IOException {
+ // BEGIN android-changed
+ if (closed) {
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+ // END android-changed
+ if (currentEntry == null) {
+ return;
+ }
+ if (currentEntry instanceof java.util.jar.JarEntry) {
+ Attributes temp = ((JarEntry) currentEntry).getAttributes();
+ if (temp != null && temp.containsKey("hidden")) { //$NON-NLS-1$
+ return;
+ }
+ }
+ // Ensure all entry bytes are read
+ skip(Long.MAX_VALUE);
+ int inB, out;
+ if (currentEntry.compressionMethod == DEFLATED) {
+ inB = inf.getTotalIn();
+ out = inf.getTotalOut();
+ } else {
+ inB = inRead;
+ out = inRead;
+ }
+ int diff = 0;
+ // Pushback any required bytes
+ if ((diff = entryIn - inB) != 0) {
+ ((PushbackInputStream) in).unread(buf, len - diff, diff);
+ }
+
+ if (hasDD) {
+ in.read(hdrBuf, 0, EXTHDR);
+ if (getLong(hdrBuf, 0) != EXTSIG) {
+ throw new ZipException(Messages.getString("archive.1F")); //$NON-NLS-1$
+ }
+ currentEntry.crc = getLong(hdrBuf, EXTCRC);
+ currentEntry.compressedSize = getLong(hdrBuf, EXTSIZ);
+ currentEntry.size = getLong(hdrBuf, EXTLEN);
+ }
+ if (currentEntry.crc != crc.getValue()) {
+ throw new ZipException(Messages.getString("archive.20")); //$NON-NLS-1$
+ }
+ if (currentEntry.compressedSize != inB || currentEntry.size != out) {
+ throw new ZipException(Messages.getString("archive.21")); //$NON-NLS-1$
+ }
+
+ inf.reset();
+ lastRead = inRead = entryIn = len = 0;
+ crc.reset();
+ currentEntry = null;
+ }
+
+ /**
+ * Reads the next entry from this {@code ZipInputStream}.
+ *
+ * @return the next {@code ZipEntry} contained in the input stream.
+ * @throws IOException
+ * if the stream is not positioned at the beginning of an entry
+ * or if an other {@code IOException} occurs.
+ * @see ZipEntry
+ * @since Android 1.0
+ */
+ public ZipEntry getNextEntry() throws IOException {
+ if (currentEntry != null) {
+ closeEntry();
+ }
+ if (entriesEnd) {
+ return null;
+ }
+
+ int x = 0, count = 0;
+ while (count != 4) {
+ count += x = in.read(hdrBuf, count, 4 - count);
+ if (x == -1) {
+ return null;
+ }
+ }
+ long hdr = getLong(hdrBuf, 0);
+ if (hdr == CENSIG) {
+ entriesEnd = true;
+ return null;
+ }
+ if (hdr != LOCSIG) {
+ return null;
+ }
+
+ // Read the local header
+ count = 0;
+ while (count != (LOCHDR - LOCVER)) {
+ count += x = in.read(hdrBuf, count, (LOCHDR - LOCVER) - count);
+ if (x == -1) {
+ throw new EOFException();
+ }
+ }
+ int version = getShort(hdrBuf, 0) & 0xff;
+ if (version > ZIPLocalHeaderVersionNeeded) {
+ throw new ZipException(Messages.getString("archive.22")); //$NON-NLS-1$
+ }
+ int flags = getShort(hdrBuf, LOCFLG - LOCVER);
+ hasDD = ((flags & ZIPDataDescriptorFlag) == ZIPDataDescriptorFlag);
+ int cetime = getShort(hdrBuf, LOCTIM - LOCVER);
+ int cemodDate = getShort(hdrBuf, LOCTIM - LOCVER + 2);
+ int cecompressionMethod = getShort(hdrBuf, LOCHOW - LOCVER);
+ long cecrc = 0, cecompressedSize = 0, cesize = -1;
+ if (!hasDD) {
+ cecrc = getLong(hdrBuf, LOCCRC - LOCVER);
+ cecompressedSize = getLong(hdrBuf, LOCSIZ - LOCVER);
+ cesize = getLong(hdrBuf, LOCLEN - LOCVER);
+ }
+ int flen = getShort(hdrBuf, LOCNAM - LOCVER);
+ if (flen == 0) {
+ throw new ZipException(Messages.getString("archive.23")); //$NON-NLS-1$
+ }
+ int elen = getShort(hdrBuf, LOCEXT - LOCVER);
+
+ count = 0;
+ if (flen > nameBuf.length) {
+ nameBuf = new byte[flen];
+ charBuf = new char[flen];
+ }
+ while (count != flen) {
+ count += x = in.read(nameBuf, count, flen - count);
+ if (x == -1) {
+ throw new EOFException();
+ }
+ }
+ currentEntry = createZipEntry(Util.convertUTF8WithBuf(nameBuf, charBuf,
+ 0, flen));
+ currentEntry.time = cetime;
+ currentEntry.modDate = cemodDate;
+ currentEntry.setMethod(cecompressionMethod);
+ if (cesize != -1) {
+ currentEntry.setCrc(cecrc);
+ currentEntry.setSize(cesize);
+ currentEntry.setCompressedSize(cecompressedSize);
+ }
+ if (elen > 0) {
+ count = 0;
+ byte[] e = new byte[elen];
+ while (count != elen) {
+ count += x = in.read(e, count, elen - count);
+ if (x == -1) {
+ throw new EOFException();
+ }
+ }
+ currentEntry.setExtra(e);
+ }
+ // BEGIN android-added
+ eof = false;
+ // END android-added
+ return currentEntry;
+ }
+
+ /* Read 4 bytes from the buffer and store it as an int */
+
+ @Override
+ public int read(byte[] buffer, int start, int length) throws IOException {
+ // BEGIN android-changed
+ if (closed) {
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+ // END android-changed
+ if (inf.finished() || currentEntry == null) {
+ return -1;
+ }
+ // avoid int overflow, check null buffer
+ if (start <= buffer.length && length >= 0 && start >= 0
+ && buffer.length - start >= length) {
+ if (currentEntry.compressionMethod == STORED) {
+ int csize = (int) currentEntry.size;
+ if (inRead >= csize) {
+ // BEGIN android-added
+ eof = true;
+ // END android-added
+ return -1;
+ }
+ if (lastRead >= len) {
+ lastRead = 0;
+ if ((len = in.read(buf)) == -1) {
+ // BEGIN android-added
+ eof = true;
+ // END android-added
+ return -1;
+ }
+ entryIn += len;
+ }
+ // BEGIN android-changed
+ int toRead = length > (len - lastRead) ? len - lastRead : length;
+ // END android-changed
+ if ((csize - inRead) < toRead) {
+ toRead = csize - inRead;
+ }
+ System.arraycopy(buf, lastRead, buffer, start, toRead);
+ lastRead += toRead;
+ inRead += toRead;
+ crc.update(buffer, start, toRead);
+ return toRead;
+ }
+ if (inf.needsInput()) {
+ fill();
+ if (len > 0) {
+ entryIn += len;
+ }
+ }
+ int read = 0;
+ try {
+ read = inf.inflate(buffer, start, length);
+ } catch (DataFormatException e) {
+ throw new ZipException(e.getMessage());
+ }
+ if (read == 0 && inf.finished()) {
+ return -1;
+ }
+ crc.update(buffer, start, read);
+ return read;
+ }
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Skips up to the specified number of bytes in the current ZIP entry.
+ *
+ * @param value
+ * the number of bytes to skip.
+ * @return the number of bytes skipped.
+ * @throws IOException
+ * if an {@code IOException} occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public long skip(long value) throws IOException {
+ if (value >= 0) {
+ long skipped = 0;
+ byte[] b = new byte[1024];
+ while (skipped != value) {
+ long rem = value - skipped;
+ int x = read(b, 0, (int) (b.length > rem ? rem : b.length));
+ if (x == -1) {
+ return skipped;
+ }
+ skipped += x;
+ }
+ return skipped;
+ }
+ throw new IllegalArgumentException();
+}
+
+ /**
+ * Returns 0 if the {@code EOF} has been reached, otherwise returns 1.
+ *
+ * @return 0 after {@code EOF} of current entry, 1 otherwise.
+ * @throws IOException
+ * if an IOException occurs.
+ * @since Android 1.0
+ */
+ @Override
+ public int available() throws IOException {
+ // BEGIN android-changed
+ if (closed) {
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+ if (currentEntry == null) {
+ return 1;
+ }
+ return super.available();
+ // END android-changed
+ }
+
+ /**
+ * creates a {@link ZipEntry } with the given name.
+ *
+ * @param name
+ * the name of the entry.
+ * @return the created {@code ZipEntry}.
+ * @since Android 1.0
+ */
+ protected ZipEntry createZipEntry(String name) {
+ return new ZipEntry(name);
+ }
+
+ private int getShort(byte[] buffer, int off) {
+ return (buffer[off] & 0xFF) | ((buffer[off + 1] & 0xFF) << 8);
+ }
+
+ private long getLong(byte[] buffer, int off) {
+ long l = 0;
+ l |= (buffer[off] & 0xFF);
+ l |= (buffer[off + 1] & 0xFF) << 8;
+ l |= (buffer[off + 2] & 0xFF) << 16;
+ l |= ((long) (buffer[off + 3] & 0xFF)) << 24;
+ return l;
+ }
+}
diff --git a/archive/src/main/java/java/util/zip/ZipOutputStream.java b/archive/src/main/java/java/util/zip/ZipOutputStream.java
new file mode 100644
index 0000000..4ddf643
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/ZipOutputStream.java
@@ -0,0 +1,456 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util.zip;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Vector;
+
+import org.apache.harmony.archive.internal.nls.Messages;
+
+/**
+ * This class provides an implementation of {@code FilterOutputStream} that
+ * compresses data entries into a <i>ZIP-archive</i> output stream.
+ * <p>
+ * {@code ZipOutputStream} is used to write {@code ZipEntries} to the underlying
+ * stream. Output from {@code ZipOutputStream} conforms to the {@code ZipFile}
+ * file format.
+ * </p>
+ * <p>
+ * While {@code DeflaterOutputStream} can write a compressed <i>ZIP-archive</i>
+ * entry, this extension can write uncompressed entries as well. In this case
+ * special rules apply, for this purpose refer to the <a
+ * href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">file format
+ * specification</a>.
+ * </p>
+ *
+ * @see ZipEntry
+ * @see ZipFile
+ * @since Android 1.0
+ */
+public class ZipOutputStream extends DeflaterOutputStream implements
+ ZipConstants {
+
+ /**
+ * Indicates deflated entries.
+ *
+ * @since Android 1.0
+ */
+ public static final int DEFLATED = 8;
+
+ /**
+ * Indicates uncompressed entries.
+ *
+ * @since Android 1.0
+ */
+ public static final int STORED = 0;
+
+ static final int ZIPDataDescriptorFlag = 8;
+
+ static final int ZIPLocalHeaderVersionNeeded = 20;
+
+ private String comment;
+
+ private final Vector<String> entries = new Vector<String>();
+
+ private int compressMethod = DEFLATED;
+
+ private int compressLevel = Deflater.DEFAULT_COMPRESSION;
+
+ private ByteArrayOutputStream cDir = new ByteArrayOutputStream();
+
+ private ZipEntry currentEntry;
+
+ private final CRC32 crc = new CRC32();
+
+ private int offset = 0, curOffset = 0, nameLength;
+
+ private byte[] nameBytes;
+
+ /**
+ * Constructs a new {@code ZipOutputStream} with the specified output
+ * stream.
+ *
+ * @param p1
+ * the {@code OutputStream} to write the data to.
+ * @since Android 1.0
+ */
+ public ZipOutputStream(OutputStream p1) {
+ super(p1, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+ }
+
+ /**
+ * Closes the current {@code ZipEntry}, if any, and the underlying output
+ * stream. If the stream is already closed this method does nothing.
+ *
+ * @throws IOException
+ * If an error occurs closing the stream.
+ * @since Android 1.0
+ */
+ @Override
+ public void close() throws IOException {
+ if (out != null) {
+ finish();
+ out.close();
+ out = null;
+ }
+ }
+
+ /**
+ * Closes the current {@code ZipEntry}. Any entry terminal data is written
+ * to the underlying stream.
+ *
+ * @throws IOException
+ * If an error occurs closing the entry.
+ * @since Android 1.0
+ */
+ public void closeEntry() throws IOException {
+ if (cDir == null) {
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+ if (currentEntry == null) {
+ return;
+ }
+ if (currentEntry.getMethod() == DEFLATED) {
+ super.finish();
+ }
+
+ // Verify values for STORED types
+ if (currentEntry.getMethod() == STORED) {
+ if (crc.getValue() != currentEntry.crc) {
+ throw new ZipException(Messages.getString("archive.20")); //$NON-NLS-1$
+ }
+ if (currentEntry.size != crc.tbytes) {
+ throw new ZipException(Messages.getString("archive.21")); //$NON-NLS-1$
+ }
+ }
+ curOffset = LOCHDR;
+
+ // Write the DataDescriptor
+ if (currentEntry.getMethod() != STORED) {
+ curOffset += EXTHDR;
+ writeLong(out, EXTSIG);
+ writeLong(out, currentEntry.crc = crc.getValue());
+ writeLong(out, currentEntry.compressedSize = def.getTotalOut());
+ writeLong(out, currentEntry.size = def.getTotalIn());
+ }
+ // Update the CentralDirectory
+ writeLong(cDir, CENSIG);
+ writeShort(cDir, ZIPLocalHeaderVersionNeeded); // Version created
+ writeShort(cDir, ZIPLocalHeaderVersionNeeded); // Version to extract
+ writeShort(cDir, currentEntry.getMethod() == STORED ? 0
+ : ZIPDataDescriptorFlag);
+ writeShort(cDir, currentEntry.getMethod());
+ writeShort(cDir, currentEntry.time);
+ writeShort(cDir, currentEntry.modDate);
+ writeLong(cDir, crc.getValue());
+ if (currentEntry.getMethod() == DEFLATED) {
+ curOffset += writeLong(cDir, def.getTotalOut());
+ writeLong(cDir, def.getTotalIn());
+ } else {
+ curOffset += writeLong(cDir, crc.tbytes);
+ writeLong(cDir, crc.tbytes);
+ }
+ curOffset += writeShort(cDir, nameLength);
+ if (currentEntry.extra != null) {
+ curOffset += writeShort(cDir, currentEntry.extra.length);
+ } else {
+ writeShort(cDir, 0);
+ }
+ String c;
+ if ((c = currentEntry.getComment()) != null) {
+ writeShort(cDir, c.length());
+ } else {
+ writeShort(cDir, 0);
+ }
+ writeShort(cDir, 0); // Disk Start
+ writeShort(cDir, 0); // Internal File Attributes
+ writeLong(cDir, 0); // External File Attributes
+ writeLong(cDir, offset);
+ cDir.write(nameBytes);
+ nameBytes = null;
+ if (currentEntry.extra != null) {
+ cDir.write(currentEntry.extra);
+ }
+ offset += curOffset;
+ if (c != null) {
+ cDir.write(c.getBytes());
+ }
+ currentEntry = null;
+ crc.reset();
+ def.reset();
+ done = false;
+ }
+
+ /**
+ * Indicates that all entries have been written to the stream. Any terminal
+ * information is written to the underlying stream.
+ *
+ * @throws IOException
+ * if an error occurs while terminating the stream.
+ * @since Android 1.0
+ */
+ @Override
+ public void finish() throws IOException {
+ if (out == null) {
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+ if (cDir == null) {
+ return;
+ }
+ if (entries.size() == 0) {
+ throw new ZipException(Messages.getString("archive.28")); //$NON-NLS-1$;
+ }
+ if (currentEntry != null) {
+ closeEntry();
+ }
+ int cdirSize = cDir.size();
+ // Write Central Dir End
+ writeLong(cDir, ENDSIG);
+ writeShort(cDir, 0); // Disk Number
+ writeShort(cDir, 0); // Start Disk
+ writeShort(cDir, entries.size()); // Number of entries
+ writeShort(cDir, entries.size()); // Number of entries
+ writeLong(cDir, cdirSize); // Size of central dir
+ writeLong(cDir, offset); // Offset of central dir
+ if (comment != null) {
+ writeShort(cDir, comment.length());
+ cDir.write(comment.getBytes());
+ } else {
+ writeShort(cDir, 0);
+ }
+ // Write the central dir
+ out.write(cDir.toByteArray());
+ cDir = null;
+
+ }
+
+ /**
+ * Writes entry information to the underlying stream. Data associated with
+ * the entry can then be written using {@code write()}. After data is
+ * written {@code closeEntry()} must be called to complete the writing of
+ * the entry to the underlying stream.
+ *
+ * @param ze
+ * the {@code ZipEntry} to store.
+ * @throws IOException
+ * If an error occurs storing the entry.
+ * @see #write
+ * @since Android 1.0
+ */
+ public void putNextEntry(ZipEntry ze) throws java.io.IOException {
+ if (currentEntry != null) {
+ closeEntry();
+ }
+ if (ze.getMethod() == STORED
+ || (compressMethod == STORED && ze.getMethod() == -1)) {
+ if (ze.crc == -1) {
+ /* [MSG "archive.20", "Crc mismatch"] */
+ throw new ZipException(Messages.getString("archive.20")); //$NON-NLS-1$
+ }
+ if (ze.size == -1 && ze.compressedSize == -1) {
+ /* [MSG "archive.21", "Size mismatch"] */
+ throw new ZipException(Messages.getString("archive.21")); //$NON-NLS-1$
+ }
+ if (ze.size != ze.compressedSize && ze.compressedSize != -1
+ && ze.size != -1) {
+ /* [MSG "archive.21", "Size mismatch"] */
+ throw new ZipException(Messages.getString("archive.21")); //$NON-NLS-1$
+ }
+ }
+ /* [MSG "archive.1E", "Stream is closed"] */
+ if (cDir == null) {
+ throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
+ }
+ if (entries.contains(ze.name)) {
+ /* [MSG "archive.29", "Entry already exists: {0}"] */
+ throw new ZipException(Messages.getString("archive.29", ze.name)); //$NON-NLS-1$
+ }
+ nameLength = utf8Count(ze.name);
+ if (nameLength > 0xffff) {
+ /* [MSG "archive.2A", "Name too long: {0}"] */
+ throw new IllegalArgumentException(Messages.getString("archive.2A", ze.name)); //$NON-NLS-1$
+ }
+
+ def.setLevel(compressLevel);
+ currentEntry = ze;
+ entries.add(currentEntry.name);
+ if (currentEntry.getMethod() == -1) {
+ currentEntry.setMethod(compressMethod);
+ }
+ writeLong(out, LOCSIG); // Entry header
+ writeShort(out, ZIPLocalHeaderVersionNeeded); // Extraction version
+ writeShort(out, currentEntry.getMethod() == STORED ? 0
+ : ZIPDataDescriptorFlag);
+ writeShort(out, currentEntry.getMethod());
+ if (currentEntry.getTime() == -1) {
+ currentEntry.setTime(System.currentTimeMillis());
+ }
+ writeShort(out, currentEntry.time);
+ writeShort(out, currentEntry.modDate);
+
+ if (currentEntry.getMethod() == STORED) {
+ if (currentEntry.size == -1) {
+ currentEntry.size = currentEntry.compressedSize;
+ } else if (currentEntry.compressedSize == -1) {
+ currentEntry.compressedSize = currentEntry.size;
+ }
+ writeLong(out, currentEntry.crc);
+ writeLong(out, currentEntry.size);
+ writeLong(out, currentEntry.size);
+ } else {
+ writeLong(out, 0);
+ writeLong(out, 0);
+ writeLong(out, 0);
+ }
+ writeShort(out, nameLength);
+ if (currentEntry.extra != null) {
+ writeShort(out, currentEntry.extra.length);
+ } else {
+ writeShort(out, 0);
+ }
+ nameBytes = toUTF8Bytes(currentEntry.name, nameLength);
+ out.write(nameBytes);
+ if (currentEntry.extra != null) {
+ out.write(currentEntry.extra);
+ }
+ }
+
+ /**
+ * Sets the {@code ZipFile} comment associated with the file being written.
+ *
+ * @param comment
+ * the comment associated with the file.
+ * @since Android 1.0
+ */
+ public void setComment(String comment) {
+ if (comment.length() > 0xFFFF) {
+ throw new IllegalArgumentException(Messages.getString("archive.2B")); //$NON-NLS-1$
+ }
+ this.comment = comment;
+ }
+
+ /**
+ * Sets the compression level to be used for writing entry data. This level
+ * may be set on a per entry basis. The level must have a value between -1
+ * and 8 according to the {@code Deflater} compression level bounds.
+ *
+ * @param level
+ * the compression level (ranging from -1 to 8).
+ * @see Deflater
+ * @since Android 1.0
+ */
+ public void setLevel(int level) {
+ if (level < Deflater.DEFAULT_COMPRESSION
+ || level > Deflater.BEST_COMPRESSION) {
+ throw new IllegalArgumentException();
+ }
+ compressLevel = level;
+ }
+
+ /**
+ * Sets the compression method to be used when compressing entry data.
+ * method must be one of {@code STORED} (for no compression) or {@code
+ * DEFLATED}.
+ *
+ * @param method
+ * the compression method to use.
+ * @since Android 1.0
+ */
+ public void setMethod(int method) {
+ if (method != STORED && method != DEFLATED) {
+ throw new IllegalArgumentException();
+ }
+ compressMethod = method;
+
+ }
+
+ private long writeLong(OutputStream os, long i) throws java.io.IOException {
+ // Write out the long value as an unsigned int
+ os.write((int) (i & 0xFF));
+ os.write((int) (i >> 8) & 0xFF);
+ os.write((int) (i >> 16) & 0xFF);
+ os.write((int) (i >> 24) & 0xFF);
+ return i;
+ }
+
+ private int writeShort(OutputStream os, int i) throws java.io.IOException {
+ os.write(i & 0xFF);
+ os.write((i >> 8) & 0xFF);
+ return i;
+
+ }
+
+ @Override
+ public void write(byte[] buffer, int off, int nbytes)
+ throws java.io.IOException {
+ // avoid int overflow, check null buf
+ if ((off > buffer.length) || (nbytes < 0) || (off < 0)
+ || (buffer.length - off < nbytes)) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ if (currentEntry == null) {
+ /* [MSG "archive.2C", "No active entry"] */
+ throw new ZipException(Messages.getString("archive.2C")); //$NON-NLS-1$
+ }
+
+ if (currentEntry.getMethod() == STORED) {
+ out.write(buffer, off, nbytes);
+ } else {
+ super.write(buffer, off, nbytes);
+ }
+ crc.update(buffer, off, nbytes);
+ }
+
+ static int utf8Count(String value) {
+ int total = 0;
+ for (int i = value.length(); --i >= 0;) {
+ char ch = value.charAt(i);
+ if (ch < 0x80) {
+ total++;
+ } else if (ch < 0x800) {
+ total += 2;
+ } else {
+ total += 3;
+ }
+ }
+ return total;
+ }
+
+ static byte[] toUTF8Bytes(String value, int length) {
+ byte[] result = new byte[length];
+ int pos = result.length;
+ for (int i = value.length(); --i >= 0;) {
+ char ch = value.charAt(i);
+ if (ch < 0x80) {
+ result[--pos] = (byte) ch;
+ } else if (ch < 0x800) {
+ result[--pos] = (byte) (0x80 | (ch & 0x3f));
+ result[--pos] = (byte) (0xc0 | (ch >> 6));
+ } else {
+ result[--pos] = (byte) (0x80 | (ch & 0x3f));
+ result[--pos] = (byte) (0x80 | ((ch >> 6) & 0x3f));
+ result[--pos] = (byte) (0xe0 | (ch >> 12));
+ }
+ }
+ return result;
+ }
+}
diff --git a/archive/src/main/java/java/util/zip/package.html b/archive/src/main/java/java/util/zip/package.html
new file mode 100644
index 0000000..2a09bf1
--- /dev/null
+++ b/archive/src/main/java/java/util/zip/package.html
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <p>
+ This package contains classes for compressing and decompressing data in
+ ZIP and GZIP file formats.
+ </p>
+ @since Android 1.0
+ </body>
+</html>
diff --git a/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java b/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java
new file mode 100644
index 0000000..764f34d
--- /dev/null
+++ b/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+// BEGIN android-note
+// Redundant code has been removed and is now called from MsgHelp.
+// END android-note
+
+package org.apache.harmony.archive.internal.nls;
+
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+// BEGIN android-changed
+import org.apache.harmony.luni.util.MsgHelp;
+// END android-changed
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.archive.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ // BEGIN android-changed
+ private static final String sResource =
+ "org.apache.harmony.archive.internal.nls.messages";
+ // END android-changed
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ // BEGIN android-changed
+ return MsgHelp.getString(sResource, msg);
+ // END android-changed
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ // BEGIN android-changed
+ return MsgHelp.getString(sResource, msg, args);
+ // END android-changed
+ }
+
+ // BEGIN android-note
+ // Duplicate code was dropped in favor of using MsgHelp.
+ // END android-note
+}
diff --git a/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties b/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
new file mode 100644
index 0000000..1ae5c5e
--- /dev/null
+++ b/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
@@ -0,0 +1,67 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# messages for EN locale
+archive.00=Canonical encodings have been incorrectly modified
+archive.01=Encoding cannot be less than zero
+archive.02=End of buffer read whilst trying to decode codec
+archive.03=End of buffer read whilst trying to decode codec
+archive.04=ADef and BDef should never both be true
+archive.05=Invalid codec encoding byte ({0}) found
+archive.06=Something has gone wrong during parsing references
+archive.07=Bad header
+archive.08=Invalid segment major version
+archive.09=Invalid segment minor version
+archive.0A=There are attribute flags, and I don't know what to do with them
+archive.0B=Not yet implemented
+archive.0C=No idea what the adc is for yet
+archive.0D=Failed to read some data from input stream
+archive.0E=Failed to read any data from input stream
+archive.0F=L must be between 1..255
+archive.10=Population encoding does not work unless the number of elements are known
+archive.11=Cannot calculate token codec from {0} and {1}
+archive.12=Cannot have a RunCodec for a negative number of numbers
+archive.13=Must supply both codecs for a RunCodec
+archive.14=Some unused flags are non-zero
+archive.15=1<=b<=5
+archive.16=1<=h<=256
+archive.17=0<=s<=2
+archive.18=0<=d<=1
+archive.19=b=1 -> h=256
+archive.1A=h=256 -> b\!=5
+archive.1B=Delta encoding used without passing in last value; this is a coding error
+archive.1C=End of stream reached whilst decoding
+archive.1D=Unknown s value
+archive.1E=Stream is closed
+archive.1F=Unknown format
+archive.20=Crc mismatch
+archive.21=Size mismatch
+archive.22=Cannot read version
+archive.23=Entry is not named
+archive.24=Unable to open\: {0}
+archive.25=Invalid zip file\: {0}
+archive.26=attempt to write after finish
+archive.27=Needs dictionary
+archive.28=No entries
+archive.29=Entry already exists: {0}
+archive.2A=Name too long: {0}
+archive.2B=String is too long
+archive.2C=No active entry
+archive.2D=Missing version string\: {0}
+archive.2E=Line too long
+archive.2F=Invalid attribute {0}
+archive.30={0} failed verification of {1}
+archive.31={0} has invalid digest for {1} in {2}
diff --git a/archive/src/main/java/org/apache/harmony/archive/util/Util.java b/archive/src/main/java/org/apache/harmony/archive/util/Util.java
new file mode 100644
index 0000000..bed3e91
--- /dev/null
+++ b/archive/src/main/java/org/apache/harmony/archive/util/Util.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.util;
+
+public class Util {
+
+ public static boolean ASCIIIgnoreCaseRegionMatches(String s1, int start1,
+ String s2, int start2, int length) {
+
+ if (s1 != null && s2 != null) {
+ if (start1 < 0 || length > s1.length() - start1) {
+ return false;
+ }
+ if (start2 < 0 || length > s2.length() - start2) {
+ return false;
+ }
+
+ s1 = s1.substring(start1, start1 + length);
+ s2 = s2.substring(start2, start2 + length);
+
+ return toASCIILowerCase(s1).equals(toASCIILowerCase(s2));
+ }
+ throw new NullPointerException();
+ }
+
+ public static String toASCIILowerCase(String s) {
+ int len = s.length();
+ StringBuilder buffer = new StringBuilder(len);
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ if ('A' <= c && c <= 'Z') {
+ buffer.append((char) (c + ('a' - 'A')));
+ } else {
+ buffer.append(c);
+ }
+ }
+ return buffer.toString();
+ }
+
+ public static String toASCIIUpperCase(String s) {
+ int len = s.length();
+ StringBuilder buffer = new StringBuilder(len);
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ if ('a' <= c && c <= 'z') {
+ buffer.append((char) (c - ('a' - 'A')));
+ } else {
+ buffer.append(c);
+ }
+ }
+ return buffer.toString();
+ }
+}
diff --git a/archive/src/main/native/hy2sie.h b/archive/src/main/native/hy2sie.h
new file mode 100644
index 0000000..d40d0e8
--- /dev/null
+++ b/archive/src/main/native/hy2sie.h
@@ -0,0 +1,114 @@
+#if !defined(hy2sie_h)
+#define hy2sie_h
+
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "sieb.h"
+
+
+typedef int BOOLEAN;
+#define TRUE 1
+#define FALSE 0
+
+
+// mc: Stuff adopted from hyport.h:
+
+/** HyMaxPath was chosen from unix MAXPATHLEN. Override in platform
+ * specific hyfile implementations if needed.
+ */
+#define HyMaxPath 1024
+
+
+
+// Following definitions from hycomp.h:
+
+/**
+ * Define common types:
+ * <ul>
+ * <li><code>U_32 / I_32</code> - unsigned/signed 32 bits</li>
+ * <li><code>U_16 / I_16</code> - unsigned/signed 16 bits</li>
+ * <li><code>U_8 / I_8</code> - unsigned/signed 8 bits (bytes -- not to be
+ * confused with char)</li>
+ * </ul>
+ */
+
+typedef int I_32;
+typedef short I_16;
+typedef signed char I_8; /* chars can be unsigned */
+typedef unsigned int U_32;
+typedef unsigned short U_16;
+typedef unsigned char U_8;
+
+typedef long long I_64;
+typedef unsigned long long U_64;
+
+/**
+ * Define platform specific types:
+ * <ul>
+ * <li><code>UDATA</code> - unsigned data, can be used as an integer or
+ * pointer storage</li>
+ * <li><code>IDATA</code> - signed data, can be used as an integer or
+ * pointer storage</li>
+ * </ul>
+ */
+/* FIXME: POINTER64 */
+
+typedef I_32 IDATA;
+typedef U_32 UDATA;
+
+
+// Further required definitions from Harmony:
+
+#define HYCONST64(x) x##L
+
+
+#define HY_CFUNC
+#define HY_CDATA
+#define PROTOTYPE(x) x
+#define VMCALL
+#define PVMCALL *
+#define NORETURN
+
+#define GLOBAL_DATA(symbol) ((void*)&(symbol))
+
+
+// Following definitions substitute the HyPortLibrary simply with the JNIEnv
+
+typedef JNIEnv HyPortLibrary;
+
+#define PORT_ACCESS_FROM_ENV(env) HyPortLibrary *privatePortLibrary = env
+#define PORT_ACCESS_FROM_PORT(portLibrary) HyPortLibrary *privatePortLibrary = portLibrary
+#define PORTLIB privatePortLibrary
+
+
+// Following defintion is used to avoide quite a few signedness warnings:
+#define mcSignednessBull void *
+
+
+// Following the substitution of hyfile:
+
+#include <fcntl.h>
+
+#define HyOpenRead O_RDONLY
+#define hyfile_open(a, b, c) open(a, b, c)
+
+#define HySeekEnd SEEK_END
+#define HySeekSet SEEK_SET
+#define HySeekCur SEEK_CUR
+#define hyfile_seek(a, b, c) lseek(a, b, c)
+
+#define hyfile_read(a, b, c) read(a, b, c)
+
+#define hyfile_close(a) close(a)
+
+
+// And further substitutions:
+
+#define hymem_allocate_memory(byteCount) sieb_malloc(privatePortLibrary, byteCount)
+#define hymem_free_memory(pointer) sieb_free(privatePortLibrary, pointer)
+
+#define ioh_convertToPlatform(path) sieb_convertToPlatform (path)
+
+
+#endif /* hy2sie_h */
diff --git a/archive/src/main/native/hycomp.h b/archive/src/main/native/hycomp.h
new file mode 100644
index 0000000..029d4fe
--- /dev/null
+++ b/archive/src/main/native/hycomp.h
@@ -0,0 +1 @@
+#include "hy2sie.h"
diff --git a/archive/src/main/native/hymutex.h b/archive/src/main/native/hymutex.h
new file mode 100644
index 0000000..5c98ebd
--- /dev/null
+++ b/archive/src/main/native/hymutex.h
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(hymutex_h)
+#define hymutex_h
+
+#include <pthread.h>
+#include <stdlib.h>
+
+typedef pthread_mutex_t MUTEX;
+
+/* MUTEX_INIT */
+#define MUTEX_INIT(mutex) (pthread_mutex_init(&(mutex), NULL) == 0)
+
+/* MUTEX_DESTROY */
+#define MUTEX_DESTROY(mutex) pthread_mutex_destroy(&(mutex))
+
+/* MUTEX_ENTER */
+#define MUTEX_ENTER(mutex) pthread_mutex_lock(&(mutex))
+
+/*
+ * MUTEX_TRY_ENTER
+ * returns 0 on success
+ */
+#define MUTEX_TRY_ENTER(mutex) pthread_mutex_trylock(&(mutex))
+
+/* MUTEX_EXIT */
+#define MUTEX_EXIT(mutex) pthread_mutex_unlock(&(mutex))
+
+#endif /* hymutex_h */
diff --git a/archive/src/main/native/hyport.h b/archive/src/main/native/hyport.h
new file mode 100644
index 0000000..029d4fe
--- /dev/null
+++ b/archive/src/main/native/hyport.h
@@ -0,0 +1 @@
+#include "hy2sie.h"
diff --git a/archive/src/main/native/java_util_zip_Adler32.c b/archive/src/main/native/java_util_zip_Adler32.c
new file mode 100644
index 0000000..a7a182a
--- /dev/null
+++ b/archive/src/main/native/java_util_zip_Adler32.c
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hy2sie.h"
+
+#include "zlib.h"
+
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Adler32_updateImpl (JNIEnv * env, jobject recv,
+ jbyteArray buf, int off, int len,
+ jlong crc)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ jbyte *b;
+ jboolean isCopy;
+ jlong result;
+
+ b = (*env)->GetPrimitiveArrayCritical (env, buf, &isCopy);
+ result = (jlong) adler32 ((uLong) crc, (Bytef *) (b + off), (uInt) len);
+ (*env)->ReleasePrimitiveArrayCritical (env, buf, b, JNI_ABORT);
+
+ return result;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Adler32_updateByteImpl (JNIEnv * env, jobject recv,
+ jint val, jlong crc)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ return adler32 ((uLong) crc, (Bytef *) (&val), 1);
+}
+
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "updateImpl", "([BIIJ)J", Java_java_util_zip_Adler32_updateImpl },
+ { "updateByteImpl", "(IJ)J", Java_java_util_zip_Adler32_updateByteImpl },
+};
+int register_java_util_zip_Adler32(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/util/zip/Adler32",
+ gMethods, NELEM(gMethods));
+}
diff --git a/archive/src/main/native/java_util_zip_CRC32.c b/archive/src/main/native/java_util_zip_CRC32.c
new file mode 100644
index 0000000..0688868
--- /dev/null
+++ b/archive/src/main/native/java_util_zip_CRC32.c
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hy2sie.h"
+
+#include "zlib.h"
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_CRC32_updateImpl (JNIEnv * env, jobject recv,
+ jbyteArray buf, int off, int len,
+ jlong crc)
+{
+ jbyte *b;
+ jlong result;
+
+ b = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
+ if (b == NULL)
+ return -1;
+ result = crc32 ((uLong) crc, (Bytef *) (b + off), (uInt) len);
+ ((*env)->ReleasePrimitiveArrayCritical (env, buf, b, JNI_ABORT));
+ return result;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_CRC32_updateByteImpl (JNIEnv * env, jobject recv,
+ jbyte val, jlong crc)
+{
+ return crc32 ((uLong) crc, (Bytef *) (&val), 1);
+}
+
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "updateImpl", "([BIIJ)J", Java_java_util_zip_CRC32_updateImpl },
+ { "updateByteImpl", "(BJ)J", Java_java_util_zip_CRC32_updateByteImpl },
+};
+int register_java_util_zip_CRC32(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/util/zip/CRC32",
+ gMethods, NELEM(gMethods));
+}
diff --git a/archive/src/main/native/java_util_zip_Deflater.c b/archive/src/main/native/java_util_zip_Deflater.c
new file mode 100644
index 0000000..c8bd199
--- /dev/null
+++ b/archive/src/main/native/java_util_zip_Deflater.c
@@ -0,0 +1,312 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hy2sie.h"
+
+#include "zlib.h"
+#include "zipsup.h"
+
+
+void zfree PROTOTYPE ((void *opaque, void *address));
+void *zalloc PROTOTYPE ((void *opaque, U_32 items, U_32 size));
+
+
+static struct {
+ jfieldID inRead;
+ jfieldID finished;
+} gCachedFields;
+
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_setDictionaryImpl (JNIEnv * env, jobject recv,
+ jbyteArray dict, int off,
+ int len, jlong handle)
+{
+ PORT_ACCESS_FROM_ENV (env);
+ int err = 0;
+ unsigned char *dBytes;
+ JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle);
+
+ dBytes = jclmem_allocate_memory (env, len);
+ if (dBytes == NULL)
+ {
+ throwNewOutOfMemoryError (env, "");
+ return;
+ }
+ (*env)->GetByteArrayRegion (env, dict, off, len, (mcSignednessBull)dBytes);
+ err = deflateSetDictionary (stream->stream, (Bytef *) dBytes, len);
+ if (err != Z_OK)
+ {
+ jclmem_free_memory (env, dBytes);
+ throwNewIllegalArgumentException (env, "");
+ return;
+ }
+ stream->dict = dBytes;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_getTotalInImpl (JNIEnv * env, jobject recv,
+ jlong handle)
+{
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+ return stream->stream->total_in;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_getTotalOutImpl (JNIEnv * env, jobject recv,
+ jlong handle)
+{
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+ return stream->stream->total_out;
+}
+
+JNIEXPORT jint JNICALL
+Java_java_util_zip_Deflater_getAdlerImpl (JNIEnv * env, jobject recv,
+ jlong handle)
+{
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+
+ return stream->stream->adler;
+}
+
+/* Create a new stream . This stream cannot be used until it has been properly initialized. */
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_createStream (JNIEnv * env, jobject recv,
+ jint level, jint strategy,
+ jboolean noHeader)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ JCLZipStream *jstream;
+ z_stream *stream;
+ int err = 0;
+ // BEGIN android-changed
+ int wbits = 12; // Was 15, made it 12 to reduce memory consumption. Use MAX
+ // for fastest.
+ int mlevel = 5; // Was 9, made it 5 to reduce memory consumption. Might result
+ // in out-of-memory problems according to some web pages. The
+ // ZLIB docs are a bit vague, unfortunately. The default
+ // results in 2 x 128K being allocated per Deflater, which is
+ // not acceptable.
+ // END android-changed
+
+ /*Allocate mem for wrapped struct */
+ jstream = jclmem_allocate_memory (env, sizeof (JCLZipStream));
+ if (jstream == NULL)
+ {
+ throwNewOutOfMemoryError (env, "");
+ return -1;
+ }
+ /*Allocate the z_stream */
+ stream = jclmem_allocate_memory (env, sizeof (z_stream));
+ if (stream == NULL)
+ {
+ jclmem_free_memory (env, jstream);
+ throwNewOutOfMemoryError (env, "");
+ return -1;
+ }
+ stream->opaque = (void *) privatePortLibrary;
+ stream->zalloc = zalloc;
+ stream->zfree = zfree;
+ jstream->stream = stream;
+ jstream->dict = NULL;
+ jstream->inaddr = NULL;
+
+ /*Unable to find official doc that this is the way to avoid zlib header use. However doc in zipsup.c claims it is so */
+ if (noHeader)
+ wbits = wbits / -1;
+ err = deflateInit2 (stream, level, Z_DEFLATED, /*Only supported ZLIB method */
+ wbits, /*Window bits to use. 15 is fastest but consumes the most memory */
+ // BEGIN android-changed
+ mlevel, /*Memory allocation for internal compression state. 9 uses the most. */
+ // END android-changed
+ strategy);
+ if (err != Z_OK)
+ {
+ throwNewIllegalArgumentException (env, "");
+ return -1;
+ }
+
+ return (jlong) ((IDATA) jstream);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_setInputImpl (JNIEnv * env, jobject recv,
+ jbyteArray buf, jint off, jint len,
+ jlong handle)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ jbyte *in;
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+ if (stream->inaddr != NULL) /*Input has already been provided, free the old buffer */
+ jclmem_free_memory (env, stream->inaddr);
+ stream->inaddr = jclmem_allocate_memory (env, len);
+ if (stream->inaddr == NULL)
+ {
+ throwNewOutOfMemoryError (env, "");
+ return;
+ }
+ in = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
+ if (in == NULL)
+ return;
+ memcpy (stream->inaddr, (in + off), len);
+ ((*env)->ReleasePrimitiveArrayCritical (env, buf, in, JNI_ABORT));
+ stream->stream->next_in = (Bytef *) stream->inaddr;
+ stream->stream->avail_in = len;
+
+ return;
+}
+
+JNIEXPORT jint JNICALL
+Java_java_util_zip_Deflater_deflateImpl (JNIEnv * env, jobject recv,
+ jbyteArray buf, int off, int len,
+ jlong handle, int flushParm)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ jbyte *out;
+ JCLZipStream *stream;
+ jint err = 0;
+ jint sin, sout, inBytes = 0;
+
+ /* We need to get the number of bytes already read */
+ inBytes =
+ ((*env)->
+ GetIntField (env, recv,
+ gCachedFields.inRead));
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+ stream->stream->avail_out = len;
+ sin = stream->stream->total_in;
+ sout = stream->stream->total_out;
+ out = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
+ if (out == NULL)
+ return -1;
+ stream->stream->next_out = (Bytef *) out + off;
+ err = deflate (stream->stream, flushParm);
+ ((*env)->ReleasePrimitiveArrayCritical (env, buf, out, 0));
+ if (err != Z_OK)
+ {
+ if (err == Z_STREAM_END)
+ {
+ ((*env)->
+ SetBooleanField (env, recv,
+ gCachedFields.finished,
+ JNI_TRUE));
+ return stream->stream->total_out - sout;
+ }
+ }
+ if (flushParm != Z_FINISH)
+ {
+ /* Need to update the number of input bytes read. */
+ ((*env)->
+ SetIntField (env, recv,
+ gCachedFields.inRead,
+ (jint) stream->stream->total_in - sin + inBytes));
+ }
+ return stream->stream->total_out - sout;
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_endImpl (JNIEnv * env, jobject recv, jlong handle)
+{
+ PORT_ACCESS_FROM_ENV (env);
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+
+ deflateEnd (stream->stream);
+ if (stream->inaddr != NULL)
+ jclmem_free_memory (env, stream->inaddr);
+ if (stream->dict != NULL)
+ jclmem_free_memory (env, stream->dict);
+ jclmem_free_memory (env, stream->stream);
+ jclmem_free_memory (env, stream);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_resetImpl (JNIEnv * env, jobject recv,
+ jlong handle)
+{
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+ deflateReset (stream->stream);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_setLevelsImpl (JNIEnv * env, jobject recv,
+ int level, int strategy,
+ jlong handle)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ JCLZipStream *stream;
+ jbyte b = 0;
+ int err = 0;
+
+ if (handle == -1)
+ {
+ throwNewIllegalStateException (env, "");
+ return;
+ }
+ stream = (JCLZipStream *) ((IDATA) handle);
+ stream->stream->next_out = (Bytef *) & b;
+ err = deflateParams (stream->stream, level, strategy);
+ if (err != Z_OK)
+ throwNewIllegalStateException (env, "");
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_oneTimeInitialization (JNIEnv * env, jclass clazz)
+{
+ memset(&gCachedFields, 0, sizeof(gCachedFields));
+ gCachedFields.inRead = (*env)->GetFieldID (env, clazz, "inRead", "I");
+ gCachedFields.finished = (*env)->GetFieldID (env, clazz, "finished", "Z");
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "setDictionaryImpl", "([BIIJ)V", Java_java_util_zip_Deflater_setDictionaryImpl },
+ { "getTotalInImpl", "(J)J", Java_java_util_zip_Deflater_getTotalInImpl },
+ { "getTotalOutImpl", "(J)J", Java_java_util_zip_Deflater_getTotalOutImpl },
+ { "getAdlerImpl", "(J)I", Java_java_util_zip_Deflater_getAdlerImpl },
+ { "createStream", "(IIZ)J", Java_java_util_zip_Deflater_createStream },
+ { "setInputImpl", "([BIIJ)V", Java_java_util_zip_Deflater_setInputImpl },
+ { "deflateImpl", "([BIIJI)I", Java_java_util_zip_Deflater_deflateImpl },
+ { "endImpl", "(J)V", Java_java_util_zip_Deflater_endImpl },
+ { "resetImpl", "(J)V", Java_java_util_zip_Deflater_resetImpl },
+ { "setLevelsImpl", "(IIJ)V", Java_java_util_zip_Deflater_setLevelsImpl },
+ { "oneTimeInitialization", "()V", Java_java_util_zip_Deflater_oneTimeInitialization },
+};
+int register_java_util_zip_Deflater(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/util/zip/Deflater",
+ gMethods, NELEM(gMethods));
+}
diff --git a/archive/src/main/native/java_util_zip_Inflater.c b/archive/src/main/native/java_util_zip_Inflater.c
new file mode 100644
index 0000000..d3a7d7c
--- /dev/null
+++ b/archive/src/main/native/java_util_zip_Inflater.c
@@ -0,0 +1,356 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hy2sie.h"
+
+#include "zlib.h"
+#include <memory.h>
+#define jclmem_allocate_memory(env, byteCount) sieb_malloc(env, byteCount)
+#define jclmem_free_memory(env, pointer) sieb_free(env, pointer)
+
+#include <fcntl.h>
+
+
+void zfree PROTOTYPE ((void *opaque, void *address));
+void *zalloc PROTOTYPE ((void *opaque, U_32 items, U_32 size));
+
+
+static struct {
+ jfieldID inRead;
+ jfieldID finished;
+ jfieldID needsDictionary;
+} gCachedFields;
+
+
+// Contents from Harmony's inflater.h was put here:
+//
+typedef struct JCLZipStream
+{
+ U_8 *inaddr;
+ int inCap;
+ U_8 *dict;
+ z_stream *stream;
+} JCLZipStream;
+
+
+
+/**
+ * Throw java.util.zip.DataFormatException
+ */
+void
+throwNewDataFormatException (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/util/zip/DataFormatException", message);
+}
+
+
+/* Create a new stream . This stream cannot be used until it has been properly initialized. */
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_createStream (JNIEnv * env, jobject recv,
+ jboolean noHeader)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ JCLZipStream *jstream;
+ z_stream *stream;
+ int err = 0;
+ int wbits = 15; /*Use MAX for fastest */
+
+ /*Allocate mem for wrapped struct */
+ jstream = jclmem_allocate_memory (env, sizeof (JCLZipStream));
+ if (jstream == NULL)
+ {
+ throwNewOutOfMemoryError (env, "");
+ return -1;
+ }
+
+ /*Allocate the z_stream */
+ stream = jclmem_allocate_memory (env, sizeof (z_stream));
+ if (stream == NULL)
+ {
+ jclmem_free_memory (env, jstream);
+ throwNewOutOfMemoryError (env, "");
+ return -1;
+ }
+ stream->opaque = (void *) privatePortLibrary;
+ stream->zalloc = zalloc;
+ stream->zfree = zfree;
+ stream->adler = 1;
+ jstream->stream = stream;
+ jstream->dict = NULL;
+ jstream->inaddr = NULL;
+ jstream->inCap = 0;
+
+ /*Unable to find official doc that this is the way to avoid zlib header use. However doc in zipsup.c claims it is so. */
+ if (noHeader)
+ wbits = wbits / -1;
+ err = inflateInit2 (stream, wbits); /*Window bits to use. 15 is fastest but consumes the most memory */
+
+ if (err != Z_OK)
+ {
+ jclmem_free_memory (env, stream);
+ jclmem_free_memory (env, jstream);
+ throwNewIllegalArgumentException (env, "");
+ return -1;
+ }
+
+ return (jlong) ((IDATA) jstream);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Inflater_setInputImpl (JNIEnv * env, jobject recv,
+ jbyteArray buf, jint off, jint len,
+ jlong handle)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ jbyte *in;
+ U_8 *baseAddr;
+ JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle);
+
+ if (stream->inaddr != NULL) /*Input has already been provided, free the old buffer */
+ jclmem_free_memory (env, stream->inaddr);
+ baseAddr = jclmem_allocate_memory (env, len);
+ if (baseAddr == NULL)
+ {
+ throwNewOutOfMemoryError (env, "");
+ return;
+ }
+ stream->inaddr = baseAddr;
+ stream->stream->next_in = (Bytef *) baseAddr;
+ stream->stream->avail_in = len;
+ in = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
+ if (in == NULL)
+ return;
+ memcpy (baseAddr, (in + off), len);
+ ((*env)->ReleasePrimitiveArrayCritical (env, buf, in, JNI_ABORT));
+ return;
+}
+
+JNIEXPORT jint JNICALL
+Java_java_util_zip_Inflater_setFileInputImpl (JNIEnv * env, jobject recv,
+ jobject javaFileDescriptor, jlong off, jint len, jlong handle)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ U_8 * baseAddr;
+ JCLZipStream * stream = (JCLZipStream *) ((IDATA) handle);
+
+ if (stream->inCap < len) {
+ // No input buffer as yet (or one that is too small).
+ jclmem_free_memory(env, stream->inaddr);
+ baseAddr = jclmem_allocate_memory(env, len);
+ if (baseAddr == NULL)
+ {
+ throwNewOutOfMemoryError(env, "");
+ return -1;
+ }
+ stream->inaddr = baseAddr;
+ }
+ stream->stream->next_in = (Bytef *) stream->inaddr;
+ stream->stream->avail_in = len;
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
+ lseek(fd, off, SEEK_SET);
+ int cnt = read(fd, stream->inaddr, len);
+
+ return cnt;
+}
+
+JNIEXPORT jint JNICALL
+Java_java_util_zip_Inflater_inflateImpl (JNIEnv * env, jobject recv,
+ jbyteArray buf, int off, int len,
+ jlong handle)
+{
+ PORT_ACCESS_FROM_ENV (env);
+
+ jbyte *out;
+ JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle);
+ jint err = 0;
+ jfieldID fid = 0, fid2 = 0;
+ jint sin, sout, inBytes = 0;
+
+ /* We need to get the number of bytes already read */
+ fid = gCachedFields.inRead;
+ inBytes = ((*env)->GetIntField (env, recv, fid));
+
+ stream->stream->avail_out = len;
+ sin = stream->stream->total_in;
+ sout = stream->stream->total_out;
+ out = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
+
+ if (out == NULL)
+ return -1;
+ stream->stream->next_out = (Bytef *) out + off;
+ err = inflate (stream->stream, Z_SYNC_FLUSH);
+ ((*env)->ReleasePrimitiveArrayCritical (env, buf, out, 0));
+
+ if (err != Z_OK)
+ {
+ if(err == Z_STREAM_ERROR) {
+ return 0;
+ }
+ if (err == Z_STREAM_END || err == Z_NEED_DICT)
+ {
+ ((*env)->SetIntField (env, recv, fid, (jint) stream->stream->total_in - sin + inBytes)); /* Update inRead */
+ if (err == Z_STREAM_END)
+ fid2 = gCachedFields.finished;
+ else
+ fid2 = gCachedFields.needsDictionary;
+
+ ((*env)->SetBooleanField (env, recv, fid2, JNI_TRUE));
+ return stream->stream->total_out - sout;
+ }
+ else
+ {
+ throwNewDataFormatException (env, "");
+ return -1;
+ }
+ }
+
+ /* Need to update the number of input bytes read. Is there a better way
+ * (Maybe global the fid then delete when end is called)?
+ */
+ ((*env)->
+ SetIntField (env, recv, fid,
+ (jint) stream->stream->total_in - sin + inBytes));
+
+ return stream->stream->total_out - sout;
+}
+
+JNIEXPORT jint JNICALL
+Java_java_util_zip_Inflater_getAdlerImpl (JNIEnv * env, jobject recv,
+ jlong handle)
+{
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+
+ return stream->stream->adler;
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Inflater_endImpl (JNIEnv * env, jobject recv, jlong handle)
+{
+ PORT_ACCESS_FROM_ENV (env);
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+ inflateEnd (stream->stream);
+ if (stream->inaddr != NULL) /*Input has been provided, free the buffer */
+ jclmem_free_memory (env, stream->inaddr);
+ if (stream->dict != NULL)
+ jclmem_free_memory (env, stream->dict);
+ jclmem_free_memory (env, stream->stream);
+ jclmem_free_memory (env, stream);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Inflater_setDictionaryImpl (JNIEnv * env, jobject recv,
+ jbyteArray dict, int off,
+ int len, jlong handle)
+{
+ PORT_ACCESS_FROM_ENV (env);
+ int err = 0;
+ U_8 *dBytes;
+ JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle);
+
+ dBytes = jclmem_allocate_memory (env, len);
+ if (dBytes == NULL)
+ {
+ throwNewOutOfMemoryError (env, "");
+ return;
+ }
+ (*env)->GetByteArrayRegion (env, dict, off, len, (mcSignednessBull)dBytes);
+ err = inflateSetDictionary (stream->stream, (Bytef *) dBytes, len);
+ if (err != Z_OK)
+ {
+ jclmem_free_memory (env, dBytes);
+ throwNewIllegalArgumentException (env, "");
+ return;
+ }
+ stream->dict = dBytes;
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Inflater_resetImpl (JNIEnv * env, jobject recv,
+ jlong handle)
+{
+ JCLZipStream *stream;
+ int err = 0;
+ stream = (JCLZipStream *) ((IDATA) handle);
+
+ err = inflateReset (stream->stream);
+ if (err != Z_OK)
+ {
+ throwNewIllegalArgumentException (env, "");
+ return;
+ }
+}
+
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_getTotalOutImpl (JNIEnv * env, jobject recv,
+ jlong handle)
+{
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+ return stream->stream->total_out;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_getTotalInImpl (JNIEnv * env, jobject recv,
+ jlong handle)
+{
+ JCLZipStream *stream;
+
+ stream = (JCLZipStream *) ((IDATA) handle);
+ return stream->stream->total_in;
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Inflater_oneTimeInitialization (JNIEnv * env, jclass clazz)
+{
+ memset(&gCachedFields, 0, sizeof(gCachedFields));
+ gCachedFields.inRead = (*env)->GetFieldID (env, clazz, "inRead", "I");
+ gCachedFields.finished = (*env)->GetFieldID (env, clazz, "finished", "Z");
+ gCachedFields.needsDictionary = (*env)->GetFieldID (env, clazz, "needsDictionary", "Z");
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "createStream", "(Z)J", Java_java_util_zip_Inflater_createStream },
+ { "setInputImpl", "([BIIJ)V", Java_java_util_zip_Inflater_setInputImpl },
+ { "setFileInputImpl", "(Ljava/io/FileDescriptor;JIJ)I", Java_java_util_zip_Inflater_setFileInputImpl },
+ { "inflateImpl", "([BIIJ)I", Java_java_util_zip_Inflater_inflateImpl },
+ { "getAdlerImpl", "(J)I", Java_java_util_zip_Inflater_getAdlerImpl },
+ { "endImpl", "(J)V", Java_java_util_zip_Inflater_endImpl },
+ { "setDictionaryImpl", "([BIIJ)V", Java_java_util_zip_Inflater_setDictionaryImpl },
+ { "resetImpl", "(J)V", Java_java_util_zip_Inflater_resetImpl },
+ { "getTotalOutImpl", "(J)J", Java_java_util_zip_Inflater_getTotalOutImpl },
+ { "getTotalInImpl", "(J)J", Java_java_util_zip_Inflater_getTotalInImpl },
+ { "oneTimeInitialization", "()V", Java_java_util_zip_Inflater_oneTimeInitialization },
+};
+int register_java_util_zip_Inflater(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/util/zip/Inflater",
+ gMethods, NELEM(gMethods));
+}
diff --git a/archive/src/main/native/sieb.c b/archive/src/main/native/sieb.c
new file mode 100644
index 0000000..ab9430b
--- /dev/null
+++ b/archive/src/main/native/sieb.c
@@ -0,0 +1,54 @@
+#include "sieb.h"
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <malloc.h>
+
+// Throw java.lang.OutOfMemoryError
+void throwNewOutOfMemoryError (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/lang/OutOfMemoryError", message);
+}
+
+// Throw java.lang.IllegalStateException
+void throwNewIllegalStateException (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/lang/IllegalStateException", message);
+}
+
+// Throw java.lang.IllegalArgumentException
+void throwNewIllegalArgumentException (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/lang/IllegalArgumentException", message);
+}
+
+
+
+void * sieb_malloc (JNIEnv * env, size_t byteCnt) {
+ void * adr = malloc(byteCnt);
+ if (adr == 0) {
+ if (byteCnt == 0)
+ throwNewOutOfMemoryError(env, "sieb_malloc(0) NOT ALLOWED");
+ else
+ throwNewOutOfMemoryError(env, "sieb_malloc");
+ }
+ return adr;
+}
+
+void sieb_free (JNIEnv * env, void * adr) {
+ free(adr);
+}
+
+
+
+void sieb_convertToPlatform (char *path) {
+ char *pathIndex;
+
+ pathIndex = path;
+ while (*pathIndex != '\0') {
+ if(*pathIndex == '\\') {
+ *pathIndex = '/';
+ }
+ pathIndex++;
+ }
+}
diff --git a/archive/src/main/native/sieb.h b/archive/src/main/native/sieb.h
new file mode 100644
index 0000000..536c806
--- /dev/null
+++ b/archive/src/main/native/sieb.h
@@ -0,0 +1,22 @@
+#if !defined(sieb_h)
+#define sieb_h
+
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+
+
+void throwNewOutOfMemoryError (JNIEnv * env, const char *message);
+void throwNewIllegalArgumentException (JNIEnv * env, const char *message);
+void throwNewIllegalStateException (JNIEnv * env, const char *message);
+
+
+void * sieb_malloc (JNIEnv * env, size_t byteCnt);
+void sieb_free (JNIEnv * env, void * adr);
+
+void sieb_convertToPlatform (char *path);
+
+
+
+#endif /* sieb_h */
diff --git a/archive/src/main/native/sub.mk b/archive/src/main/native/sub.mk
new file mode 100644
index 0000000..047c319
--- /dev/null
+++ b/archive/src/main/native/sub.mk
@@ -0,0 +1,23 @@
+# This file is included by the top-level libcore Android.mk.
+# It's not a normal makefile, so we don't include CLEAR_VARS
+# or BUILD_*_LIBRARY.
+
+LOCAL_SRC_FILES := \
+ java_util_zip_Adler32.c \
+ java_util_zip_CRC32.c \
+ java_util_zip_Deflater.c \
+ java_util_zip_Inflater.c \
+ zipalloc.c \
+ sieb.c
+
+LOCAL_C_INCLUDES += \
+ external/zlib
+
+# Any shared/static libs that are listed here must also
+# be listed in libs/nativehelper/Android.mk.
+# TODO: fix this requirement
+
+LOCAL_SHARED_LIBRARIES += \
+ libz
+
+LOCAL_STATIC_LIBRARIES +=
diff --git a/archive/src/main/native/zipalloc.c b/archive/src/main/native/zipalloc.c
new file mode 100644
index 0000000..2b4966b
--- /dev/null
+++ b/archive/src/main/native/zipalloc.c
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hyport.h"
+
+#include "zlib.h"
+
+#define CDEV_CURRENT_FUNCTION _prototypes_private
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION _prototypes_public
+void *zalloc PROTOTYPE ((void *opaque, U_32 items, U_32 size));
+void zfree PROTOTYPE ((void *opaque, void *address));
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zalloc
+
+/*
+ ZLib interface to hymem_allocate_memory.
+*/
+void *
+zalloc (void *opaque, U_32 items, U_32 size)
+{
+ PORT_ACCESS_FROM_PORT (((HyPortLibrary *) opaque));
+
+ return hymem_allocate_memory (items * size);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zfree
+
+/*
+ ZLib interface to hymem_free_memory.
+*/
+void
+zfree (void *opaque, void *address)
+{
+ PORT_ACCESS_FROM_PORT ((HyPortLibrary *) opaque);
+
+ hymem_free_memory (address);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION
+
+#undef CDEV_CURRENT_FUNCTION
diff --git a/archive/src/main/native/zipsup.c b/archive/src/main/native/zipsup.c
new file mode 100644
index 0000000..1bbe51f
--- /dev/null
+++ b/archive/src/main/native/zipsup.c
@@ -0,0 +1,2319 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * @ingroup ZipSupport
+ * @brief Zip Support for Java VM
+*/
+
+#include <string.h>
+#include <sys/stat.h>
+
+#include "hy2sie.h"
+#include "zipsup.h"
+
+#include "zlib.h"
+
+// zlib is statically linked for Android:
+#define checkZipLibrary(dummy) 0
+#ifdef checkZipLibrary
+#define inflateInit2Func(a, b, c, d) inflateInit2_ (a, b, c, d)
+#define inflateFunc(a, b) inflate (a, b)
+#define inflateEndFunc(a) inflateEnd (a)
+#else
+/* Globals for the zip library */
+UDATA zipDLLDescriptor = 0;
+int (*inflateInit2Func) (void *, int, const char *, int);
+int (*inflateFunc) (void *, int);
+int (*inflateEndFunc) (void *);
+#endif
+
+#define ZIP_NEXT_U8(value, index) (value = *(index++))
+#define ZIP_NEXT_U16(value, index) ((value = (index[1] << 8) | index[0]), index += 2, value)
+#define ZIP_NEXT_U32(value, index) ((value = ((U_32)index[3] << 24) | ((U_32)index[2] << 16) | ((U_32)index[1] << 8) | (U_32)index[0]), index += 4, value)
+
+#define WORK_BUFFER_SIZE 64000
+
+#define SCAN_CHUNK_SIZE 1024
+
+struct workBuffer
+{
+ HyPortLibrary *portLib;
+ UDATA *bufferStart;
+ UDATA *bufferEnd;
+ UDATA *currentAlloc;
+ UDATA cntr;
+};
+
+#define CDEV_CURRENT_FUNCTION _prototypes_private
+I_32 zip_populateCache
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile));
+
+static I_32 inflateData
+PROTOTYPE ((struct workBuffer * workBuf, U_8 * inputBuffer,
+ U_32 inputBufferSize, U_8 * outputBuffer, U_32 outputBufferSize));
+
+I_32 checkZipLibrary PROTOTYPE ((HyPortLibrary * portLib));
+
+I_32 scanForDataDescriptor
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * zipEntry));
+void zdatafree PROTOTYPE ((void *opaque, void *address));
+static I_32 readZipEntry
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * zipEntry, const char *filename,
+ IDATA * enumerationPointer, IDATA * entryStart,
+ BOOLEAN findDirectory));
+I_32 scanForCentralEnd
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipCentralEnd * endEntry));
+void *zdataalloc PROTOTYPE ((void *opaque, U_32 items, U_32 size));
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION _prototypes_public
+I_32 zip_getZipEntryData
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile, HyZipEntry * entry,
+ U_8 * buffer, U_32 bufferSize));
+I_32 zip_getZipEntryFromOffset
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile, HyZipEntry * entry,
+ IDATA offset));
+I_32 zip_establishCache
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile));
+void zip_resetZipFile
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ IDATA * nextEntryPointer));
+I_32 zip_getNextZipEntry
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * zipEntry, IDATA * nextEntryPointer));
+I_32 zip_getZipEntry
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile, HyZipEntry * entry,
+ const char *filename, BOOLEAN findDirectory));
+I_32 zip_getZipEntryExtraField
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile, HyZipEntry * entry,
+ U_8 * buffer, U_32 bufferSize));
+void zip_initZipEntry
+PROTOTYPE ((HyPortLibrary * portLib, HyZipEntry * entry));
+I_32 zip_openZipFile
+PROTOTYPE ((HyPortLibrary * portLib, char *filename, HyZipFile * zipFile,
+ HyZipCachePool * cachePool));
+void zip_freeZipEntry
+PROTOTYPE ((HyPortLibrary * portLib, HyZipEntry * entry));
+I_32 VMCALL zip_closeZipFile
+PROTOTYPE ((HyPortLibrary * portLib, struct HyZipFile * zipFile));
+I_32 zip_getZipEntryComment
+PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile, HyZipEntry * entry,
+ U_8 * buffer, U_32 bufferSize));
+
+#undef CDEV_CURRENT_FUNCTION
+
+//#include "hythread.h"
+//#define ENTER() hythread_monitor_enter(hythread_global_monitor())
+//#define EXIT() hythread_monitor_exit(hythread_global_monitor())
+
+#include "hymutex.h"
+MUTEX zip_globalMutex;
+static int initialized = 0;
+
+#define ENTER() \
+ if (!initialized) { MUTEX_INIT(zip_globalMutex); initialized = 1; } \
+ MUTEX_ENTER(zip_globalMutex);
+
+#define EXIT() MUTEX_EXIT(zip_globalMutex);
+
+
+HyZipCachePool *
+zipsup_GetZipCachePool(JNIEnv * env)
+{
+ static HyZipCachePool *pool = 0;
+
+ if (pool == 0) {
+ pool = zipCachePool_new(env);
+ }
+ return pool;
+}
+
+
+#ifndef checkZipLibrary
+#define CDEV_CURRENT_FUNCTION checkZipLibrary
+
+/*
+ Ensure that the zip library is loaded.
+ Return 0 on success, -1 on failure.
+*/
+I_32
+checkZipLibrary (HyPortLibrary * portLib)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+
+ /* if the library has already been loaded return success/failure */
+ if (zipDLLDescriptor > 1)
+ return 0;
+ if (zipDLLDescriptor == 1)
+ return -1;
+
+ /* open up the zip library by name */
+
+ if (hysl_open_shared_library (HY_ZIP_DLL_NAME, &zipDLLDescriptor, TRUE))
+ goto openFailed;
+
+ /* look up the functions */
+ if (hysl_lookup_name
+ (zipDLLDescriptor, "inflateInit2_", (void *) &inflateInit2Func,
+ "ILILI"))
+ goto loadFailed;
+ if (hysl_lookup_name
+ (zipDLLDescriptor, "inflate", (void *) &inflateFunc, "IPI"))
+ goto loadFailed;
+ if (hysl_lookup_name
+ (zipDLLDescriptor, "inflateEnd", (void *) &inflateEndFunc, "IP"))
+ goto loadFailed;
+
+ /* good to go */
+ return 0;
+
+loadFailed:
+ hysl_close_shared_library (zipDLLDescriptor);
+
+ /* mark the descriptor as a failed load. only report the error once */
+ zipDLLDescriptor = 1;
+
+ /* Unable to open %s (Missing export) */
+ hynls_printf (PORTLIB, HYNLS_WARNING, HYNLS_ZIP_MISSING_EXPORT,
+ HY_ZIP_DLL_NAME);
+
+ return -1;
+
+openFailed:
+ /* mark the descriptor as a failed load. only report the error once */
+ zipDLLDescriptor = 1;
+
+ /* Unable to open %s (%s) */
+ hynls_printf (PORTLIB, HYNLS_WARNING, HYNLS_ZIP_UNABLE_TO_OPEN_ZIP_DLL,
+ HY_ZIP_DLL_NAME, hyerror_last_error_message ());
+ return -1;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+#endif
+
+#define CDEV_CURRENT_FUNCTION inflateData
+
+/*
+ Returns 0 on success or one of the following:
+ ZIP_ERR_UNSUPPORTED_FILE_TYPE
+ ZIP_ERR_FILE_CORRUPT
+ ZIP_ERR_OUT_OF_MEMORY
+ ZIP_ERR_INTERNAL_ERROR
+*/
+static I_32
+inflateData (struct workBuffer *workBuf, U_8 * inputBuffer,
+ U_32 inputBufferSize, U_8 * outputBuffer, U_32 outputBufferSize)
+{
+ PORT_ACCESS_FROM_PORT (workBuf->portLib);
+
+ z_stream stream;
+ I_32 err;
+
+ stream.next_in = inputBuffer;
+ stream.avail_in = inputBufferSize;
+ stream.next_out = outputBuffer;
+ stream.avail_out = outputBufferSize;
+
+ stream.opaque = workBuf;
+ stream.zalloc = zdataalloc;
+ stream.zfree = zdatafree;
+
+ /* Initialize stream. Pass "-15" as max number of window bits, negated
+ to indicate that no zlib header is present in the data. */
+ err = inflateInit2Func (&stream, -15, ZLIB_VERSION, sizeof (z_stream));
+ if (err != Z_OK)
+ return -1;
+
+ /* Inflate the data. */
+ err = inflateFunc (&stream, Z_SYNC_FLUSH);
+
+ /* Clean up the stream. */
+ inflateEndFunc (&stream);
+
+ /* Check the return code. Did we complete the inflate? */
+ if ((err == Z_STREAM_END) || (err == Z_OK))
+ {
+ if (stream.total_out == outputBufferSize)
+ {
+ return 0;
+ }
+ }
+
+ switch (err)
+ {
+ case Z_OK: /* an error if file is incomplete */
+ case Z_STREAM_END: /* an error if file is incomplete */
+ case Z_ERRNO: /* a random error */
+ case Z_STREAM_ERROR: /* stream inconsistent */
+ case Z_DATA_ERROR: /* corrupted zip */
+ return ZIP_ERR_FILE_CORRUPT;
+
+ case Z_VERSION_ERROR: /* wrong zlib version */
+ case Z_NEED_DICT: /* needs a preset dictionary that we can't provide */
+ return ZIP_ERR_UNSUPPORTED_FILE_TYPE;
+
+ case Z_MEM_ERROR: /* out of memory */
+ return ZIP_ERR_OUT_OF_MEMORY;
+
+ case Z_BUF_ERROR: /* no progress / out of output buffer */
+ default: /* jic */
+ return ZIP_ERR_INTERNAL_ERROR;
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION scanForCentralEnd
+/*
+ Scan backward from end of file for a central end header. Read from zipFile and update the HyZipCentralEnd provided.
+
+ Returns 0 on success or one of the following:
+ ZIP_ERR_FILE_READ_ERROR
+ ZIP_ERR_FILE_CORRUPT
+*/
+I_32
+scanForCentralEnd (HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipCentralEnd * endEntry)
+{
+ U_8 *current;
+ U_8 buffer[SCAN_CHUNK_SIZE];
+ I_32 i, size, state;
+ U_32 dataSize = 0;
+ I_64 seekResult;
+ I_32 fileSize;
+ I_32 bytesAlreadyRead = 0;
+
+ PORT_ACCESS_FROM_PORT (portLib);
+
+ /* Haven't seen anything yet. */
+ state = 0;
+
+ seekResult = hyfile_seek (zipFile->fd, 0, HySeekEnd);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ fileSize = (I_32) seekResult;
+ zipFile->pointer = fileSize;
+
+ while (TRUE)
+ {
+ /* Fill the buffer. */
+ if (bytesAlreadyRead == fileSize)
+ {
+ zipFile->pointer = -1;
+ return ZIP_ERR_FILE_CORRUPT;
+ }
+
+ size = SCAN_CHUNK_SIZE;
+ if (size > fileSize - bytesAlreadyRead)
+ size = fileSize - bytesAlreadyRead;
+ bytesAlreadyRead += size;
+ seekResult =
+ hyfile_seek (zipFile->fd, fileSize - bytesAlreadyRead, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer = (I_32) seekResult;
+
+ if (hyfile_read (zipFile->fd, buffer, size) != size)
+ {
+ zipFile->pointer = -1;
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer += size;
+
+ /* Scan the buffer (backwards) for CentralEnd signature = PK^E^F. */
+ for (i = size; i--; dataSize++)
+ {
+ switch (state)
+ {
+ case 0:
+ /* Nothing yet. */
+ if (buffer[i] == 6)
+ state = 1;
+ break;
+
+ case 1:
+ /* Seen ^F */
+ if (buffer[i] == 5)
+ state = 2;
+ else
+ state = 0;
+ break;
+
+ case 2:
+ /* Seen ^E^F */
+ if (buffer[i] == 'K')
+ state = 3;
+ else
+ state = 0;
+ break;
+
+ case 3:
+ /* Seen K^E^F */
+ if (buffer[i] == 'P' && dataSize >= 21)
+ {
+ /* Found it. Read the data from the end-of-central-dir record. */
+ current = buffer + i + 4;
+ ZIP_NEXT_U16 (endEntry->diskNumber, current);
+ ZIP_NEXT_U16 (endEntry->dirStartDisk, current);
+ ZIP_NEXT_U16 (endEntry->thisDiskEntries, current);
+ ZIP_NEXT_U16 (endEntry->totalEntries, current);
+ ZIP_NEXT_U32 (endEntry->dirSize, current);
+ ZIP_NEXT_U32 (endEntry->dirOffset, current);
+ ZIP_NEXT_U16 (endEntry->commentLength, current);
+
+ /* Quick test to ensure that the header isn't invalid.
+ Current dataSize is the number of bytes of data scanned, up to the ^H in the stream. */
+ if (dataSize >= (U_32) (21 + endEntry->commentLength))
+ return 0;
+
+ /* Header looked invalid. Pretend we didn't see it and keep scanning.. */
+ }
+ state = 0;
+ break;
+ }
+ }
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION scanForDataDescriptor
+/*
+ Scan ahead for a data descriptor. Read from zipFile and update the HyZipLocalHeader provided.
+
+ Returns 0 on success or one of the following:
+ ZIP_ERR_FILE_READ_ERROR
+ ZIP_ERR_FILE_CORRUPT
+*/
+I_32
+scanForDataDescriptor (HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * zipEntry)
+{
+ U_8 *current;
+ U_8 buffer[SCAN_CHUNK_SIZE], descriptor[16];
+ I_32 i, size, state;
+ U_32 dataSize, blockPointer;
+ I_64 seekResult;
+
+ PORT_ACCESS_FROM_PORT (portLib);
+
+ /* Skip ahead and read the data descriptor. The compressed size should be 0. */
+ if (zipFile->pointer !=
+ (IDATA) (zipEntry->dataPointer + zipEntry->compressedSize))
+ {
+ seekResult =
+ hyfile_seek (zipFile->fd,
+ zipEntry->dataPointer + zipEntry->compressedSize,
+ HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer = (I_32) seekResult;
+ }
+
+ /* Haven't seen anything yet. */
+ blockPointer = dataSize = zipEntry->compressedSize;
+ state = 0;
+
+ /* Scan until we find PK^G^H (otherwise it's an error). */
+ while (1)
+ {
+ /* Fill the buffer. */
+ size = hyfile_read (zipFile->fd, buffer, SCAN_CHUNK_SIZE);
+ if (size == 0)
+ {
+ return ZIP_ERR_FILE_CORRUPT;
+ }
+ else if (size < 0)
+ {
+ zipFile->pointer = -1;
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer += size;
+ blockPointer += size;
+
+ /* Scan the buffer. */
+ for (i = 0; i < size; i++, dataSize++)
+ {
+ switch (state)
+ {
+ case 0:
+ /* Nothing yet. */
+ if (buffer[i] == 'P')
+ {
+ state = 1;
+ }
+ break;
+
+ case 1:
+ /* Seen P */
+ if (buffer[i] == 'K')
+ {
+ state = 2;
+ }
+ else
+ state = 0;
+ break;
+
+ case 2:
+ /* Seen PK */
+ if (buffer[i] == 7)
+ {
+ state = 3;
+ }
+ else
+ {
+ state = 0;
+ }
+ break;
+
+ case 3:
+ /* Seen PK^G */
+ if (buffer[i] == 8)
+ {
+ /* Found it! Read the descriptor */
+ if (i + 12 < size)
+ {
+ current = &buffer[i + 1];
+ }
+ else
+ {
+ seekResult =
+ hyfile_seek (zipFile->fd,
+ zipEntry->dataPointer + dataSize + 1,
+ HySeekSet);
+ if ((seekResult < 0)
+ || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer = (I_32) seekResult;
+ if (hyfile_read (zipFile->fd, descriptor, 12) != 12)
+ {
+ zipFile->pointer = -1;
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer += 12;
+ current = descriptor;
+ }
+
+ /* Read the data from the descriptor. */
+ ZIP_NEXT_U32 (zipEntry->crc32, current);
+ ZIP_NEXT_U32 (zipEntry->compressedSize, current);
+ ZIP_NEXT_U32 (zipEntry->uncompressedSize, current);
+
+ /* Quick test to ensure that the header isn't invalid.
+ Current dataSize is the number of bytes of data scanned, up to the ^H in the stream. */
+ if (dataSize - 3 == zipEntry->compressedSize)
+ {
+ return 0;
+ }
+
+ /* Header looked invalid. Reset the pointer and continue scanning. */
+ seekResult =
+ hyfile_seek (zipFile->fd,
+ zipEntry->dataPointer + blockPointer,
+ HySeekSet);
+ if ((seekResult < 0)
+ || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer = (I_32) seekResult;
+ }
+ else
+ state = 0;
+ break;
+ }
+ }
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_populateCache
+/*
+ Fill in the cache of a given zip file. This should only be called once during zip_openZipFile!
+
+ Returns 0 on success or one of the following:
+ ZIP_ERR_FILE_READ_ERROR
+ ZIP_ERR_FILE_OPEN_ERROR
+ ZIP_ERR_UNKNOWN_FILE_TYPE
+ ZIP_ERR_UNSUPPORTED_FILE_TYPE
+ ZIP_ERR_OUT_OF_MEMORY
+ ZIP_ERR_INTERNAL_ERROR
+*/
+I_32
+zip_populateCache (HyPortLibrary * portLib, HyZipFile * zipFile)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+
+ I_32 result = 0;
+ IDATA bufferSize = 65536;
+ IDATA unreadSize = 0;
+ IDATA bufferedSize = 0;
+ IDATA bytesToRead = 0;
+ IDATA filenameCopied;
+ HyZipEntry entry;
+ HyZipCentralEnd endEntry;
+ U_8 *buffer = NULL;
+ U_8 *filename = NULL;
+ IDATA filenameSize = 256; /* Should be sufficient for most filenames */
+ U_8 *current;
+ U_32 sig;
+ U_32 localHeaderOffset;
+ IDATA startCentralDir;
+ I_64 seekResult;
+
+ if (!zipFile->cache)
+ return ZIP_ERR_INTERNAL_ERROR;
+
+ /* Find and read the end-of-central-dir record. */
+ result = scanForCentralEnd (portLib, zipFile, &endEntry);
+ if (result != 0)
+ return result;
+
+ unreadSize = endEntry.dirSize + 4 /* slop */ ;
+ zipFile->cache->startCentralDir = startCentralDir =
+ (IDATA) ((UDATA) endEntry.dirOffset);
+
+ if (zipFile->pointer != startCentralDir)
+ {
+ seekResult = hyfile_seek (zipFile->fd, startCentralDir, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+
+ zipFile->pointer = (I_32) seekResult;
+ if (zipFile->pointer != startCentralDir)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ zipFile->pointer = -1;
+ goto finished;
+ }
+ }
+
+ /* No point in allocating more than we'll actually need.. */
+ if (bufferSize > unreadSize)
+ bufferSize = unreadSize;
+
+ filename = hymem_allocate_memory (filenameSize);
+ if (!filename)
+ {
+ result = ZIP_ERR_OUT_OF_MEMORY;
+ goto finished;
+ }
+
+ /* Allocate some space to hold central directory goo as we eat through it */
+ buffer = hymem_allocate_memory (bufferSize);
+ if (!buffer && (bufferSize > 4096))
+ {
+ /* Not enough memory, fall back to a smaller buffer! */
+ bufferSize = 4096;
+ buffer = hymem_allocate_memory (bufferSize);
+ }
+ if (!buffer)
+ {
+ result = ZIP_ERR_OUT_OF_MEMORY;
+ goto finished;
+ }
+
+ while (unreadSize)
+ {
+
+ /* Read as much as needed into buffer. */
+ bytesToRead = bufferSize - bufferedSize;
+ if (bytesToRead > unreadSize)
+ bytesToRead = unreadSize;
+ result = hyfile_read (zipFile->fd, buffer + bufferedSize, bytesToRead);
+ if (result < 0)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ zipFile->pointer = -1;
+ goto finished;
+ }
+ zipFile->pointer += result;
+ unreadSize -= result;
+ bufferedSize += result;
+ current = buffer;
+
+ /* consume entries until we run out. */
+ while (current + 46 < buffer + bufferedSize)
+ {
+ IDATA entryPointer;
+
+ entryPointer =
+ zipFile->pointer + (current - (buffer + bufferedSize));
+
+ sig = 0;
+ ZIP_NEXT_U32 (sig, current);
+ if (sig == ZIP_CentralEnd)
+ {
+ /* We're done here. */
+ result = 0;
+ goto finished;
+ }
+ if (sig != ZIP_CentralHeader)
+ {
+ /* Umm...What the Hell? */
+ result = ZIP_ERR_FILE_CORRUPT;
+ goto finished;
+ }
+
+ /* Read ZIP_CentralHeader entry */
+ ZIP_NEXT_U16 (entry.versionCreated, current);
+ ZIP_NEXT_U16 (entry.versionNeeded, current);
+ ZIP_NEXT_U16 (entry.flags, current);
+ ZIP_NEXT_U16 (entry.compressionMethod, current);
+ ZIP_NEXT_U16 (entry.lastModTime, current);
+ ZIP_NEXT_U16 (entry.lastModDate, current);
+ ZIP_NEXT_U32 (entry.crc32, current);
+ ZIP_NEXT_U32 (entry.compressedSize, current);
+ ZIP_NEXT_U32 (entry.uncompressedSize, current);
+ ZIP_NEXT_U16 (entry.filenameLength, current);
+ ZIP_NEXT_U16 (entry.extraFieldLength, current);
+ ZIP_NEXT_U16 (entry.fileCommentLength, current);
+ current += sizeof (U_16); /* skip disk number field */
+ ZIP_NEXT_U16 (entry.internalAttributes, current);
+ current += sizeof (U_32); /* skip external attributes field */
+ ZIP_NEXT_U32 (localHeaderOffset, current);
+
+ /* Increase filename buffer size if necessary. */
+ if (filenameSize < entry.filenameLength + 1)
+ {
+ hymem_free_memory (filename);
+ filenameSize = entry.filenameLength + 1;
+ filename = hymem_allocate_memory (filenameSize);
+ if (!filename)
+ {
+ result = ZIP_ERR_OUT_OF_MEMORY;
+ goto finished;
+ }
+ }
+
+ filenameCopied = 0;
+ while (filenameCopied < entry.filenameLength)
+ {
+ IDATA size;
+ /* Copy as much of the filename as we can see in the buffer (probably the whole thing). */
+
+ size = entry.filenameLength - filenameCopied;
+ if (size > bufferedSize - (current - buffer))
+ {
+ size = bufferedSize - (current - buffer);
+ }
+ memcpy (filename + filenameCopied, current, size);
+ filenameCopied += size;
+ current += size;
+ if (filenameCopied >= entry.filenameLength)
+ break; /* done */
+
+ /* Otherwise, we ran out of source string. Load another chunk.. */
+ bufferedSize = 0;
+ if (!unreadSize)
+ {
+ /* Central header is supposedly done? Bak */
+ result = ZIP_ERR_FILE_CORRUPT;
+ goto finished;
+ }
+ bytesToRead = bufferSize - bufferedSize;
+ if (bytesToRead > unreadSize)
+ bytesToRead = unreadSize;
+ result =
+ hyfile_read (zipFile->fd, buffer + bufferedSize, bytesToRead);
+ if (result < 0)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ zipFile->pointer = -1;
+ goto finished;
+ }
+ zipFile->pointer += result;
+ unreadSize -= result;
+ bufferedSize += result;
+ current = buffer;
+ }
+ filename[entry.filenameLength] = '\0'; /* null-terminate */
+
+ if (((entry.compressionMethod == ZIP_CM_Deflated)
+ && (entry.flags & 0x8)) || (entry.fileCommentLength != 0))
+ {
+ /* Either local header doesn't know the compressedSize, or this entry has a file
+ comment. In either case, cache the central header instead of the local header
+ so we can find the information we need later. */
+
+ result =
+ zipCache_addElement (zipFile->cache, (char *) filename,
+ entryPointer);
+
+ }
+ else
+ {
+ result =
+ zipCache_addElement (zipFile->cache, (char *) filename,
+ localHeaderOffset);
+ }
+
+ if (!result)
+ {
+ result = ZIP_ERR_OUT_OF_MEMORY;
+ goto finished;
+ }
+
+ /* Skip the data and comment. */
+ bytesToRead = entry.extraFieldLength + entry.fileCommentLength;
+ if (bufferedSize - (current - buffer) >= bytesToRead)
+ {
+ current += bytesToRead;
+ }
+ else
+ {
+ /* The rest of the buffer is uninteresting. Skip ahead to where the good stuff is */
+ bytesToRead -= (bufferedSize - (current - buffer));
+ current = buffer + bufferedSize;
+ unreadSize -= bytesToRead;
+
+ seekResult = hyfile_seek (zipFile->fd, bytesToRead, HySeekCur);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer = (I_32) seekResult;
+ }
+ }
+ bufferedSize -= (current - buffer);
+ memmove (buffer, current, bufferedSize);
+ }
+
+ result = 0;
+
+finished:
+ if (filename)
+ hymem_free_memory (filename);
+ if (buffer)
+ hymem_free_memory (buffer);
+ return result;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION readZipEntry
+/*
+ Read the next zip entry for the zipFile into the zipEntry provided. If filename is non-NULL, it is expected to match
+ the filename read for the entry. If (cachePointer != -1) the filename of the entry will be looked up in the cache (assuming
+ there is one) to help detect use of an invalid cache. If enumerationPointer is non-NULL, sequential access is assumed and
+ either a local zip entry or a data descriptor will be accepted, but a central zip entry will cause ZIP_ERR_NO_MORE_ENTRIES
+ to be returned. If enumerationPointer is NULL, random access is assumed and either a local zip entry or a central zip
+ entry will be accepted.
+
+ Returns 0 on success or one of the following:
+ ZIP_ERR_FILE_READ_ERROR
+ ZIP_ERR_FILE_CORRUPT
+ ZIP_ERR_OUT_OF_MEMORY
+ ZIP_ERR_NO_MORE_ENTRIES
+*/
+static I_32
+readZipEntry (HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * zipEntry, const char *filename,
+ IDATA * enumerationPointer, IDATA * entryStart,
+ BOOLEAN findDirectory)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+
+ I_32 result;
+ U_8 buffer[46 + 128];
+ U_8 *current;
+ U_32 sig;
+ IDATA readLength;
+ I_64 seekResult;
+ U_8 *readBuffer;
+ IDATA currentEntryPointer, localEntryPointer;
+ IDATA headerSize;
+ IDATA filenameLength = filename ? strlen (filename) : 0;
+
+retry:
+ if (entryStart)
+ *entryStart = zipFile->pointer;
+ readBuffer = NULL;
+ /* Guess how many bytes we'll need to read. If we guess correctly we will do fewer I/O operations */
+ headerSize = 30; /* local zip header size */
+ if (zipFile->cache && (zipFile->pointer >= zipFile->cache->startCentralDir))
+ {
+ headerSize = 46; /* central zip header size */
+ }
+ readLength = headerSize + (filename ? filenameLength : 128);
+ if (findDirectory)
+ {
+ /* Extra byte for possible trailing '/' */
+ readLength++;
+ }
+
+ /* Allocate some memory if necessary */
+ if (readLength <= sizeof (buffer))
+ {
+ current = buffer;
+ }
+ else
+ {
+ current = readBuffer = hymem_allocate_memory (readLength);
+ if (!readBuffer)
+ return ZIP_ERR_OUT_OF_MEMORY;
+ }
+
+ currentEntryPointer = localEntryPointer = zipFile->pointer;
+
+ result = hyfile_read (zipFile->fd, current, readLength);
+ if ((result < 22)
+ || (filename
+ && !(result == readLength
+ || (findDirectory && result == (readLength - 1)))))
+ {
+ /* We clearly didn't get enough bytes */
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer += result;
+ readLength = result; /* If it's not enough, we'll catch that later */
+ ZIP_NEXT_U32 (sig, current);
+
+ if (enumerationPointer)
+ {
+ if ((sig == ZIP_CentralEnd))
+ {
+ result = ZIP_ERR_NO_MORE_ENTRIES;
+ goto finished;
+ }
+ }
+ if ((enumerationPointer || (!zipFile->cache))
+ && (sig == ZIP_DataDescriptor))
+ {
+ /* We failed to predict a data descriptor here. This should be an error (i.e. only happens in malformed zips?)
+ but, but we will silently skip over it */
+ seekResult =
+ hyfile_seek (zipFile->fd, currentEntryPointer + 16, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer = (I_32) seekResult;
+
+ if (zipFile->pointer == currentEntryPointer + 16)
+ {
+ if (readBuffer)
+ {
+ hymem_free_memory (readBuffer);
+ }
+ goto retry;
+ }
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+
+ if ((sig != ZIP_CentralHeader) && (sig != ZIP_LocalHeader))
+ {
+ /* Unexpected. */
+ result = ZIP_ERR_FILE_CORRUPT;
+ goto finished;
+ }
+ headerSize = ((sig == ZIP_CentralHeader) ? 46 : 30);
+ if (readLength < headerSize)
+ {
+ /* We didn't get the whole header (and none of the filename).. */
+ /* NOTE: this could happen in normal use if the assumed filename length above is <16. Since it's 128, we don't
+ handle the impossible case where we would have to read more header. It could also happen if the caller
+ supplied a filename of length <16 but that only happens when we have a cache (so we'll know the header size)
+ */
+ result = ZIP_ERR_FILE_READ_ERROR;
+ }
+ readLength -= headerSize;
+
+ if (sig == ZIP_CentralHeader)
+ {
+ current += 2; /* skip versionCreated field */
+ }
+ ZIP_NEXT_U16 (zipEntry->versionNeeded, current);
+ ZIP_NEXT_U16 (zipEntry->flags, current);
+ ZIP_NEXT_U16 (zipEntry->compressionMethod, current);
+ ZIP_NEXT_U16 (zipEntry->lastModTime, current);
+ ZIP_NEXT_U16 (zipEntry->lastModDate, current);
+ ZIP_NEXT_U32 (zipEntry->crc32, current);
+ ZIP_NEXT_U32 (zipEntry->compressedSize, current);
+ ZIP_NEXT_U32 (zipEntry->uncompressedSize, current);
+ ZIP_NEXT_U16 (zipEntry->filenameLength, current);
+ ZIP_NEXT_U16 (zipEntry->extraFieldLength, current);
+ zipEntry->fileCommentLength = 0;
+
+ if (sig == ZIP_CentralHeader)
+ {
+ ZIP_NEXT_U16 (zipEntry->fileCommentLength, current);
+ current += 8; /* skip disk number start + internal attrs + external attrs */
+ ZIP_NEXT_U32 (localEntryPointer, current);
+ }
+
+ if (filename)
+ {
+ if (zipFile->cache)
+ {
+ if (!
+ (readLength == zipEntry->filenameLength
+ || (findDirectory
+ && (readLength - 1) == zipEntry->filenameLength)))
+ {
+ /* We knew exactly how much we were supposed to read, and this wasn't it */
+ result = ZIP_ERR_FILE_CORRUPT;
+ goto finished;
+ }
+ }
+ }
+
+ /* Allocate space for filename */
+ if (zipEntry->filenameLength >= ZIP_INTERNAL_MAX)
+ {
+ zipEntry->filename =
+ hymem_allocate_memory (zipEntry->filenameLength + 1);
+ if (!zipEntry->filename)
+ {
+ result = ZIP_ERR_OUT_OF_MEMORY;
+ goto finished;
+ }
+ }
+ else
+ {
+ zipEntry->filename = zipEntry->internalFilename;
+ }
+ if (readLength > zipEntry->filenameLength)
+ {
+ readLength = zipEntry->filenameLength;
+ }
+ memcpy (zipEntry->filename, current, readLength);
+
+ /* Read the rest of the filename if necessary. Allocate space in HyZipEntry for it! */
+ if (readLength < zipEntry->filenameLength)
+ {
+ result =
+ hyfile_read (zipFile->fd, zipEntry->filename + readLength,
+ zipEntry->filenameLength - readLength);
+ if (result != (zipEntry->filenameLength - readLength))
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer += result;
+ }
+ zipEntry->filename[zipEntry->filenameLength] = '\0';
+
+ /* If we know what filename is supposed to be, compare it and make sure it matches */
+ /* Note: CASE-SENSITIVE COMPARE because filenames in zips are case sensitive (even on platforms with
+ case-insensitive file systems) */
+ if (filename)
+ {
+ if (!
+ ((findDirectory && zipEntry->filenameLength == (filenameLength + 1)
+ && zipEntry->filename[filenameLength] == '/'
+ && !strncmp ((char *) zipEntry->filename, (const char *) filename,
+ filenameLength))
+ || !strcmp ((const char *) zipEntry->filename,
+ (const char *) filename)))
+ {
+ /* We seem to have read something totally invalid.. */
+ result = ZIP_ERR_FILE_CORRUPT;
+ goto finished;
+ }
+ }
+
+ zipEntry->filenamePointer = currentEntryPointer + headerSize;
+ zipEntry->extraFieldPointer =
+ localEntryPointer + 30 + zipEntry->filenameLength;
+ zipEntry->dataPointer =
+ zipEntry->extraFieldPointer + zipEntry->extraFieldLength;
+ zipEntry->extraField = NULL;
+ zipEntry->fileCommentPointer = 0;
+ zipEntry->fileComment = NULL;
+ zipEntry->data = NULL;
+
+ if (sig == ZIP_CentralHeader)
+ {
+ U_8 buf[2];
+ U_8 *buf2 = buf;
+ U_16 lost;
+ /* Also, we know where the comment is */
+ zipEntry->fileCommentPointer = currentEntryPointer + headerSize +
+ zipEntry->filenameLength + zipEntry->extraFieldLength;
+ if (hyfile_seek (zipFile->fd, localEntryPointer + 28, HySeekSet) ==
+ localEntryPointer + 28)
+ {
+ if (hyfile_read (zipFile->fd, buf, 2) == 2)
+ {
+ ZIP_NEXT_U16 (lost, buf2);
+ zipEntry->dataPointer = zipEntry->extraFieldPointer + lost;
+ zipFile->pointer = localEntryPointer + 30;
+ }
+ }
+ }
+
+ if ((sig == ZIP_LocalHeader)
+ && (zipEntry->compressionMethod == ZIP_CM_Deflated)
+ && (zipEntry->flags & 0x8))
+ {
+ /* What we just read doesn't tell us how big the compressed data is. We have to do a heuristic search for a
+ valid data descriptor at the end of the compressed text */
+ result = scanForDataDescriptor (portLib, zipFile, zipEntry);
+ if (result < 0)
+ goto finished;
+ }
+
+ /* Entry read successfully */
+
+ if (enumerationPointer)
+ {
+ /* Work out where the next entry is supposed to be */
+ *enumerationPointer =
+ zipEntry->fileCommentPointer + zipEntry->fileCommentLength;
+ }
+
+ if (readBuffer)
+ hymem_free_memory (readBuffer);
+ return 0;
+
+finished:
+ if (readBuffer)
+ {
+ hymem_free_memory (readBuffer);
+ }
+ if ((zipEntry->filename)
+ && (zipEntry->filename != zipEntry->internalFilename))
+ {
+ hymem_free_memory (zipEntry->filename);
+ }
+ zipEntry->filename = NULL;
+ if (result == ZIP_ERR_FILE_READ_ERROR)
+ {
+ zipFile->pointer = -1;
+ }
+ return result;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_closeZipFile
+/**
+ * Attempt to close the zipfile.
+ *
+ * @param[in] portLib the port library
+ * @param[in] zipFile The zip file to be closed
+ *
+ * @return 0 on success
+ * @return ZIP_ERR_FILE_CLOSE_ERROR if there is an error closing the file
+ * @return ZIP_ERR_INTERNAL_ERROR if there is an internal error
+ *
+*/
+I_32 VMCALL
+zip_closeZipFile (HyPortLibrary * portLib, struct HyZipFile * zipFile)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+#if defined(HY_NO_THR)
+ THREAD_ACCESS_FROM_PORT(portLib);
+#endif /* HY_NO_THR */
+ IDATA fd;
+
+ ENTER ();
+
+ fd = zipFile->fd;
+ zipFile->fd = -1;
+
+ if (zipFile->cache && zipFile->cachePool)
+ {
+ zipCachePool_release (zipFile->cachePool, zipFile->cache);
+ zipFile->cache = NULL;
+ }
+ if ((zipFile->filename) && (zipFile->filename != zipFile->internalFilename))
+ {
+ hymem_free_memory (zipFile->filename);
+ }
+ zipFile->filename = NULL;
+
+ if (fd == -1)
+ {
+ EXIT ();
+ return ZIP_ERR_INTERNAL_ERROR;
+ }
+ if (hyfile_close (fd))
+ {
+ EXIT ();
+ return ZIP_ERR_FILE_CLOSE_ERROR;
+ }
+ EXIT ();
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_establishCache
+/**
+ * Called to set up a cache when a zip file is opened with a cachePool but without a cache, or when the
+ * current cache is found to be invalid in some way.
+ *
+ * @param[in] portLib the port library
+ * @param[in] zipFile the zip file for which we want to establish a cache
+ *
+ * The current cache is marked as invalid such that new instances of zip files
+ * won't try to use it and an attempt is made to establish a new cache.
+ *
+ * @return 0 on success
+ * @return ZIP_ERR_FILE_READ_ERROR if there is an error reading from zipFile
+ * @return ZIP_ERR_FILE_OPEN_ERROR if is there is an error opening the file
+ * @return ZIP_ERR_UNKNOWN_FILE_TYPE if the file type is unknown
+ * @return ZIP_ERR_UNSUPPORTED_FILE_TYPE if the file type is unsupported
+ * @return ZIP_ERR_OUT_OF_MEMORY if there is not enough memory to complete this call
+ * @return ZIP_ERR_INTERNAL_ERROR if there was an internal error
+*/
+
+I_32
+zip_establishCache (HyPortLibrary * portLib, HyZipFile * zipFile)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+ I_32 result;
+ I_64 timeStamp, actualFileSize;
+ IDATA fileSize, filenameLength;
+
+ if (zipFile->cache)
+ {
+ if (zipFile->cachePool)
+ {
+ /* Whack cache timestamp to keep other people from starting to use it (we will create a new one for them
+ to start to use instead). Once all the current users of the cache have stopped using it, it will go away */
+ zipFile->cache->zipTimeStamp = -2;
+ zipCachePool_release (zipFile->cachePool, zipFile->cache);
+ }
+ zipFile->cache = NULL;
+ }
+ if (!zipFile->cachePool)
+ {
+ return ZIP_ERR_INTERNAL_ERROR;
+ }
+
+ /* Check the cachePool for a suitable cache. */
+ filenameLength = strlen ((const char *) zipFile->filename);
+
+// timeStamp = hyfile_lastmod ((const char *) zipFile->filename);
+// actualFileSize = hyfile_length ((const char *) zipFile->filename);
+ {
+ struct stat st;
+ tzset ();
+ stat ((mcSignednessBull)zipFile->filename, &st);
+ timeStamp = (U_64)st.st_mtime * 1000;
+ actualFileSize = (I_64) st.st_size;
+ }
+
+ if ((actualFileSize < 0) || (actualFileSize > HYCONST64 (0x7FFFFFFF)))
+ {
+ return ZIP_ERR_INTERNAL_ERROR;
+ }
+ fileSize = (IDATA) actualFileSize;
+
+ zipFile->cache =
+ zipCachePool_findCache (zipFile->cachePool,
+ (const char *) zipFile->filename, filenameLength,
+ fileSize, timeStamp);
+ if (!zipFile->cache)
+ {
+ /* Build a new cache. Because caller asked for a cache, fail if we can't provide one */
+ zipFile->cache =
+ zipCache_new (portLib, (char *) zipFile->filename, filenameLength);
+ if (!zipFile->cache)
+ return ZIP_ERR_OUT_OF_MEMORY;
+
+ zipFile->cache->zipFileSize = fileSize;
+ zipFile->cache->zipTimeStamp = timeStamp;
+
+ result = zip_populateCache (portLib, zipFile);
+ if (result != 0)
+ {
+ zipCache_kill (zipFile->cache);
+ zipFile->cache = NULL;
+ return result;
+ }
+ if (!zipCachePool_addCache (zipFile->cachePool, zipFile->cache))
+ {
+ zipCache_kill (zipFile->cache);
+ zipFile->cache = NULL;
+ return ZIP_ERR_OUT_OF_MEMORY;
+ }
+ }
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_initZipEntry
+/**
+ * Initialize a zip entry.
+ *
+ * Should be called before the entry is passed to any other zip support functions
+ *
+ * @param[in] portLib the port library
+ * @param[in] entry the zip entry to init
+ *
+ * @return none
+*/
+
+void
+zip_initZipEntry (HyPortLibrary * portLib, HyZipEntry * entry)
+{
+ memset (entry, 0, sizeof (*entry));
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_freeZipEntry
+/**
+ * Free any memory associated with a zip entry.
+ *
+ * @param[in] portLib the port library
+ * @param[in] entry the zip entry we are freeing
+ *
+ * @return none
+ *
+ * @note This does not free the entry itself.
+*/
+
+void
+zip_freeZipEntry (HyPortLibrary * portLib, HyZipEntry * entry)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+
+ if ((entry->filename) && (entry->filename != entry->internalFilename))
+ {
+ hymem_free_memory (entry->filename);
+ }
+ entry->filename = NULL;
+ if (entry->extraField)
+ {
+ hymem_free_memory (entry->extraField);
+ entry->extraField = NULL;
+ }
+ if (entry->data)
+ {
+ hymem_free_memory (entry->data);
+ entry->data = NULL;
+ }
+ if (entry->fileComment)
+ {
+ hymem_free_memory (entry->fileComment);
+ entry->fileComment = NULL;
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_getNextZipEntry
+/**
+ * Read the next zip entry at nextEntryPointer into zipEntry.
+ *
+ * Any memory held onto by zipEntry may be lost, and therefore
+ * MUST be freed with @ref zip_freeZipEntry first.
+ *
+ * @param[in] portLib the port library
+ * @param[in] zipFile The zip file being read
+ * @param[out] zipEntry compressed data is placed here
+ * @param[in] nextEntryPointer
+ *
+ * @return 0 on success
+ * @return ZIP_ERR_FILE_READ_ERROR if there is an error reading zipFile
+ * @return ZIP_ERR_FILE_CORRUPT if zipFile is corrupt
+ * @return ZIP_ERR_NO_MORE_ENTRIES if there are no more entries in zipFile
+ * @return ZIP_ERR_OUT_OF_MEMORY if there is not enough memory to complete this call
+ *
+ * @see zip_freeZipEntry
+ *
+*/
+I_32
+zip_getNextZipEntry (HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * zipEntry, IDATA * nextEntryPointer)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+#if defined(HY_NO_THR)
+ THREAD_ACCESS_FROM_PORT(portLib);
+#endif /* HY_NO_THR */
+ IDATA result;
+ BOOLEAN retryAllowed = TRUE;
+ IDATA pointer;
+ IDATA entryStart;
+ I_64 seekResult;
+
+ ENTER ();
+
+retry:
+ pointer = *nextEntryPointer;
+
+ /* Seek to the entry's position in the file. */
+ if (pointer != zipFile->pointer)
+ {
+ seekResult = hyfile_seek (zipFile->fd, pointer, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ EXIT ();
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer = (I_32) seekResult;
+
+ if (pointer != zipFile->pointer)
+ {
+ zipFile->pointer = -1;
+ EXIT ();
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ }
+
+ /* Read the entry */
+ entryStart = *nextEntryPointer;
+ result =
+ readZipEntry (portLib, zipFile, zipEntry, NULL, &pointer, &entryStart,
+ FALSE);
+ if (result != 0)
+ {
+ if (!retryAllowed || (result == ZIP_ERR_NO_MORE_ENTRIES))
+ {
+ EXIT ();
+ return result;
+ }
+ zip_establishCache (portLib, zipFile);
+ retryAllowed = FALSE;
+ goto retry;
+ }
+
+ if (zipFile->cache)
+ {
+ /* Validity check: look up filename in the cache... */
+ result =
+ (IDATA) zipCache_findElement (zipFile->cache,
+ (const char *) zipEntry->filename,
+ FALSE);
+ if (result != entryStart)
+ {
+ if (result >= zipFile->cache->startCentralDir)
+ {
+ /* ! Cache contents are not valid. Invalidate it and make a new one */
+ if (!retryAllowed)
+ {
+ EXIT ();
+ return ZIP_ERR_FILE_CORRUPT; /* should never happen! */
+ }
+ result = zip_establishCache (portLib, zipFile);
+ if (result)
+ {
+ /* (silently start operating without a cache if we couldn't make a new one) */
+ }
+ else
+ {
+ retryAllowed = FALSE;
+ goto retry;
+ }
+ }
+ else
+ {
+ /* We know that the central header for this entry contains info that the
+ local header is missing (comment length and/or uncompressed size) */
+ zipEntry->fileCommentPointer = -1;
+ }
+ }
+ }
+
+ *nextEntryPointer = pointer;
+ EXIT ();
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_getZipEntry
+/**
+ * Attempt to find and read the zip entry corresponding to filename.
+ * If found, read the entry into the parameter entry.
+ *
+ * If an uncached entry is found, the filename field will be filled in. This
+ * memory will have to be freed with @ref zip_freeZipEntry.
+ *
+ * @param[in] portLib the port library
+ * @param[in] zipFile the file being read from
+ * @param[out] entry the zip entry found in zipFile is read to here
+ * @param[in] filename the name of the file that corresponds to entry
+ * @param[in] findDirectory when true, match a directory even if filename does not end in '/'.
+ * Note findDirectory is only supported (for the JCL) when there is a cache
+ *
+ * @return 0 on success or one of the following:
+ * @return ZIP_ERR_FILE_READ_ERROR if there is an error reading from zipFile
+ * @return ZIP_ERR_FILE_CORRUPT if zipFile is corrupt
+ * @return ZIP_ERR_ENTRY_NOT_FOUND if a zip entry with name filename was not found
+ * @return ZIP_ERR_OUT_OF_MEMORY if there is not enough memory to complete this call
+ *
+ * @see zip_freeZipEntry
+*/
+
+I_32
+zip_getZipEntry (HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, const char *filename,
+ BOOLEAN findDirectory)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+#if defined(HY_NO_THR)
+ THREAD_ACCESS_FROM_PORT(portLib);
+#endif /* HY_NO_THR */
+ IDATA result, position;
+ BOOLEAN retryAllowed = TRUE;
+ I_64 seekResult;
+
+ ENTER ();
+
+retry:
+ if (zipFile->cache)
+ {
+ /* Look up filename in the cache. */
+ position =
+ (IDATA) zipCache_findElement (zipFile->cache, filename,
+ findDirectory);
+ if (position == -1)
+ {
+ /* Note: we assume the cache is still valid here */
+ EXIT ();
+ return ZIP_ERR_ENTRY_NOT_FOUND;
+ }
+
+ /* Seek to the entry's position in the file. */
+ if (zipFile->pointer != position)
+ {
+ seekResult = hyfile_seek (zipFile->fd, position, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ EXIT ();
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer = (I_32) seekResult;
+
+ if (zipFile->pointer != position)
+ {
+ zipFile->pointer = -1;
+ EXIT ();
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ }
+
+ /* Read the entry */
+ result =
+ readZipEntry (portLib, zipFile, entry, filename, NULL, NULL,
+ findDirectory);
+ if (result != 0)
+ {
+ if (!retryAllowed)
+ {
+ EXIT ();
+ return result;
+ }
+ result = zip_establishCache (portLib, zipFile); /* invalidate existing cache */
+ if (result)
+ {
+ EXIT ();
+ return result;
+ }
+ retryAllowed = FALSE;
+ goto retry;
+ }
+ EXIT ();
+ return 0;
+ }
+ else
+ {
+ /* Uh oh -- random access without a cache (SLOW!) */
+ position = 0;
+ zip_resetZipFile (PORTLIB, zipFile, &position);
+ while (TRUE)
+ {
+
+ if (zipFile->pointer != position)
+ {
+ seekResult = hyfile_seek (zipFile->fd, position, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ EXIT ();
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer = (I_32) seekResult;
+
+ if (zipFile->pointer != position)
+ {
+ zipFile->pointer = -1;
+ EXIT ();
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ }
+
+ result =
+ readZipEntry (portLib, zipFile, entry, NULL, &position, NULL,
+ FALSE);
+ if (result || !strcmp ((const char *) entry->filename, filename))
+ {
+ EXIT ();
+ return result;
+ }
+
+ /* No match. Reset for next entry */
+ zip_freeZipEntry (portLib, entry);
+ zip_initZipEntry (portLib, entry);
+ }
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_getZipEntryData
+/**
+ * Attempt to read and uncompress the data for the zip entry entry.
+ *
+ * If buffer is non-NULL it is used, but not explicitly held onto by the entry.
+ * If buffer is NULL, memory is allocated and held onto by the entry, and thus
+ * should later be freed with @ref zip_freeZipEntry.
+ *
+ * @param[in] portLib the port library
+ * @param[in] zipFile the zip file being read from.
+ * @param[in,out] entry the zip entry
+ * @param[in] buffer may or may not be NULL
+ * @param[in] bufferSize
+
+ * @return 0 on success
+ * @return ZIP_ERR_FILE_READ_ERROR if there is an error reading from zipEntry
+ * @return ZIP_ERR_FILE_CORRUPT if zipFile is corrupt
+ * @return ZIP_ERR_ENTRY_NOT_FOUND if entry is not found
+ * @return ZIP_ERR_OUT_OF_MEMORY if there is not enough memory to complete this call
+ * @return ZIP_ERR_BUFFER_TOO_SMALL if buffer is too small to hold the comment for zipFile
+ *
+ * @see zip_freeZipEntry
+ *
+*/
+I_32
+zip_getZipEntryData (HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, U_8 * buffer, U_32 bufferSize)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+#if defined(HY_NO_THR)
+ THREAD_ACCESS_FROM_PORT(portLib);
+#endif /* HY_NO_THR */
+
+ I_32 result;
+ U_8 *dataBuffer;
+ struct workBuffer wb;
+ I_64 seekResult;
+
+ ENTER ();
+
+ wb.portLib = portLib;
+ wb.bufferStart = wb.bufferEnd = wb.currentAlloc = 0;
+
+ if (buffer)
+ {
+ if (bufferSize < entry->uncompressedSize)
+ {
+ EXIT ();
+ return ZIP_ERR_BUFFER_TOO_SMALL;
+ }
+ dataBuffer = buffer;
+ }
+ else
+ {
+ /* Note that this is the first zalloc. This memory must be available to the calling method and is freed explicitly in zip_freeZipEntry. */
+ /* Note that other allocs freed in zip_freeZipEntry are not alloc'd using zalloc */
+ dataBuffer = zdataalloc (&wb, 1, entry->uncompressedSize);
+ if (!dataBuffer)
+ {
+ EXIT ();
+ return ZIP_ERR_OUT_OF_MEMORY;
+ }
+ entry->data = dataBuffer;
+ }
+
+ if (entry->compressionMethod == ZIP_CM_Stored)
+ {
+ /* No compression - just read the data in. */
+ if (zipFile->pointer != entry->dataPointer)
+ {
+ seekResult =
+ hyfile_seek (zipFile->fd, entry->dataPointer, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer = (I_32) seekResult;
+
+ if (zipFile->pointer != entry->dataPointer)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ }
+ result = hyfile_read (zipFile->fd, dataBuffer, entry->compressedSize);
+ if (result != (I_32) entry->compressedSize)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer += result;
+ EXIT ();
+ return 0;
+ }
+
+ if (entry->compressionMethod == ZIP_CM_Deflated)
+ {
+ U_8 *readBuffer;
+
+ /* Ensure that the library is loaded. */
+ if (checkZipLibrary (portLib))
+ {
+ result = ZIP_ERR_UNSUPPORTED_FILE_TYPE;
+ goto finished;
+ }
+
+ /* Read the file contents. */
+ readBuffer = zdataalloc (&wb, 1, entry->compressedSize);
+ if (!readBuffer)
+ {
+ result = ZIP_ERR_OUT_OF_MEMORY;
+ goto finished;
+ }
+ if (zipFile->pointer != entry->dataPointer)
+ {
+ seekResult =
+ hyfile_seek (zipFile->fd, entry->dataPointer, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ zdatafree (&wb, readBuffer);
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer = (I_32) seekResult;
+
+ if (zipFile->pointer != entry->dataPointer)
+ {
+ zdatafree (&wb, readBuffer);
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ }
+ if (hyfile_read (zipFile->fd, readBuffer, entry->compressedSize) !=
+ (I_32) entry->compressedSize)
+ {
+ zdatafree (&wb, readBuffer);
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer += (I_32) entry->compressedSize;
+
+ /* Deflate the data. */
+ result =
+ inflateData (&wb, readBuffer, entry->compressedSize, dataBuffer,
+ entry->uncompressedSize);
+ zdatafree (&wb, readBuffer);
+ if (result)
+ goto finished;
+ EXIT ();
+ return 0;
+ }
+
+ /* Whatever this is, we can't decompress it */
+ result = ZIP_ERR_UNSUPPORTED_FILE_TYPE;
+
+finished:
+ if (!buffer)
+ {
+ entry->data = NULL;
+ zdatafree (&wb, dataBuffer);
+ }
+ if (result == ZIP_ERR_FILE_READ_ERROR)
+ {
+ zipFile->pointer = -1;
+ }
+ EXIT ();
+ return result;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_getZipEntryExtraField
+/**
+ * Read the extra field of entry from the zip file filename.
+ *
+ * buffer is used if non-NULL, but is not held onto by entry.
+ *
+ * If buffer is NULL, memory is allocated and held onto by entry, and MUST be freed later with
+ * @ref zip_freeZipEntry.
+ *
+ * @param[in] portLib the port library
+ * @param[in] zipFile the zip file being read from.
+ * @param[in,out] entry the zip entry concerned
+ * @param[in] buffer may or may not be NULL
+ * @param[in] bufferSize
+ *
+ * @return 0 on success or one of the following:
+ * @return ZIP_ERR_FILE_READ_ERROR if there is an error reading from zipFile
+ * @return ZIP_ERR_FILE_CORRUPT if zipFile is corrupt
+ * @return ZIP_ERR_OUT_OF_MEMORY if there is not enough memory to complete this call
+ * @return ZIP_ERR_BUFFER_TOO_SMALL if the buffer was non-Null but not large enough to hold the contents of entry
+ *
+ * @see zip_freeZipEntry
+*/
+I_32
+zip_getZipEntryExtraField (HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, U_8 * buffer, U_32 bufferSize)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+#if defined(HY_NO_THR)
+ THREAD_ACCESS_FROM_PORT(portLib);
+#endif /* HY_NO_THR */
+
+ I_32 result;
+ U_8 *extraFieldBuffer;
+ I_64 seekResult;
+
+ ENTER ();
+
+ if (entry->extraFieldLength == 0)
+ {
+ EXIT ();
+ return 0;
+ }
+
+ if (buffer)
+ {
+ if (bufferSize < entry->extraFieldLength)
+ {
+ EXIT ();
+ return ZIP_ERR_BUFFER_TOO_SMALL;
+ }
+ extraFieldBuffer = buffer;
+ }
+ else
+ {
+ extraFieldBuffer = hymem_allocate_memory (entry->extraFieldLength);
+ if (!extraFieldBuffer)
+ {
+ EXIT ();
+ return ZIP_ERR_OUT_OF_MEMORY;
+ }
+ entry->extraField = extraFieldBuffer;
+ }
+
+ if (zipFile->pointer != entry->extraFieldPointer)
+ {
+ seekResult =
+ hyfile_seek (zipFile->fd, entry->extraFieldPointer, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer = (I_32) seekResult;
+ if (zipFile->pointer != entry->extraFieldPointer)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ }
+ result =
+ hyfile_read (zipFile->fd, extraFieldBuffer, entry->extraFieldLength);
+ if (result != (I_32) entry->extraFieldLength)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer += result;
+ EXIT ();
+ return 0;
+
+finished:
+ if (!buffer)
+ {
+ entry->extraField = NULL;
+ hymem_free_memory (extraFieldBuffer);
+ }
+ if (result == ZIP_ERR_FILE_READ_ERROR)
+ zipFile->pointer = -1;
+ EXIT ();
+ return result;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_getZipEntryFilename
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_getZipEntryComment
+/**
+ * Read the file comment for entry.
+ *
+ * If buffer is non-NULL, it is used, but not held onto by entry.
+ *
+ * If buffer is NULL, memory is allocated and
+ * held onto by entry, and thus should later be freed with @ref zip_freeZipEntry.
+ *
+ * @param[in] portLib the port library
+ * @param[in] zipFile the zip file concerned
+ * @param[in] entry the entry who's comment we want
+ * @param[in] buffer may or may not be NULL
+ * @param[in] bufferSize
+
+ * @return 0 on success or one of the following
+ * @return ZIP_ERR_FILE_READ_ERROR if there is an error reading the file comment from zipEntry
+ * @return ZIP_ERR_FILE_CORRUPT if zipFile is corrupt
+ * @return ZIP_ERR_ENTRY_NOT_FOUND if entry is not found
+ * @return ZIP_ERR_OUT_OF_MEMORY if there is not enough memory to complete this call
+ * @return ZIP_ERR_BUFFER_TOO_SMALL if buffer is too small to hold the comment for zipFile
+*/
+
+I_32
+zip_getZipEntryComment (HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, U_8 * buffer, U_32 bufferSize)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+#if defined(HY_NO_THR)
+ THREAD_ACCESS_FROM_PORT(portLib);
+#endif /* HY_NO_THR */
+
+ I_32 result;
+ U_8 *fileCommentBuffer;
+ I_64 seekResult;
+
+ ENTER ();
+
+ if (entry->fileCommentLength == 0)
+ {
+ if (entry->fileCommentPointer == -1)
+ {
+ /* TODO: we don't know where the comment is (or even if there is one)! This only happens if you're running
+ without a cache, so too bad for now */
+ }
+ EXIT ();
+ return 0;
+ }
+
+ if (buffer)
+ {
+ if (bufferSize < entry->fileCommentLength)
+ {
+ EXIT ();
+ return ZIP_ERR_BUFFER_TOO_SMALL;
+ }
+ fileCommentBuffer = buffer;
+ }
+ else
+ {
+ fileCommentBuffer = hymem_allocate_memory (entry->fileCommentLength);
+ if (!fileCommentBuffer)
+ {
+ EXIT ();
+ return ZIP_ERR_OUT_OF_MEMORY;
+ }
+ entry->fileComment = fileCommentBuffer;
+ }
+
+ if (zipFile->pointer != entry->fileCommentPointer)
+ {
+ seekResult =
+ hyfile_seek (zipFile->fd, entry->fileCommentPointer, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer = (I_32) seekResult;
+
+ if (zipFile->pointer != entry->fileCommentPointer)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ }
+ result =
+ hyfile_read (zipFile->fd, fileCommentBuffer, entry->fileCommentLength);
+ if (result != (I_32) entry->fileCommentLength)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+ zipFile->pointer += result;
+ EXIT ();
+ return 0;
+
+finished:
+ if (!buffer)
+ {
+ entry->fileComment = NULL;
+ hymem_free_memory (fileCommentBuffer);
+ }
+ if (result == ZIP_ERR_FILE_READ_ERROR)
+ {
+ zipFile->pointer = -1;
+ }
+ EXIT ();
+ return result;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_openZipFile
+/**
+ * Attempt to open a zip file.
+ *
+ * If the cache pool is non-NULL, the cachePool will be used to find a suitable cache, and if none can be found it will create one and add it to cachePool.
+ * Zip support is responsible for managing the lifetime of the cache.
+ *
+ * @note If cachePool is NULL, zipFile will be opened without a cache.
+ *
+ * @param[in] portLib the port library
+ * @param[in] filename the zip file to open
+ * @param[out] zipFile the zip file structure to populate
+ * @param[in] cachePool the cache pool
+ *
+ * @return 0 on success
+ * @return ZIP_ERR_FILE_OPEN_ERROR if is there is an error opening the file
+ * @return ZIP_ERR_FILE_READ_ERROR if there is an error reading the file
+ * @return ZIP_ERR_FILE_CORRUPT if the file is corrupt
+ * @return ZIP_ERR_UNKNOWN_FILE_TYPE if the file type is not known
+ * @return ZIP_ERR_UNSUPPORTED_FILE_TYPE if the file type is unsupported
+ * @return ZIP_ERR_OUT_OF_MEMORY if we are out of memory
+*/
+I_32
+zip_openZipFile (HyPortLibrary * portLib, char *filename, HyZipFile * zipFile,
+ HyZipCachePool * cachePool)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+#if defined(HY_NO_THR)
+ THREAD_ACCESS_FROM_PORT(portLib);
+#endif /* HY_NO_THR */
+
+ IDATA fd = -1;
+ I_32 result = 0;
+ I_64 seekResult;
+ U_8 buffer[4];
+ I_32 len;
+
+ ENTER ();
+
+ len = strlen (filename);
+ zipFile->fd = -1;
+ zipFile->type = ZIP_Unknown;
+ zipFile->cache = NULL;
+ zipFile->cachePool = NULL;
+ zipFile->pointer = -1;
+ /* Allocate space for filename */
+ if (len >= ZIP_INTERNAL_MAX)
+ {
+ zipFile->filename = hymem_allocate_memory (len + 1);
+ if (!zipFile->filename)
+ {
+ EXIT ();
+ return ZIP_ERR_OUT_OF_MEMORY;
+ }
+ }
+ else
+ {
+ zipFile->filename = zipFile->internalFilename;
+ }
+
+ strcpy ((char *) zipFile->filename, filename);
+
+ fd = hyfile_open (filename, HyOpenRead, 0);
+ if (fd == -1)
+ {
+ result = ZIP_ERR_FILE_OPEN_ERROR;
+ goto finished;
+ }
+
+ if (hyfile_read (fd, buffer, 4) != 4)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+
+ if ((buffer[0] == 'P') && (buffer[1] == 'K'))
+ {
+ /* If not the central header or local file header, its corrupt */
+ if (!
+ ((buffer[2] == 1 && buffer[3] == 2)
+ || (buffer[2] == 3 && buffer[3] == 4)))
+ {
+ result = ZIP_ERR_FILE_CORRUPT;
+ goto finished;
+ }
+ /* PKZIP file. Back up the pointer to the beginning. */
+ seekResult = hyfile_seek (fd, 0, HySeekSet);
+ if (seekResult != 0)
+ {
+ result = ZIP_ERR_FILE_READ_ERROR;
+ goto finished;
+ }
+
+ zipFile->fd = fd;
+ zipFile->type = ZIP_PKZIP;
+ zipFile->pointer = 0;
+ }
+
+ if ((buffer[0] == 0x1F) && (buffer[1] == 0x8B))
+ {
+ /* GZIP - currently unsupported.
+ zipFile->fd = fd;
+ zipFile->type = ZIP_GZIP;
+ zipFile->pointer = 2;
+ */
+ result = ZIP_ERR_UNSUPPORTED_FILE_TYPE;
+ goto finished;
+ }
+
+ if (zipFile->type == ZIP_Unknown)
+ {
+ result = ZIP_ERR_UNKNOWN_FILE_TYPE;
+ goto finished;
+ }
+
+ result = 0;
+
+ if (cachePool)
+ {
+ zipFile->cachePool = cachePool;
+ result = zip_establishCache (portLib, zipFile);
+ }
+
+finished:
+ if (result == 0)
+ {
+ zipFile->fd = fd;
+ EXIT ();
+ return 0;
+ }
+ if (fd != -1)
+ {
+ hyfile_close (fd);
+ }
+ if ((zipFile->filename) && (zipFile->filename != zipFile->internalFilename))
+ {
+ hymem_free_memory (zipFile->filename);
+ }
+ zipFile->filename = NULL;
+ EXIT ();
+ return result;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_resetZipFile
+/**
+ * Reset nextEntryPointer to the first entry in the file.
+ *
+ * @param[in] portLib the port library
+ * @param[in] zipFile the zip being read from
+ * @param[out] nextEntryPointer will be reset to the first entry in the file
+ *
+ * @return none
+ *
+ *
+*/
+void
+zip_resetZipFile (HyPortLibrary * portLib, HyZipFile * zipFile,
+ IDATA * nextEntryPointer)
+{
+ *nextEntryPointer = 0;
+ if (zipFile)
+ {
+ if (zipFile->cache)
+ *nextEntryPointer = zipFile->cache->startCentralDir;
+ else
+ {
+ I_32 result;
+ HyZipCentralEnd endEntry;
+ result = scanForCentralEnd (portLib, zipFile, &endEntry);
+ if (result != 0)
+ return;
+ *nextEntryPointer = (IDATA) ((UDATA) endEntry.dirOffset);
+ }
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zip_getZipEntryFromOffset
+/**
+ * Attempt to read a zip entry at offset from the zip file provided.
+ * If found, read into entry.
+ *
+ * @note If an uncached entry is found, the filename field will be filled in. This
+ * memory MUST be freed with @ref zip_freeZipEntry.
+ *
+ * @param[in] portLib the port library
+ * @param[in] zipFile the zip file being read
+ * @param[in] offset the offset into the zipFile of the desired zip entry
+ * @param[out] entry the compressed data
+ *
+ * @return 0 on success
+ * @return ZIP_ERR_FILE_READ_ERROR if there is an error reading from @ref zipFile
+ * @return ZIP_ERR_FILE_CORRUPT if @ref zipFile is corrupt
+ * @return ZIP_ERR_ENTRY_NOT_FOUND if the entry is not found
+ * @return ZIP_ERR_OUT_OF_MEMORY if there is not enough memory to complete this call
+ *
+ * @see zip_freeZipEntry
+*/
+I_32
+zip_getZipEntryFromOffset (HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, IDATA offset)
+{
+ PORT_ACCESS_FROM_PORT (portLib);
+#if defined(HY_NO_THR)
+ THREAD_ACCESS_FROM_PORT(portLib);
+#endif /* HY_NO_THR */
+ I_32 result;
+ I_64 seekResult;
+
+ ENTER ();
+
+ if (zipFile->pointer != offset)
+ {
+ seekResult = hyfile_seek (zipFile->fd, offset, HySeekSet);
+ if ((seekResult < 0) || (seekResult > HYCONST64 (0x7FFFFFFF)))
+ {
+ zipFile->pointer = -1;
+ EXIT ();
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ zipFile->pointer = (I_32) seekResult;
+ if (zipFile->pointer != offset)
+ {
+ zipFile->pointer = -1;
+ EXIT ();
+ return ZIP_ERR_FILE_READ_ERROR;
+ }
+ }
+
+ result = readZipEntry (portLib, zipFile, entry, NULL, NULL, NULL, FALSE);
+ EXIT ();
+ return result;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zdataalloc
+/*
+ cached alloc management for zip_getZipEntryData.
+*/
+void *
+zdataalloc (void *opaque, U_32 items, U_32 size)
+{
+ UDATA *returnVal = 0;
+ U_32 byteSize = items * size;
+ U_32 allocSize = WORK_BUFFER_SIZE;
+ struct workBuffer *wb = (struct workBuffer *) opaque;
+
+ PORT_ACCESS_FROM_PORT (wb->portLib);
+
+ /* Round to UDATA multiple */
+ byteSize = (byteSize + (sizeof (UDATA) - 1)) & ~(sizeof (UDATA) - 1);
+
+ if (wb->bufferStart == 0)
+ {
+ if (byteSize > WORK_BUFFER_SIZE)
+ {
+ allocSize = byteSize;
+ }
+ wb->bufferStart = hymem_allocate_memory (allocSize);
+ if (wb->bufferStart)
+ {
+ wb->bufferEnd = (UDATA *) ((UDATA) wb->bufferStart + allocSize);
+ wb->currentAlloc = wb->bufferStart;
+ wb->cntr = 0;
+ }
+ }
+
+ if ((wb->bufferStart == 0)
+ || (((UDATA) wb->currentAlloc + byteSize) > (UDATA) wb->bufferEnd))
+ {
+ returnVal = hymem_allocate_memory (byteSize);
+ }
+ else
+ {
+ ++(wb->cntr);
+ returnVal = wb->currentAlloc;
+ wb->currentAlloc = (UDATA *) ((UDATA) wb->currentAlloc + byteSize);
+ }
+ return returnVal;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION zdatafree
+/*
+ cached alloc management for zip_getZipEntryData.
+*/
+void
+zdatafree (void *opaque, void *address)
+{
+ struct workBuffer *wb = (struct workBuffer *) opaque;
+
+ PORT_ACCESS_FROM_PORT (wb->portLib);
+
+ if ((address < (void *) wb->bufferStart)
+ || (address >= (void *) wb->bufferEnd))
+ {
+ hymem_free_memory (address);
+ }
+ else if (--(wb->cntr) == 0)
+ {
+ hymem_free_memory (wb->bufferStart);
+ wb->bufferStart = wb->bufferEnd = wb->currentAlloc = 0;
+ }
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
diff --git a/archive/src/main/native/zipsup.h b/archive/src/main/native/zipsup.h
new file mode 100644
index 0000000..adc086a
--- /dev/null
+++ b/archive/src/main/native/zipsup.h
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+* Zip Support Header
+*/
+
+#if !defined(ZIPSUP_H)
+#define ZIPSUP_H
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+#include "hy2sie.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <memory.h>
+
+#include "zlib.h"
+
+
+// Contents from Harmony's inflater.h was put here:
+//
+typedef struct JCLZipStream
+{
+ U_8 *inaddr;
+ U_8 *dict;
+ z_stream *stream;
+} JCLZipStream;
+
+
+typedef struct HyZipCachePool HyZipCachePool;
+
+HyZipCachePool *
+zipsup_GetZipCachePool(HyPortLibrary * portLib);
+
+
+#define HY_ZIP_DLL_NAME "hyzlib"
+
+#define ZIP_INTERNAL_MAX 80
+#define ZIP_CM_Reduced1 2
+#define ZIP_Unknown 0
+#define ZIP_GZIP 2
+#define ZIP_ERR_OUT_OF_MEMORY -3
+#define ZIP_ERR_FILE_CORRUPT -6
+#define ZIP_ERR_INTERNAL_ERROR -11
+#define ZIP_CM_Imploded 6
+#define ZIP_CM_Reduced4 5
+#define ZIP_CM_Shrunk 1
+#define ZIP_CM_Reduced2 3
+#define ZIP_ERR_FILE_READ_ERROR -1
+#define ZIP_CentralHeader 0x2014B50
+#define ZIP_ERR_FILE_CLOSE_ERROR -10
+#define ZIP_ERR_BUFFER_TOO_SMALL -7
+#define ZIP_CM_Reduced3 4
+#define ZIP_CM_Deflated 8
+#define ZIP_LocalHeader 0x4034B50
+#define ZIP_CM_Tokenized 7
+#define ZIP_PKZIP 1
+#define ZIP_CM_Stored 0
+#define ZIP_ERR_UNSUPPORTED_FILE_TYPE -5
+#define ZIP_ERR_NO_MORE_ENTRIES -2
+#define ZIP_CentralEnd 0x6054B50
+#define ZIP_ERR_FILE_OPEN_ERROR -9
+#define ZIP_ERR_UNKNOWN_FILE_TYPE -4
+#define ZIP_ERR_ENTRY_NOT_FOUND -8
+#define ZIP_DataDescriptor 0x8074B50
+
+ typedef struct HyZipCache
+ {
+ U_8 *zipFileName;
+ IDATA zipFileSize;
+ I_64 zipTimeStamp;
+ IDATA startCentralDir;
+ HyPortLibrary *portLib;
+ void *cachePool;
+ void *cachePoolEntry;
+ } HyZipCache;
+
+
+ typedef struct HyZipCentralEnd
+ {
+ U_16 diskNumber;
+ U_16 dirStartDisk;
+ U_16 thisDiskEntries;
+ U_16 totalEntries;
+ U_32 dirSize;
+ U_32 dirOffset;
+ U_16 commentLength;
+ char _hypadding0012[2]; /* 2 bytes of automatic padding */
+ U_8 *comment;
+ } HyZipCentralEnd;
+
+
+ typedef struct HyZipDataDescriptor
+ {
+ U_32 crc32;
+ U_32 compressedSize;
+ U_32 uncompressedSize;
+ } HyZipDataDescriptor;
+
+
+ typedef struct HyZipEntry
+ {
+ U_8 *data;
+ U_8 *filename;
+ U_8 *extraField;
+ U_8 *fileComment;
+ I_32 dataPointer;
+ I_32 filenamePointer;
+ I_32 extraFieldPointer;
+ I_32 fileCommentPointer;
+ U_32 compressedSize;
+ U_32 uncompressedSize;
+ U_32 crc32;
+ U_16 filenameLength;
+ U_16 extraFieldLength;
+ U_16 fileCommentLength;
+ U_16 internalAttributes;
+ U_16 versionCreated;
+ U_16 versionNeeded;
+ U_16 flags;
+ U_16 compressionMethod;
+ U_16 lastModTime;
+ U_16 lastModDate;
+ U_8 internalFilename[80];
+ } HyZipEntry;
+
+
+ typedef struct HyZipFile
+ {
+ U_8 *filename;
+ struct HyZipCache *cache;
+ void *cachePool;
+ I_32 fd;
+ I_32 pointer;
+ U_8 internalFilename[80];
+ U_8 type;
+ char _hypadding0065[3]; /* 3 bytes of automatic padding */
+ } HyZipFile;
+
+
+
+// Contents from Harmony's zip.h were put in java_util_zip_ZipFile.c
+// and here:
+typedef struct JCLZipFile
+{
+ struct JCLZipFile *last;
+ struct JCLZipFile *next;
+ HyZipFile hyZipFile;
+} JCLZipFile;
+
+
+
+
+#include "hymutex.h"
+extern MUTEX zip_GlobalMutex;
+
+
+
+#define jclmem_allocate_memory(env, byteCount) sieb_malloc(env, byteCount)
+#define jclmem_free_memory(env, pointer) sieb_free(env, pointer)
+
+
+/* HySourceZipSupport*/
+ extern HY_CFUNC I_32 zip_getZipEntryData
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, U_8 * buffer, U_32 bufferSize));
+ extern HY_CFUNC I_32 zip_getZipEntryFromOffset
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, IDATA offset));
+ extern HY_CFUNC I_32 zip_establishCache
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile));
+ extern HY_CFUNC void zip_resetZipFile
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ IDATA * nextEntryPointer));
+ extern HY_CFUNC I_32 zip_getNextZipEntry
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * zipEntry, IDATA * nextEntryPointer));
+ extern HY_CFUNC I_32 zip_getZipEntry
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, const char *filename,
+ BOOLEAN findDirectory));
+ extern HY_CFUNC I_32 zip_getZipEntryExtraField
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, U_8 * buffer, U_32 bufferSize));
+ extern HY_CFUNC void zip_initZipEntry
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipEntry * entry));
+ extern HY_CFUNC I_32 zip_openZipFile
+ PROTOTYPE ((HyPortLibrary * portLib, char *filename, HyZipFile * zipFile,
+ HyZipCachePool * cachePool));
+ extern HY_CFUNC void zip_freeZipEntry
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipEntry * entry));
+ struct HyZipFile;
+ extern HY_CFUNC I_32 VMCALL zip_closeZipFile
+ PROTOTYPE ((HyPortLibrary * portLib, struct HyZipFile * zipFile));
+ extern HY_CFUNC I_32 zip_getZipEntryComment
+ PROTOTYPE ((HyPortLibrary * portLib, HyZipFile * zipFile,
+ HyZipEntry * entry, U_8 * buffer, U_32 bufferSize));
+/* HySourceZipCache*/
+ extern HY_CFUNC UDATA zipCache_findElement
+ PROTOTYPE ((HyZipCache * zipCache, const char *elementName,
+ BOOLEAN searchDirList));
+ extern HY_CFUNC void zipCache_kill PROTOTYPE ((HyZipCache * zipCache));
+ extern HY_CFUNC IDATA zipCache_enumGetDirName
+ PROTOTYPE ((void *handle, char *nameBuf, UDATA nameBufSize));
+ extern HY_CFUNC HyZipCache *zipCache_new
+ PROTOTYPE ((HyPortLibrary * portLib, char *zipName, IDATA zipNameLength));
+ extern HY_CFUNC IDATA zipCache_enumNew
+ PROTOTYPE ((HyZipCache * zipCache, char *directoryName, void **handle));
+ extern HY_CFUNC IDATA zipCache_enumElement
+ PROTOTYPE ((void *handle, char *nameBuf, UDATA nameBufSize,
+ UDATA * offset));
+ extern HY_CFUNC void zipCache_enumKill PROTOTYPE ((void *handle));
+ extern HY_CFUNC BOOLEAN zipCache_addElement
+ PROTOTYPE ((HyZipCache * zipCache, char *elementName,
+ UDATA elementOffset));
+/* HySourceZipCachePool*/
+ extern HY_CFUNC BOOLEAN zipCachePool_release
+ PROTOTYPE ((HyZipCachePool * zcp, HyZipCache * zipCache));
+ extern HY_CFUNC void zipCachePool_kill PROTOTYPE ((HyZipCachePool * zcp));
+ extern HY_CFUNC HyZipCache *zipCachePool_findCache
+ PROTOTYPE ((HyZipCachePool * zcp, char const *zipFileName,
+ IDATA zipFileNameLength, IDATA zipFileSize,
+ I_64 zipTimeStamp));
+ extern HY_CFUNC HyZipCachePool *zipCachePool_new
+ PROTOTYPE ((HyPortLibrary * portLib));
+ extern HY_CFUNC BOOLEAN zipCachePool_addCache
+ PROTOTYPE ((HyZipCachePool * zcp, HyZipCache * zipCache));
+ extern HY_CFUNC BOOLEAN zipCachePool_addRef
+ PROTOTYPE ((HyZipCachePool * zcp, HyZipCache * zipCache));
+#if defined(__cplusplus)
+}
+#endif
+#endif /* ZIPSUP_H */
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AllTests.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AllTests.java
new file mode 100644
index 0000000..13fe019
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AllTests.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite for java.util.jar package.
+ */
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite = tests.TestSuiteFactory.createTestSuite(
+ "Suite org.apache.harmony.archive.tests.java.util.jar");
+ suite.addTestSuite(AttributesNameTest.class);
+ suite.addTestSuite(AttributesTest.class);
+ suite.addTestSuite(JarEntryTest.class);
+ suite.addTestSuite(JarExceptionTest.class);
+ suite.addTestSuite(JarExecTest.class);
+ suite.addTestSuite(JarFileTest.class);
+ suite.addTestSuite(JarInputStreamTest.class);
+ suite.addTestSuite(JarOutputStreamTest.class);
+ suite.addTestSuite(ManifestTest.class);
+ suite.addTestSuite(Pack200Test.class);
+ suite.addTestSuite(Pack200PackerTest.class);
+ suite.addTestSuite(Pack200UnpackerTest.class);
+ suite.addTestSuite(ZipExecTest.class);
+ return suite;
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesNameTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesNameTest.java
new file mode 100644
index 0000000..067bf49
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesNameTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.util.jar.Attributes;
+import junit.framework.TestCase;
+
+@TestTargetClass(Attributes.Name.class)
+public class AttributesNameTest extends TestCase {
+
+ /**
+ * @tests java.util.jar.Attributes.Name#Name(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Name",
+ args = {java.lang.String.class}
+ )
+ public void test_AttributesName_Constructor() {
+ // Regression for HARMONY-85
+ try {
+ new Attributes.Name(
+ "01234567890123456789012345678901234567890123456789012345678901234567890");
+ fail("Assert 0: should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ new Attributes.Name((String) null);
+ fail("NullPointerException expected");
+ } catch (NullPointerException ee) {
+ // expected
+ }
+
+ assertNotNull(new Attributes.Name("Attr"));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "equals",
+ args = {java.lang.Object.class}
+ )
+ public void test_equalsLjava_lang_Object() {
+ Attributes.Name attr1 = new Attributes.Name("Attr");
+ Attributes.Name attr2 = new Attributes.Name("Attr");
+
+ assertTrue(attr1.equals(attr2));
+ attr2 = new Attributes.Name("Attr1");
+ assertFalse(attr1.equals(attr2));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "hashCode",
+ args = {}
+ )
+ public void test_hashCode() {
+ Attributes.Name attr1 = new Attributes.Name("Attr1");
+ Attributes.Name attr2 = new Attributes.Name("Attr2");
+
+ assertNotSame(attr1.hashCode(), attr2.hashCode());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "toString",
+ args = {}
+ )
+ public void test_toString() {
+ String str1 = "Attr1";
+ String str2 = "Attr2";
+ Attributes.Name attr1 = new Attributes.Name(str1);
+ Attributes.Name attr2 = new Attributes.Name("Attr2");
+
+ assertTrue(attr1.toString().equals(str1));
+ assertTrue(attr2.toString().equals(str2));
+ assertFalse(attr2.toString().equals(str1));
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java
new file mode 100644
index 0000000..0a8b037
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java
@@ -0,0 +1,520 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import junit.framework.TestCase;
+
+@TestTargetClass(Attributes.class)
+public class AttributesTest extends TestCase {
+ private Attributes a;
+
+ @Override
+ protected void setUp() {
+ a = new Attributes();
+ a.putValue("1", "one");
+ a.putValue("2", "two");
+ a.putValue("3", "three");
+ a.putValue("4", "four");
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#Attributes(java.util.jar.Attributes)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Attributes",
+ args = {java.util.jar.Attributes.class}
+ )
+ public void test_ConstructorLjava_util_jar_Attributes() {
+ Attributes a2 = new Attributes(a);
+ assertEquals(a, a2);
+ a.putValue("1", "one(1)");
+ assertTrue("equal", !a.equals(a2));
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#clear()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clear",
+ args = {}
+ )
+ public void test_clear() {
+ a.clear();
+ assertNull("a) All entries should be null after clear", a.get("1"));
+ assertNull("b) All entries should be null after clear", a.get("2"));
+ assertNull("c) All entries should be null after clear", a.get("3"));
+ assertNull("d) All entries should be null after clear", a.get("4"));
+ assertTrue("Should not contain any keys", !a.containsKey("1"));
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#containsKey(java.lang.Object)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "containsKey",
+ args = {java.lang.Object.class}
+ )
+ public void test_containsKeyLjava_lang_Object() {
+ assertTrue("a) Should have returned false", !a.containsKey(new Integer(
+ 1)));
+ assertTrue("b) Should have returned false", !a.containsKey("0"));
+ assertTrue("Should have returned true", a
+ .containsKey(new Attributes.Name("1")));
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#containsValue(java.lang.Object)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "containsValue",
+ args = {java.lang.Object.class}
+ )
+ public void test_containsValueLjava_lang_Object() {
+ assertTrue("Should have returned false", !a.containsValue("One"));
+ assertTrue("Should have returned true", a.containsValue("one"));
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#entrySet()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "entrySet",
+ args = {}
+ )
+ public void test_entrySet() {
+ Set<Map.Entry<Object, Object>> entrySet = a.entrySet();
+ Set<Object> keySet = new HashSet<Object>();
+ Set<Object> valueSet = new HashSet<Object>();
+ Iterator<?> i;
+ assertEquals(4, entrySet.size());
+ i = entrySet.iterator();
+ while (i.hasNext()) {
+ java.util.Map.Entry<?, ?> e;
+ e = (Map.Entry<?, ?>) i.next();
+ keySet.add(e.getKey());
+ valueSet.add(e.getValue());
+ }
+ assertTrue("a) Should contain entry", valueSet.contains("one"));
+ assertTrue("b) Should contain entry", valueSet.contains("two"));
+ assertTrue("c) Should contain entry", valueSet.contains("three"));
+ assertTrue("d) Should contain entry", valueSet.contains("four"));
+ assertTrue("a) Should contain key", keySet
+ .contains(new Attributes.Name("1")));
+ assertTrue("b) Should contain key", keySet
+ .contains(new Attributes.Name("2")));
+ assertTrue("c) Should contain key", keySet
+ .contains(new Attributes.Name("3")));
+ assertTrue("d) Should contain key", keySet
+ .contains(new Attributes.Name("4")));
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#get(java.lang.Object)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getValue",
+ args = {java.lang.String.class}
+ )
+ public void test_getLjava_lang_Object() {
+ assertEquals("a) Incorrect value returned", "one", a.getValue("1"));
+ assertNull("b) Incorrect value returned", a.getValue("0"));
+
+ try {
+ a.getValue("IllegalArgumentException expected");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#isEmpty()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "isEmpty",
+ args = {}
+ )
+ public void test_isEmpty() {
+ assertTrue("Should not be empty", !a.isEmpty());
+ a.clear();
+ assertTrue("a) Should be empty", a.isEmpty());
+ a = new Attributes();
+ assertTrue("b) Should be empty", a.isEmpty());
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#keySet()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "keySet",
+ args = {}
+ )
+ public void test_keySet() {
+ Set<?> s = a.keySet();
+ assertEquals(4, s.size());
+ assertTrue("a) Should contain entry", s.contains(new Attributes.Name(
+ "1")));
+ assertTrue("b) Should contain entry", s.contains(new Attributes.Name(
+ "2")));
+ assertTrue("c) Should contain entry", s.contains(new Attributes.Name(
+ "3")));
+ assertTrue("d) Should contain entry", s.contains(new Attributes.Name(
+ "4")));
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#putAll(java.util.Map)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "putAll",
+ args = {java.util.Map.class}
+ )
+ public void test_putAllLjava_util_Map() {
+ Attributes b = new Attributes();
+ b.putValue("3", "san");
+ b.putValue("4", "shi");
+ b.putValue("5", "go");
+ b.putValue("6", "roku");
+ a.putAll(b);
+ assertEquals("Should not have been replaced", "one", a.getValue("1"));
+ assertEquals("Should have been replaced", "san", a.getValue("3"));
+ assertEquals("Should have been added", "go", a.getValue("5"));
+ Attributes atts = new Attributes();
+ assertNull("Assert 0: ", atts.put(Attributes.Name.CLASS_PATH,
+ "tools.jar"));
+ assertNull("Assert 1: ", atts
+ .put(Attributes.Name.MANIFEST_VERSION, "1"));
+ Attributes atts2 = new Attributes();
+ atts2.putAll(atts);
+ assertEquals("Assert 2:", "tools.jar", atts2
+ .get(Attributes.Name.CLASS_PATH));
+ assertEquals("Assert 3: ", "1", atts2
+ .get(Attributes.Name.MANIFEST_VERSION));
+ try {
+ atts.putAll(Collections.EMPTY_MAP);
+ fail("Assert 4: no class cast from attrib parameter");
+ } catch (ClassCastException e) {
+ // Expected
+ }
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#putAll(java.util.Map)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "Regression test",
+ method = "putAll",
+ args = {java.util.Map.class}
+ )
+ public void test_putAllLjava_util_Map2() {
+ // Regression for HARMONY-464
+ try {
+ new Attributes().putAll((Map) null);
+ fail("ClassCastException expected");
+ } catch (ClassCastException e) {
+ }
+ // verify that special care for null is done in the Attributes.putAll()
+ // method
+ try {
+ new Attributes() {
+ @Override
+ public void putAll(Map<?, ?> attrib) {
+ map.putAll(attrib);
+ }
+ }.putAll((Map<?, ?>) null);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#remove(java.lang.Object)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "remove",
+ args = {java.lang.Object.class}
+ )
+ public void test_removeLjava_lang_Object() {
+ a.remove(new Attributes.Name("1"));
+ a.remove(new Attributes.Name("3"));
+ assertNull("Should have been removed", a.getValue("1"));
+ assertEquals("Should not have been removed", "four", a.getValue("4"));
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#size()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "size",
+ args = {}
+ )
+ public void test_size() {
+ assertEquals("Incorrect size returned", 4, a.size());
+ a.clear();
+ assertEquals(0, a.size());
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#values()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "values",
+ args = {}
+ )
+ public void test_values() {
+ Collection<?> valueCollection = a.values();
+ assertTrue("a) Should contain entry", valueCollection.contains("one"));
+ assertTrue("b) Should contain entry", valueCollection.contains("two"));
+ assertTrue("c) Should contain entry", valueCollection.contains("three"));
+ assertTrue("d) Should contain entry", valueCollection.contains("four"));
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#clone()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clone",
+ args = {}
+ )
+ public void test_clone() {
+ Attributes a2 = (Attributes) a.clone();
+ assertEquals(a, a2);
+ a.putValue("1", "one(1)");
+ assertTrue("equal", !a.equals(a2));
+ }
+
+ /**
+ * @tests java.util.jar.Attributes#equals(java.lang.Object)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "equals",
+ args = {java.lang.Object.class}
+ )
+ public void test_equalsLjava_lang_Object() {
+ Attributes.Name n1 = new Attributes.Name("name"), n2 = new Attributes.Name(
+ "Name");
+ assertEquals(n1, n2);
+ Attributes a1 = new Attributes();
+ a1.putValue("one", "1");
+ a1.putValue("two", "2");
+ Attributes a2 = new Attributes();
+ a2.putValue("One", "1");
+ a2.putValue("TWO", "2");
+ assertEquals(a1, a2);
+ }
+
+ /**
+ * @tests java.util.jar.Attributes.put(java.lang.Object, java.lang.Object)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "Regression test. Checks ClassCastException",
+ method = "put",
+ args = {java.lang.Object.class, java.lang.Object.class}
+ )
+ public void test_putLjava_lang_ObjectLjava_lang_Object() {
+ Attributes atts = new Attributes();
+ assertNull("Assert 0: ", atts.put(Attributes.Name.CLASS_PATH,
+ "tools.jar"));
+ assertEquals("Assert 1: ", "tools.jar", atts
+ .getValue(Attributes.Name.CLASS_PATH));
+ // Regression for HARMONY-79
+ try {
+ atts.put("not a name", "value");
+ fail("Assert 2: no class cast from key parameter");
+ } catch (ClassCastException e) {
+ // Expected
+ }
+ try {
+ atts.put(Attributes.Name.CLASS_PATH, Boolean.TRUE);
+ fail("Assert 3: no class cast from value parameter");
+ } catch (ClassCastException e) {
+ // Expected
+ }
+ }
+
+ /**
+ * @tests java.util.jar.Attributes.put(java.lang.Object, java.lang.Object)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "ClassCastException checking missed.",
+ method = "put",
+ args = {java.lang.Object.class, java.lang.Object.class}
+ )
+ public void test_putLjava_lang_ObjectLjava_lang_Object_Null() {
+
+ Attributes attribute = new Attributes();
+
+ assertFalse(attribute.containsKey(null));
+ assertFalse(attribute.containsValue(null));
+ attribute.put(null, null);
+ attribute.put(null, null);
+ assertEquals(1, attribute.size());
+ assertTrue(attribute.containsKey(null));
+ assertTrue(attribute.containsValue(null));
+ assertNull(attribute.get(null));
+
+ String value = "It's null";
+ attribute.put(null, value);
+ assertEquals(1, attribute.size());
+ assertEquals(value, attribute.get(null));
+
+ Attributes.Name name = new Attributes.Name("null");
+ attribute.put(name, null);
+ assertEquals(2, attribute.size());
+ assertNull(attribute.get(name));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Attributes",
+ args = {}
+ )
+ public void test_Constructor() {
+ Attributes attr = new Attributes();
+ assertTrue(attr.size() >= 0);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Attributes",
+ args = {int.class}
+ )
+ public void test_ConstructorI() {
+ Attributes attr = new Attributes(10);
+ assertTrue(attr.size() >= 0);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "get",
+ args = {java.lang.Object.class}
+ )
+ public void test_getLjava_lang_Object_true() {
+ assertEquals("a) Incorrect value returned", "one", a
+ .get(new Attributes.Name("1")));
+ assertNull("b) Incorrect value returned", a.get("0"));
+ assertNull("b) Incorrect value returned", a.get("1"));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getValue",
+ args = {java.util.jar.Attributes.Name.class}
+ )
+ public void test_getValueLjava_util_jar_Attributes_Name() {
+ assertEquals("a) Incorrect value returned", "one", a
+ .getValue(new Attributes.Name("1")));
+ assertNull("b) Incorrect value returned", a
+ .getValue(new Attributes.Name("0")));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "hashCode",
+ args = {}
+ )
+ public void test_hashCode() {
+ Attributes b = (Attributes) a.clone();
+ b.putValue("33", "Thirty three");
+ assertNotSame(a.hashCode(), b.hashCode());
+ b = (Attributes) a.clone();
+ b.clear();
+ assertNotSame(a.hashCode(), b.hashCode());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "putValue",
+ args = {java.lang.String.class, java.lang.String.class}
+ )
+ public void test_putValueLjava_lang_StringLjava_lang_String() {
+ Attributes b = new Attributes();
+ b.put(new Attributes.Name("1"), "one");
+ b.putValue("2", "two");
+ b.put(new Attributes.Name("3"), "three");
+ b.putValue("4", "four");
+
+ assertTrue(a.equals(b));
+
+ try {
+ b.putValue(null, "null");
+ fail("NullPointerException expected");
+ } catch (NullPointerException ee) {
+ // expected
+ }
+
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < 0x10000; i++) {
+ sb.append('3');
+ }
+ try {
+ b.putValue(new String(sb), "wrong name");
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/DalvikExecTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/DalvikExecTest.java
new file mode 100644
index 0000000..77fbb15
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/DalvikExecTest.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.AndroidOnly;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+import junit.framework.TestCase;
+
+import tests.support.Support_Exec;
+import tests.support.resource.Support_Resources;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.jar.JarFile;
+
+
+@TestTargetClass(JarOutputStream.class)
+@AndroidOnly("dalvik vm specific")
+public class DalvikExecTest extends TestCase {
+
+ String execDalvik1 (String classpath, String mainClass, String arg1)
+ throws IOException, InterruptedException {
+
+ ArrayList<String> cmdLine = new ArrayList<String>(10);
+
+ String base = System.getenv("OUT");
+ cmdLine.add(base + "/system/bin/dalvikvm");
+
+ cmdLine.add("-Djava.io.tmpdir=/tmp/mc");
+ cmdLine.add("-Duser.language=en");
+ cmdLine.add("-Duser.region=US");
+
+ if ("true".equals(System.getenv("TARGET_SIMULATOR"))) {
+ // Test against SIMULATOR:
+// cmdLine.add("-Xmx512M");
+// cmdLine.add("-Xcheck:jni");
+ cmdLine.add("-Xbootclasspath:" + System.getProperty("java.boot.class.path"));
+ } else {
+ // Test against EMULATOR:
+ }
+
+ cmdLine.add("-classpath");
+ cmdLine.add(classpath);
+ cmdLine.add(mainClass);
+
+ if (arg1 != null) cmdLine.add(arg1);
+
+ Object[] res = Support_Exec.execAndDigestOutput(
+ cmdLine.toArray(new String[cmdLine.size()]),
+ null );
+ return Support_Exec.getProcessOutput(res, true);
+ }
+
+ String execDalvik (String classpath, String mainClass)
+ throws IOException, InterruptedException {
+ return execDalvik1(classpath, mainClass, null);
+ }
+
+ @TestTargets ({
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Execute an existing JAR on dalvikvm using -classpath option.",
+ clazz = Runtime.class,
+ method = "exec",
+ args = {java.lang.String[].class}
+ )
+ })
+ public void test_execExistingJar () throws IOException, InterruptedException {
+ String res;
+ File jarFile;
+ if (System.getProperty("java.vendor").contains("Android")) {
+ //
+ // Test against Android:
+ //
+ File tempDir = Support_Resources.createTempFolder();
+ jarFile = Support_Resources.copyFile(
+ tempDir, null, "cts_dalvikExecTest.jar" );
+ res = execDalvik(jarFile.getAbsolutePath(), "dalvikExecTest.HelloWorld");
+ assertEquals("Hello Android World!", "Hello Android World!\n", res);
+
+ res = execDalvik(jarFile.getAbsolutePath(), "dalvikExecTest.ResourceDumper");
+ assertTrue("Android Resource Dumper started",
+ res.contains("Android Resource Dumper started"));
+ assertTrue("This Resource contains some text.",
+ res.contains("This Resource contains some text."));
+ } else {
+ //
+ // Test against RI:
+ //
+ // Do nothing!
+ }
+ }
+
+
+ @TestTargets ({
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "putNextEntry",
+ args = {java.util.zip.ZipEntry.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ method = "JarOutputStream",
+ args = {java.io.OutputStream.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Create a temp file, fill it with contents according to Dalvik JAR format, and execute it on dalvikvm using -classpath option.",
+ clazz = Runtime.class,
+ method = "exec",
+ args = {java.lang.String[].class}
+ )
+ })
+ public void test_execCreatedJar () throws IOException, InterruptedException {
+ File jarFile = File.createTempFile("cts_dalvikExecTest_", ".jar");
+ jarFile.deleteOnExit();
+
+ // Create a JAR output stream on the temp file:
+ JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(jarFile));
+
+ // Define the entry for the classes.dex:
+ jarOut.putNextEntry(new JarEntry("classes.dex"));
+
+ // Fill in the classes.dex contents, i.e. the Dalvik executable code:
+ // (See below for the detailed source code contents.)
+ Support_Resources.writeResourceToStream("cts_dalvikExecTest_classes.dex", jarOut);
+
+ // Now add a resource file:
+ //
+ jarOut.putNextEntry(new JarEntry("dalvikExecTest/myResource"));
+ jarOut.write("This Resource contains some text.".getBytes());
+
+ // Close the stream to the completed JAR file.
+ jarOut.close();
+
+ // The resulting JAR file contains the classes listed at the end of this text,
+ // like the 'cts_dalvikExecTest.jar' as part of the resources, too.
+
+ String res;
+
+ res = execDalvik(jarFile.getAbsolutePath(), "dalvikExecTest.HelloWorld");
+ assertEquals("Hello Android World!", "Hello Android World!\n", res);
+
+ res = execDalvik(jarFile.getAbsolutePath(), "dalvikExecTest.ResourceDumper");
+ assertTrue("Android Resource Dumper started",
+ res.contains("Android Resource Dumper started"));
+ assertTrue("This Resource contains some text.",
+ res.contains("This Resource contains some text."));
+ }
+
+
+ @TestTargets ({
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "putNextEntry",
+ args = {java.util.zip.ZipEntry.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "JarOutputStream",
+ args = {java.io.OutputStream.class, java.util.jar.Manifest.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ clazz = Runtime.class,
+ method = "exec",
+ args = {java.lang.String[].class}
+ )
+ })
+ /**
+ * This test does quite the same as test_execCreatedJar, but includes a manifest.
+ * Note however that the Dalvik JAR format does not require this manifest.
+ * We just test whether the manifest is placed correctly within the JAR by
+ * dumping its contents read as a simple text resource.
+ * No! We can't do that so easily either, as there are other (parent) JARs
+ * with a manifest inside, taken with precedence.
+ * So we will reopen the JAR as a JarFile and check the manifest
+ * with a top level end-to-end approach.
+ */
+ public void test_execCreatedJarWithManifest () throws IOException, InterruptedException {
+ File jarFile = File.createTempFile("cts_dalvikExecTest_", ".jar");
+ jarFile.deleteOnExit();
+
+ // Create the manifest:
+ Manifest manifest = new Manifest();
+ Attributes attrs = manifest.getMainAttributes();
+ attrs.put(Attributes.Name.MANIFEST_VERSION, "3.1415962");
+ attrs.put(Attributes.Name.MAIN_CLASS, "dalvikExecTest.HelloWorld");
+ attrs.put(Attributes.Name.CLASS_PATH, jarFile.getName());
+
+ // Create a JAR output stream on the temp file using the manifest:
+ JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(jarFile), manifest);
+
+ // Define the entry for the classes.dex:
+ jarOut.putNextEntry(new JarEntry("classes.dex"));
+
+ // Fill in the classes.dex contents, i.e. the Dalvik executable code:
+ // (See below for the detailed source code contents.)
+ Support_Resources.writeResourceToStream("cts_dalvikExecTest_classes.dex", jarOut);
+
+ // Now add a resource file:
+ //
+ jarOut.putNextEntry(new JarEntry("dalvikExecTest/myResource"));
+ jarOut.write("This Resource contains some text.".getBytes());
+
+ // Close the stream to the completed JAR file.
+ jarOut.close();
+
+ // The resulting JAR file contains the classes listed at the end of this text,
+ // like the 'cts_dalvikExecTest.jar' as part of the resources, too.
+
+ String res;
+
+ res = execDalvik(jarFile.getAbsolutePath(), "dalvikExecTest.HelloWorld");
+ assertEquals("Hello Android World!", "Hello Android World!\n", res);
+
+ res = execDalvik(jarFile.getAbsolutePath(), "dalvikExecTest.ResourceDumper");
+ assertTrue("Android Resource Dumper started",
+ res.contains("Android Resource Dumper started"));
+ assertTrue("This Resource contains some text.",
+ res.contains("This Resource contains some text."));
+
+ // And now reread the manifest:
+ //
+ JarFile jarIn = new JarFile(jarFile);
+ manifest = jarIn.getManifest();
+ attrs = manifest.getMainAttributes();
+ assertEquals("MANIFEST_VERSION must match!", "3.1415962",
+ attrs.get(Attributes.Name.MANIFEST_VERSION));
+ assertEquals("MAIN_CLASS must match!", "dalvikExecTest.HelloWorld",
+ attrs.get(Attributes.Name.MAIN_CLASS));
+ assertEquals("CLASS_PATH must match!", jarFile.getName(),
+ attrs.get(Attributes.Name.CLASS_PATH));
+ }
+
+
+ /*
+ * The following two classes are added, here, only for completeness.
+ * They form the contents of the dalvikExecTest package contained
+ * in the 'cts_dalvikExecTest_classes.dex' resource file.
+ */
+ /**
+ * @hide
+ */
+ public static class HelloWorld {
+
+ public static void main(String[] args) {
+ System.out.println("Hello Android World!");
+ }
+
+ }
+
+ public static class ResourceDumper {
+
+ static ByteArrayOutputStream outputFrom (InputStream input) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buffer = new byte[512];
+ int total = 0;
+ int count;
+ count = input.read(buffer);
+ while (count != -1) {
+ out.write(buffer, 0, count);
+ total = total + count;
+ count = input.read(buffer);
+ }
+ return out;
+ }
+
+ public static void main(String[] args) throws IOException {
+ System.out.print("Android Resource Dumper started ");
+ String fileName;
+ if (args.length >= 1) {
+ fileName = args[0];
+ System.out.format("for argument '%s'.\n", fileName);
+ } else {
+ System.out.print("standard ");
+ fileName = "myResource";
+ System.out.println("for standard 'myResource'.");
+ }
+ InputStream is = ResourceDumper.class.getResourceAsStream(fileName);
+ if (is != null) {
+ System.out.println("Resource obtained and being dumped:");
+ System.out.println(outputFrom(is).toString());
+ }
+ }
+
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
new file mode 100644
index 0000000..40eff3b
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
@@ -0,0 +1,259 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.CodeSigner;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import junit.framework.TestCase;
+import tests.support.resource.Support_Resources;
+
+
+@TestTargetClass(JarEntry.class)
+public class JarEntryTest extends TestCase {
+ private ZipEntry zipEntry;
+
+ private JarEntry jarEntry;
+
+ private JarFile jarFile;
+
+ private final String jarName = "hyts_patch.jar";
+
+ private final String entryName = "foo/bar/A.class";
+
+ private final String entryName2 = "Blah.txt";
+
+ private final String attJarName = "hyts_att.jar";
+
+ private final String attEntryName = "HasAttributes.txt";
+
+ private final String attEntryName2 = "NoAttributes.txt";
+
+ private File resources;
+
+ @Override
+ protected void setUp() throws Exception {
+ resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, jarName);
+ jarFile = new JarFile(new File(resources, jarName));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarEntry#JarEntry(java.util.zip.ZipEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarEntry",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_ConstructorLjava_util_zip_ZipEntry() {
+ assertNotNull("Jar file is null", jarFile);
+ zipEntry = jarFile.getEntry(entryName);
+ assertNotNull("Zip entry is null", zipEntry);
+ jarEntry = new JarEntry(zipEntry);
+ assertNotNull("Jar entry is null", jarEntry);
+ assertEquals("Wrong entry constructed--wrong name", entryName, jarEntry
+ .getName());
+ assertEquals("Wrong entry constructed--wrong size", 311, jarEntry
+ .getSize());
+ }
+
+ /**
+ * @tests java.util.jar.JarEntry#getAttributes()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getAttributes",
+ args = {}
+ )
+ public void test_getAttributes() {
+ JarFile attrJar = null;
+ File file = null;
+ try {
+ Support_Resources.copyFile(resources, null, attJarName);
+ file = new File(resources, attJarName);
+ attrJar = new JarFile(file);
+ } catch (Exception e) {
+ assertTrue(file + " does not exist", file.exists());
+ fail("Exception opening file: " + e.toString());
+ }
+ try {
+ jarEntry = attrJar.getJarEntry(attEntryName);
+ assertNotNull("Should have Manifest attributes", jarEntry
+ .getAttributes());
+ } catch (Exception e) {
+ fail("Exception during 2nd test: " + e.toString());
+ }
+ try {
+ jarEntry = attrJar.getJarEntry(attEntryName2);
+ assertNull("Shouldn't have any Manifest attributes", jarEntry
+ .getAttributes());
+ attrJar.close();
+ } catch (Exception e) {
+ fail("Exception during 1st test: " + e.toString());
+ }
+
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ try {
+ attrJar = new JarFile(new File(resources, "Broken_manifest.jar"));
+ jarEntry = attrJar.getJarEntry("META-INF/");
+ jarEntry.getAttributes();
+ fail("IOException expected");
+ } catch (IOException e) {
+ // expected.
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarEntry#getCertificates()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getCertificates",
+ args = {}
+ )
+ public void test_getCertificates() throws Exception {
+ zipEntry = jarFile.getEntry(entryName2);
+ jarEntry = new JarEntry(zipEntry);
+ assertNull("Shouldn't have any Certificates", jarEntry
+ .getCertificates());
+
+ // Regression Test for HARMONY-3424
+ String jarFileName = "TestCodeSigners.jar";
+ Support_Resources.copyFile(resources, null, jarFileName);
+ File file = new File(resources, jarFileName);
+ JarFile jarFile = new JarFile(file);
+ JarEntry jarEntry1 = jarFile.getJarEntry("Test.class");
+ JarEntry jarEntry2 = jarFile.getJarEntry("Test.class");
+ InputStream in = jarFile.getInputStream(jarEntry1);
+ byte[] buffer = new byte[1024];
+ while (in.read(buffer) >= 0);
+ in.close();
+ assertNotNull(jarEntry1.getCertificates());
+ assertNotNull(jarEntry2.getCertificates());
+ }
+
+ /**
+ * @tests java.util.jar.JarEntry#getCodeSigners()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getCodeSigners",
+ args = {}
+ )
+ public void test_getCodeSigners() throws IOException {
+ String jarFileName = "TestCodeSigners.jar";
+ Support_Resources.copyFile(resources, null, jarFileName);
+ File file = new File(resources, jarFileName);
+ JarFile jarFile = new JarFile(file);
+ JarEntry jarEntry = jarFile.getJarEntry("Test.class");
+ InputStream in = jarFile.getInputStream(jarEntry);
+ byte[] buffer = new byte[1024];
+ while (in.available() > 0) {
+ in.read(buffer);
+ }
+ CodeSigner[] codeSigners = jarEntry.getCodeSigners();
+ assertEquals(2, codeSigners.length);
+ List<?> certs_bob = codeSigners[0].getSignerCertPath()
+ .getCertificates();
+ List<?> certs_alice = codeSigners[1].getSignerCertPath()
+ .getCertificates();
+ if (1 == certs_bob.size()) {
+ List<?> temp = certs_bob;
+ certs_bob = certs_alice;
+ certs_alice = temp;
+ }
+ assertEquals(2, certs_bob.size());
+ assertEquals(1, certs_alice.size());
+ assertNull(
+ "getCodeSigners() of a primitive JarEntry should return null",
+ new JarEntry("aaa").getCodeSigners());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarEntry",
+ args = {java.lang.String.class}
+ )
+ public void test_ConstructorLjava_lang_String() {
+ assertNotNull("Jar file is null", jarFile);
+ zipEntry = jarFile.getEntry(entryName);
+ assertNotNull("Zip entry is null", zipEntry);
+ jarEntry = new JarEntry(entryName);
+ assertNotNull("Jar entry is null", jarEntry);
+ assertEquals("Wrong entry constructed--wrong name", entryName, jarEntry
+ .getName());
+ try {
+ jarEntry = new JarEntry((String) null);
+ fail("NullPointerException expected");
+ } catch (NullPointerException ee) {
+ // expected
+ }
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < 0x10000; i++) {
+ sb.append('3');
+ }
+ try {
+ jarEntry = new JarEntry(new String(sb));
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarEntry",
+ args = {java.util.jar.JarEntry.class}
+ )
+ public void test_ConstructorLjava_util_jar_JarEntry() {
+ assertNotNull("Jar file is null", jarFile);
+ JarEntry je = jarFile.getJarEntry(entryName);
+ assertNotNull("Jar entry is null", je);
+ jarEntry = new JarEntry(je);
+ assertNotNull("Jar entry is null", jarEntry);
+ assertEquals("Wrong entry constructed--wrong name", entryName, jarEntry
+ .getName());
+ assertEquals("Wrong entry constructed--wrong size", 311, jarEntry
+ .getSize());
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarExceptionTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarExceptionTest.java
new file mode 100644
index 0000000..7f48342
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarExceptionTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.jar.Manifest;
+import junit.framework.TestCase;
+import java.util.jar.JarException;
+
+@TestTargetClass(JarException.class)
+public class JarExceptionTest extends TestCase {
+ /**
+ * @tests java.util.jar.JarException#JarException(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarException",
+ args = {}
+ )
+ public void test_Constructor() throws Exception {
+ JarException ex = new JarException();
+ JarException ex1 = new JarException("Test string");
+ JarException ex2 = new JarException(null);
+ assertNotSame(ex, ex1);
+ assertNotSame(ex.getMessage(), ex1.getMessage());
+ assertNotSame(ex, ex2);
+ assertSame(ex.getMessage(), ex2.getMessage());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarException",
+ args = {java.lang.String.class}
+ )
+ public void test_ConstructorLjava_lang_String() throws Exception {
+ JarException ex1 = new JarException("Test string");
+ JarException ex2 = new JarException(null);
+ assertNotSame(ex1, ex2);
+ assertNotSame(ex1.getMessage(), ex2.getMessage());
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarExecTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarExecTest.java
new file mode 100644
index 0000000..4c209d1
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarExecTest.java
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import tests.support.Support_Exec;
+import tests.support.resource.Support_Resources;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+/**
+ *
+ * tests for various cases of java -jar ... execution
+ *
+ */
+
+@TestTargetClass(JarOutputStream.class)
+public class JarExecTest extends junit.framework.TestCase {
+ /**
+ * regression test for HARMONY-1562 issue
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Regression functional test. Exception checking missed.",
+ method = "putNextEntry",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
+ public void test_1562() throws Exception {
+ // create the manifest
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+
+ File outputJar = File.createTempFile("hyts_", ".jar");
+ outputJar.deleteOnExit();
+ JarOutputStream jout = new JarOutputStream(new FileOutputStream(
+ outputJar), man);
+ File resources = Support_Resources.createTempFolder();
+
+ for (String jarClass : new String[] {"Foo", "Bar"}) {
+ jout.putNextEntry(new JarEntry("foo/bar/execjartest/" + jarClass
+ + ".class"));
+ jout.write(getResource(resources, "hyts_" + jarClass + ".ser"));
+ }
+
+ jout.close();
+
+
+ // set up the VM parameters
+ String[] args = new String[] {"-jar", outputJar.getAbsolutePath()};
+
+ // execute the JAR and read the result
+ String res = Support_Exec.execJava(args, null, false);
+
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+ }
+
+ /**
+ * tests Class-Path entry in manifest
+ *
+ * @throws Exception in case of troubles
+ */
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Functional test.",
+ method = "JarOutputStream",
+ args = {java.io.OutputStream.class, java.util.jar.Manifest.class}
+ )
+ @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
+ public void test_jar_class_path() throws Exception {
+ File fooJar = File.createTempFile("hyts_", ".jar");
+ File barJar = File.createTempFile("hyts_", ".jar");
+ fooJar.deleteOnExit();
+ barJar.deleteOnExit();
+
+ // create the manifest
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+ att.put(Attributes.Name.CLASS_PATH, barJar.getName());
+
+ File resources = Support_Resources.createTempFolder();
+
+ JarOutputStream joutFoo = new JarOutputStream(new FileOutputStream(
+ fooJar), man);
+ joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
+ joutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ joutFoo.close();
+
+ JarOutputStream joutBar = new JarOutputStream(new FileOutputStream(
+ barJar));
+ joutBar.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
+ joutBar.write(getResource(resources, "hyts_Bar.ser"));
+ joutBar.close();
+
+ String[] args = new String[] {"-jar", fooJar.getAbsolutePath()};
+
+ // execute the JAR and read the result
+ String res = Support_Exec.execJava(args, null, false);
+
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+
+ // rewrite manifest so it contains not only reference to bar but useless
+ // entries as well
+ att.put(Attributes.Name.CLASS_PATH, "xx yy zz " + barJar.getName());
+ joutFoo = new JarOutputStream(new FileOutputStream(fooJar), man);
+ joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
+ joutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ joutFoo.close();
+ // execute the JAR and read the result
+ res = Support_Exec.execJava(args, null, false);
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+
+
+ // play with relative file names - put relative path as ../<parent dir
+ // name>/xx.jar
+ att.put(Attributes.Name.CLASS_PATH, ".." + File.separator
+ + barJar.getParentFile().getName() + File.separator
+ + barJar.getName());
+ joutFoo = new JarOutputStream(new FileOutputStream(fooJar), man);
+ joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
+ joutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ joutFoo.close();
+ // execute the JAR and read the result
+ res = Support_Exec.execJava(args, null, false);
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+ }
+
+ /**
+ * tests case when Main-Class is not in the jar launched but in another jar
+ * referenced by Class-Path
+ *
+ * @throws Exception in case of troubles
+ */
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Functional test.",
+ method = "JarOutputStream",
+ args = {java.io.OutputStream.class, java.util.jar.Manifest.class}
+ )
+ @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
+ public void test_main_class_in_another_jar() throws Exception {
+ File fooJar = File.createTempFile("hyts_", ".jar");
+ File barJar = File.createTempFile("hyts_", ".jar");
+ fooJar.deleteOnExit();
+ barJar.deleteOnExit();
+
+ // create the manifest
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+ att.put(Attributes.Name.CLASS_PATH, fooJar.getName());
+
+ File resources = Support_Resources.createTempFolder();
+
+ JarOutputStream joutFoo = new JarOutputStream(new FileOutputStream(
+ fooJar));
+ joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
+ joutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ joutFoo.close();
+
+ JarOutputStream joutBar = new JarOutputStream(new FileOutputStream(
+ barJar), man);
+ joutBar.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
+ joutBar.write(getResource(resources, "hyts_Bar.ser"));
+ joutBar.close();
+
+ String[] args = new String[] {"-jar", barJar.getAbsolutePath()};
+
+ // execute the JAR and read the result
+ String res = Support_Exec.execJava(args, null, false);
+
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Functional test.",
+ method = "JarOutputStream",
+ args = {java.io.OutputStream.class, java.util.jar.Manifest.class}
+ )
+ @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
+ public void test_classpath() throws Exception {
+ File resources = Support_Resources.createTempFolder();
+
+ File fooJar = File.createTempFile("hyts_", ".jar");
+ fooJar.deleteOnExit();
+
+ JarOutputStream joutFoo = new JarOutputStream(new FileOutputStream(
+ fooJar));
+ joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
+ joutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
+ joutFoo.write(getResource(resources, "hyts_Bar.ser"));
+ joutFoo.close();
+
+ String[] args = new String[] {"foo.bar.execjartest.Foo"};
+
+ // execute the JAR and read the result
+ String res = Support_Exec.execJava(args, null,
+ new String[] {"CLASSPATH=" + fooJar.getAbsolutePath()}, false);
+
+ assertTrue(
+ "Error executing class from ClassPath : result returned was incorrect.",
+ res.startsWith("FOOBAR"));
+
+ // ok - next try - add -cp to path - it should override env
+ File booJar = File.createTempFile("hyts_", ".jar");
+ booJar.deleteOnExit();
+
+ JarOutputStream joutBoo = new JarOutputStream(new FileOutputStream(
+ booJar));
+ joutBoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
+ String booBody = new String(getResource(resources, "hyts_Foo.ser"),
+ "iso-8859-1");
+ booBody = booBody.replaceFirst("FOO", "BOO");
+ joutBoo.write(booBody.getBytes("iso-8859-1"));
+ joutBoo.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
+ String farBody = new String(getResource(resources, "hyts_Bar.ser"),
+ "iso-8859-1");
+ farBody = farBody.replaceFirst("BAR", "FAR");
+ joutBoo.write(farBody.getBytes("iso-8859-1"));
+ joutBoo.close();
+
+ res = Support_Exec.execJava(args, new String[] {booJar
+ .getAbsolutePath()}, new String[] {"CLASSPATH="
+ + fooJar.getAbsolutePath()}, false);
+
+ assertTrue(
+ "Error executing class specified by -cp : result returned was incorrect.",
+ res.startsWith("BOOFAR"));
+
+ // now add -jar option - it should override env and classpath
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+
+ File zooJar = File.createTempFile("hyts_", ".jar");
+ zooJar.deleteOnExit();
+
+ JarOutputStream joutZoo = new JarOutputStream(new FileOutputStream(
+ zooJar), man);
+ joutZoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
+ String zooBody = new String(getResource(resources, "hyts_Foo.ser"),
+ "iso-8859-1");
+ zooBody = zooBody.replaceFirst("FOO", "ZOO");
+ joutZoo.write(zooBody.getBytes("iso-8859-1"));
+ joutZoo.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
+ String zarBody = new String(getResource(resources, "hyts_Bar.ser"),
+ "iso-8859-1");
+ zarBody = zarBody.replaceFirst("BAR", "ZAR");
+ joutZoo.write(zarBody.getBytes("iso-8859-1"));
+ joutZoo.close();
+
+ args = new String[] {"-jar", zooJar.getAbsolutePath()};
+
+ res = Support_Exec.execJava(args, new String[] {booJar
+ .getAbsolutePath()}, new String[] {"CLASSPATH="
+ + fooJar.getAbsolutePath()}, false);
+
+ assertTrue(
+ "Error executing class specified by -cp : result returned was incorrect.",
+ res.startsWith("ZOOZAR"));
+ }
+
+ private static byte[] getResource(File tempDir, String resourceName)
+ throws IOException {
+ Support_Resources.copyFile(tempDir, null, resourceName);
+ File resourceFile = new File(tempDir, resourceName);
+ resourceFile.deleteOnExit();
+
+ // read whole resource data into memory
+ byte[] resourceBody = new byte[(int) resourceFile.length()];
+ FileInputStream fis = new FileInputStream(resourceFile);
+ fis.read(resourceBody);
+ fis.close();
+
+ return resourceBody;
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
new file mode 100644
index 0000000..497b897
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
@@ -0,0 +1,929 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+
+import dalvik.annotation.AndroidOnly;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.Permission;
+import java.security.cert.Certificate;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+import junit.framework.TestCase;
+import tests.support.Support_PlatformFile;
+import tests.support.resource.Support_Resources;
+
+
+@TestTargetClass(JarFile.class)
+public class JarFileTest extends TestCase {
+
+ // BEGIN android-added
+ public byte[] getAllBytesFromStream(InputStream is) throws IOException {
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ byte[] buf = new byte[666];
+ int iRead;
+ int off;
+ while (is.available() > 0) {
+ iRead = is.read(buf, 0, buf.length);
+ if (iRead > 0) bs.write(buf, 0, iRead);
+ }
+ return bs.toByteArray();
+ }
+
+ // END android-added
+
+ private final String jarName = "hyts_patch.jar"; // a 'normal' jar file
+
+ private final String jarName2 = "hyts_patch2.jar";
+
+ private final String jarName3 = "hyts_manifest1.jar";
+
+ private final String jarName4 = "hyts_signed.jar";
+
+ private final String jarName5 = "hyts_signed_inc.jar";
+
+ private final String entryName = "foo/bar/A.class";
+
+ private final String entryName3 = "coucou/FileAccess.class";
+
+ private File resources;
+
+ // custom security manager
+ SecurityManager sm = new SecurityManager() {
+ final String forbidenPermissionName = "user.dir";
+
+ public void checkPermission(Permission perm) {
+ if (perm.getName().equals(forbidenPermissionName)) {
+ throw new SecurityException();
+ }
+ }
+ };
+
+ @Override
+ protected void setUp() {
+ resources = Support_Resources.createTempFolder();
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#JarFile(java.io.File)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarFile",
+ args = {java.io.File.class}
+ )
+ public void test_ConstructorLjava_io_File() {
+ try {
+ JarFile jarFile = new JarFile(new File("Wrong.file"));
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ SecurityManager oldSm = System.getSecurityManager();
+ System.setSecurityManager(sm);
+ try {
+ JarFile jarFile = new JarFile(new File("tmp.jar"));
+ fail("Should throw SecurityException");
+ } catch (IOException e) {
+ fail("Should throw SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ System.setSecurityManager(oldSm);
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ } catch (IOException e) {
+ fail("Should not throw IOException");
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#JarFile(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarFile",
+ args = {java.lang.String.class}
+ )
+ public void test_ConstructorLjava_lang_String() {
+ try {
+ JarFile jarFile = new JarFile("Wrong.file");
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ SecurityManager oldSm = System.getSecurityManager();
+ System.setSecurityManager(sm);
+ try {
+ JarFile jarFile = new JarFile("tmp.jar");
+ fail("Should throw SecurityException");
+ } catch (IOException e) {
+ fail("Should throw SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ System.setSecurityManager(oldSm);
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ String fileName = (new File(resources, jarName)).getCanonicalPath();
+ JarFile jarFile = new JarFile(fileName);
+ } catch (IOException e) {
+ fail("Should not throw IOException");
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#JarFile(java.lang.String, boolean)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarFile",
+ args = {java.lang.String.class, boolean.class}
+ )
+ public void test_ConstructorLjava_lang_StringZ() {
+ try {
+ JarFile jarFile = new JarFile("Wrong.file", false);
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ SecurityManager oldSm = System.getSecurityManager();
+ System.setSecurityManager(sm);
+ try {
+ JarFile jarFile = new JarFile("tmp.jar", true);
+ fail("Should throw SecurityException");
+ } catch (IOException e) {
+ fail("Should throw SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ System.setSecurityManager(oldSm);
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ String fileName = (new File(resources, jarName)).getCanonicalPath();
+ JarFile jarFile = new JarFile(fileName, true);
+ } catch (IOException e) {
+ fail("Should not throw IOException");
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#JarFile(java.io.File, boolean)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarFile",
+ args = {java.io.File.class, boolean.class}
+ )
+ public void test_ConstructorLjava_io_FileZ() {
+ try {
+ JarFile jarFile = new JarFile(new File("Wrong.file"), true);
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ SecurityManager oldSm = System.getSecurityManager();
+ System.setSecurityManager(sm);
+ try {
+ JarFile jarFile = new JarFile(new File("tmp.jar"), false);
+ fail("Should throw SecurityException");
+ } catch (IOException e) {
+ fail("Should throw SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ System.setSecurityManager(oldSm);
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName), false);
+ } catch (IOException e) {
+ fail("Should not throw IOException");
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#JarFile(java.io.File, boolean, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarFile",
+ args = {java.io.File.class, boolean.class, int.class}
+ )
+ public void test_ConstructorLjava_io_FileZI() {
+ try {
+ JarFile jarFile = new JarFile(new File("Wrong.file"), true,
+ ZipFile.OPEN_READ);
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ SecurityManager oldSm = System.getSecurityManager();
+ System.setSecurityManager(sm);
+ try {
+ JarFile jarFile = new JarFile(new File("tmp.jar"), false,
+ ZipFile.OPEN_READ);
+ fail("Should throw SecurityException");
+ } catch (IOException e) {
+ fail("Should throw SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ System.setSecurityManager(oldSm);
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName), false,
+ ZipFile.OPEN_READ);
+ } catch (IOException e) {
+ fail("Should not throw IOException");
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName), false,
+ ZipFile.OPEN_READ | ZipFile.OPEN_DELETE + 33);
+ fail("Should throw IllegalArgumentException");
+ } catch (IOException e) {
+ fail("Should not throw IOException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#entries()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "entries",
+ args = {}
+ )
+ public void test_entries() throws Exception {
+ /*
+ * Note only (and all of) the following should be contained in the file
+ * META-INF/ META-INF/MANIFEST.MF foo/ foo/bar/ foo/bar/A.class Blah.txt
+ */
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ Enumeration<JarEntry> e = jarFile.entries();
+ int i = 0;
+ while (e.hasMoreElements()) {
+ i++;
+ e.nextElement();
+ }
+ jarFile.close();
+ assertEquals(6, i);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "entries",
+ args = {}
+ )
+ public void test_entries2() throws Exception {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ Enumeration<JarEntry> enumeration = jarFile.entries();
+ jarFile.close();
+ boolean pass = false;
+ try {
+ enumeration.hasMoreElements();
+ } catch (IllegalStateException e) {
+ pass = true;
+ }
+ assertTrue("hasMoreElements did not detect closed jar file", pass);
+ Support_Resources.copyFile(resources, null, jarName);
+ jarFile = new JarFile(new File(resources, jarName));
+ enumeration = jarFile.entries();
+ jarFile.close();
+ pass = false;
+ try {
+ enumeration.nextElement();
+ } catch (IllegalStateException e) {
+ pass = true;
+ }
+ assertTrue("nextElement did not detect closed jar file", pass);
+ }
+
+ /**
+ * @throws IOException
+ * @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getEntry",
+ args = {java.lang.String.class}
+ )
+ public void test_getEntryLjava_lang_String() throws IOException {
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ assertEquals("Error in returned entry", 311, jarFile.getEntry(
+ entryName).getSize());
+ jarFile.close();
+ } catch (Exception e) {
+ fail("Exception during test: " + e.toString());
+ }
+
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ Enumeration<JarEntry> enumeration = jarFile.entries();
+ assertTrue(enumeration.hasMoreElements());
+ while (enumeration.hasMoreElements()) {
+ JarEntry je = enumeration.nextElement();
+ jarFile.getEntry(je.getName());
+ }
+
+ enumeration = jarFile.entries();
+ assertTrue(enumeration.hasMoreElements());
+ JarEntry je = enumeration.nextElement();
+ try {
+ jarFile.close();
+ jarFile.getEntry(je.getName());
+ // fail("IllegalStateException expected.");
+ } catch (IllegalStateException ee) { // Per documentation exception
+ // may be thrown.
+ // expected
+ }
+ }
+
+ /**
+ * @throws IOException
+ * @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getJarEntry",
+ args = {java.lang.String.class}
+ )
+ public void test_getJarEntryLjava_lang_String() throws IOException {
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ assertEquals("Error in returned entry", 311, jarFile.getJarEntry(
+ entryName).getSize());
+ jarFile.close();
+ } catch (Exception e) {
+ fail("Exception during test: " + e.toString());
+ }
+
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ Enumeration<JarEntry> enumeration = jarFile.entries();
+ assertTrue(enumeration.hasMoreElements());
+ while (enumeration.hasMoreElements()) {
+ JarEntry je = enumeration.nextElement();
+ jarFile.getJarEntry(je.getName());
+ }
+
+ enumeration = jarFile.entries();
+ assertTrue(enumeration.hasMoreElements());
+ JarEntry je = enumeration.nextElement();
+ try {
+ jarFile.close();
+ jarFile.getJarEntry(je.getName());
+ // fail("IllegalStateException expected.");
+ } catch (IllegalStateException ee) { // Per documentation exception
+ // may be thrown.
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#getManifest()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getManifest",
+ args = {}
+ )
+ public void test_getManifest() {
+ // Test for method java.util.jar.Manifest
+ // java.util.jar.JarFile.getManifest()
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ assertNotNull("Error--Manifest not returned", jarFile.getManifest());
+ jarFile.close();
+ } catch (Exception e) {
+ fail("Exception during 1st test: " + e.toString());
+ }
+ try {
+ Support_Resources.copyFile(resources, null, jarName2);
+ JarFile jarFile = new JarFile(new File(resources, jarName2));
+ assertNull("Error--should have returned null", jarFile
+ .getManifest());
+ jarFile.close();
+ } catch (Exception e) {
+ fail("Exception during 2nd test: " + e.toString());
+ }
+
+ try {
+ // jarName3 was created using the following test
+ Support_Resources.copyFile(resources, null, jarName3);
+ JarFile jarFile = new JarFile(new File(resources, jarName3));
+ assertNotNull("Should find manifest without verifying", jarFile
+ .getManifest());
+ jarFile.close();
+ } catch (Exception e) {
+ fail("Exception during 3rd test: " + e.toString());
+ }
+
+ try {
+ // this is used to create jarName3 used in the previous test
+ Manifest manifest = new Manifest();
+ Attributes attributes = manifest.getMainAttributes();
+ attributes.put(new Attributes.Name("Manifest-Version"), "1.0");
+ ByteArrayOutputStream manOut = new ByteArrayOutputStream();
+ manifest.write(manOut);
+ byte[] manBytes = manOut.toByteArray();
+ File file = new File(Support_PlatformFile.getNewPlatformFile(
+ "hyts_manifest1", ".jar"));
+ JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(
+ file.getAbsolutePath()));
+ ZipEntry entry = new ZipEntry("META-INF/");
+ entry.setSize(0);
+ jarOut.putNextEntry(entry);
+ entry = new ZipEntry(JarFile.MANIFEST_NAME);
+ entry.setSize(manBytes.length);
+ jarOut.putNextEntry(entry);
+ jarOut.write(manBytes);
+ entry = new ZipEntry("myfile");
+ entry.setSize(1);
+ jarOut.putNextEntry(entry);
+ jarOut.write(65);
+ jarOut.close();
+ JarFile jar = new JarFile(file.getAbsolutePath(), false);
+ assertNotNull("Should find manifest without verifying", jar
+ .getManifest());
+ jar.close();
+ file.delete();
+ } catch (IOException e) {
+ fail("IOException 3");
+ }
+ try {
+ Support_Resources.copyFile(resources, null, jarName2);
+ JarFile jF = new JarFile(new File(resources, jarName2));
+ jF.close();
+ jF.getManifest();
+ fail("FAILED: expected IllegalStateException");
+ } catch (IllegalStateException ise) {
+ // expected;
+ } catch (Exception e) {
+ fail("Exception during 4th test: " + e.toString());
+ }
+
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ JarFile jf;
+ try {
+ jf = new JarFile(new File(resources, "Broken_manifest.jar"));
+ jf.getManifest();
+ fail("IOException expected.");
+ } catch (IOException e) {
+ // expected.
+ }
+ }
+
+ /**
+ * @throws IOException
+ * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException {
+ File localFile = null;
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ localFile = new File(resources, jarName);
+ } catch (Exception e) {
+ fail("Failed to create local file: " + e);
+ }
+
+ byte[] b = new byte[1024];
+ try {
+ JarFile jf = new JarFile(localFile);
+ java.io.InputStream is = jf.getInputStream(jf.getEntry(entryName));
+ // BEGIN android-removed
+ // jf.close();
+ // END android-removed
+ assertTrue("Returned invalid stream", is.available() > 0);
+ int r = is.read(b, 0, 1024);
+ is.close();
+ StringBuffer sb = new StringBuffer(r);
+ for (int i = 0; i < r; i++) {
+ sb.append((char) (b[i] & 0xff));
+ }
+ String contents = sb.toString();
+ assertTrue("Incorrect stream read", contents.indexOf("bar") > 0);
+ // BEGIN android-added
+ jf.close();
+ // END android-added
+ } catch (Exception e) {
+ fail("Exception during test: " + e.toString());
+ }
+
+ try {
+ JarFile jf = new JarFile(localFile);
+ InputStream in = jf.getInputStream(new JarEntry("invalid"));
+ assertNull("Got stream for non-existent entry", in);
+ } catch (Exception e) {
+ fail("Exception during test 2: " + e);
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ File signedFile = new File(resources, jarName);
+ JarFile jf = new JarFile(signedFile);
+ JarEntry jre = new JarEntry("foo/bar/A.class");
+ jf.getInputStream(jre);
+ // InputStream returned in any way, exception can be thrown in case
+ // of reading from this stream only.
+ // fail("Should throw ZipException");
+ } catch (ZipException ee) {
+ // expected
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ File signedFile = new File(resources, jarName);
+ JarFile jf = new JarFile(signedFile);
+ JarEntry jre = new JarEntry("foo/bar/A.class");
+ jf.close();
+ jf.getInputStream(jre);
+ // InputStream returned in any way, exception can be thrown in case
+ // of reading from this stream only.
+ // The same for IOException
+ fail("Should throw IllegalStateException");
+ } catch (IllegalStateException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException and functionality checked.",
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ @AndroidOnly("This test doesn't pass on RI. If entry size is set up " +
+ "incorrectly, SecurityException is thrown. " +
+ "But SecurityException is thrown on RI only " +
+ "if jar file is signed incorreclty.")
+ public void test_getInputStreamLjava_util_jar_JarEntry_subtest0() {
+ File signedFile = null;
+ try {
+ Support_Resources.copyFile(resources, null, jarName4);
+ signedFile = new File(resources, jarName4);
+ } catch (Exception e) {
+ fail("Failed to create local file 2: " + e);
+ }
+
+ try {
+ JarFile jar = new JarFile(signedFile);
+ JarEntry entry = new JarEntry(entryName3);
+ InputStream in = jar.getInputStream(entry);
+ in.read();
+ } catch (Exception e) {
+ fail("Exception during test 3: " + e);
+ }
+
+ try {
+ JarFile jar = new JarFile(signedFile);
+ JarEntry entry = new JarEntry(entryName3);
+ InputStream in = jar.getInputStream(entry);
+ // BEGIN android-added
+ byte[] dummy = getAllBytesFromStream(in);
+ // END android-added
+ assertNull("found certificates", entry.getCertificates());
+ } catch (Exception e) {
+ fail("Exception during test 4: " + e);
+ }
+
+ try {
+ JarFile jar = new JarFile(signedFile);
+ JarEntry entry = new JarEntry(entryName3);
+ entry.setSize(1076);
+ InputStream in = jar.getInputStream(entry);
+ // BEGIN android-added
+ byte[] dummy = getAllBytesFromStream(in);
+ // END android-added
+ fail("SecurityException should be thrown.");
+ } catch (SecurityException e) {
+ // expected
+ } catch (Exception e) {
+ fail("Exception during test 5: " + e);
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName5);
+ signedFile = new File(resources, jarName5);
+ } catch (Exception e) {
+ fail("Failed to create local file 5: " + e);
+ }
+
+ try {
+ JarFile jar = new JarFile(signedFile);
+ JarEntry entry = new JarEntry(entryName3);
+ InputStream in = jar.getInputStream(entry);
+ fail("SecurityException should be thrown.");
+ } catch (SecurityException e) {
+ // expected
+ } catch (Exception e) {
+ fail("Exception during test 5: " + e);
+ }
+ }
+
+ /*
+ * The jar created by 1.4 which does not provide a
+ * algorithm-Digest-Manifest-Main-Attributes entry in .SF file.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "entries",
+ args = {}
+ )
+ public void test_Jar_created_before_java_5() throws IOException {
+ String modifiedJarName = "Created_by_1_4.jar";
+ Support_Resources.copyFile(resources, null, modifiedJarName);
+ JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
+ true);
+ Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry zipEntry = entries.nextElement();
+ jarFile.getInputStream(zipEntry);
+ }
+ }
+
+ /* The jar is intact, then everything is all right. */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "entries",
+ args = {}
+ )
+ public void test_JarFile_Integrate_Jar() throws IOException {
+ String modifiedJarName = "Integrate.jar";
+ Support_Resources.copyFile(resources, null, modifiedJarName);
+ JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
+ true);
+ Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry zipEntry = entries.nextElement();
+ jarFile.getInputStream(zipEntry);
+ }
+ }
+
+ /*
+ * If another entry is inserted into Manifest, no security exception will be
+ * thrown out.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "entries",
+ args = {}
+ )
+ public void test_JarFile_InsertEntry_in_Manifest_Jar() throws IOException {
+ String modifiedJarName = "Inserted_Entry_Manifest.jar";
+ Support_Resources.copyFile(resources, null, modifiedJarName);
+ JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
+ true);
+ Enumeration<JarEntry> entries = jarFile.entries();
+ int count = 0;
+ while (entries.hasMoreElements()) {
+
+ ZipEntry zipEntry = entries.nextElement();
+ jarFile.getInputStream(zipEntry);
+ count++;
+ }
+ assertEquals(5, count);
+ }
+
+ /*
+ * If another entry is inserted into Manifest, no security exception will be
+ * thrown out.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "entries",
+ args = {}
+ )
+ public void test_Inserted_Entry_Manifest_with_DigestCode()
+ throws IOException {
+ String modifiedJarName = "Inserted_Entry_Manifest_with_DigestCode.jar";
+ Support_Resources.copyFile(resources, null, modifiedJarName);
+ JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
+ true);
+ Enumeration<JarEntry> entries = jarFile.entries();
+ int count = 0;
+ while (entries.hasMoreElements()) {
+
+ ZipEntry zipEntry = entries.nextElement();
+ jarFile.getInputStream(zipEntry);
+ count++;
+ }
+ assertEquals(5, count);
+ }
+
+ /*
+ * The content of Test.class is modified, jarFile.getInputStream will not
+ * throw security Exception, but it will anytime before the inputStream got
+ * from getInputStream method has been read to end.
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException and functionality checked.",
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_JarFile_Modified_Class() throws IOException {
+ String modifiedJarName = "Modified_Class.jar";
+ Support_Resources.copyFile(resources, null, modifiedJarName);
+ JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
+ true);
+ Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry zipEntry = entries.nextElement();
+ jarFile.getInputStream(zipEntry);
+ }
+ /* The content of Test.class has been tampered. */
+ ZipEntry zipEntry = jarFile.getEntry("Test.class");
+ InputStream in = jarFile.getInputStream(zipEntry);
+ byte[] buffer = new byte[1024];
+ try {
+ while (in.available() > 0) {
+ in.read(buffer);
+ }
+ fail("should throw Security Exception");
+ } catch (SecurityException e) {
+ // desired
+ }
+ }
+
+ /*
+ * In the Modified.jar, the main attributes of META-INF/MANIFEST.MF is
+ * tampered manually. Hence the RI 5.0 JarFile.getInputStream of any
+ * JarEntry will throw security exception, but the apache harmony will not.
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException and functionality checked.",
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_JarFile_Modified_Manifest_MainAttributes()
+ throws IOException {
+ String modifiedJarName = "Modified_Manifest_MainAttributes.jar";
+ Support_Resources.copyFile(resources, null, modifiedJarName);
+ JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
+ true);
+ Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry zipEntry = entries.nextElement();
+ try {
+ jarFile.getInputStream(zipEntry);
+ fail("should throw Security Exception");
+ } catch (SecurityException e) {
+ // desired
+ }
+ }
+ }
+
+ /*
+ * It is all right in our original JarFile. If the Entry Attributes, for
+ * example Test.class in our jar, the jarFile.getInputStream will throw
+ * Security Exception.
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException and functionality checked.",
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_JarFile_Modified_Manifest_EntryAttributes()
+ throws IOException {
+ String modifiedJarName = "Modified_Manifest_EntryAttributes.jar";
+ Support_Resources.copyFile(resources, null, modifiedJarName);
+ JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
+ true);
+ Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry zipEntry = entries.nextElement();
+ try {
+ jarFile.getInputStream(zipEntry);
+ fail("should throw Security Exception");
+ } catch (SecurityException e) {
+ // desired
+ }
+ }
+ }
+
+ /*
+ * If the content of the .SA file is modified, no matter what it resides,
+ * JarFile.getInputStream of any JarEntry will throw Security Exception.
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException and functionality checked.",
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_JarFile_Modified_SF_EntryAttributes() throws IOException {
+ String modifiedJarName = "Modified_SF_EntryAttributes.jar";
+ Support_Resources.copyFile(resources, null, modifiedJarName);
+ JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
+ true);
+ Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry zipEntry = entries.nextElement();
+ try {
+ jarFile.getInputStream(zipEntry);
+ fail("should throw Security Exception");
+ } catch (SecurityException e) {
+ // desired
+ }
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "close",
+ args = {}
+ )
+ public void test_close() throws IOException {
+ String modifiedJarName = "Modified_SF_EntryAttributes.jar";
+ Support_Resources.copyFile(resources, null, modifiedJarName);
+ JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
+ true);
+ Enumeration<JarEntry> entries = jarFile.entries();
+
+ jarFile.close();
+ jarFile.close();
+
+ // Can not check IOException
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarInputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarInputStreamTest.java
new file mode 100644
index 0000000..1a8c753
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarInputStreamTest.java
@@ -0,0 +1,653 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import tests.support.resource.Support_Resources;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+
+@TestTargetClass(JarInputStream.class)
+public class JarInputStreamTest extends junit.framework.TestCase {
+ // a 'normal' jar file
+ private String jarName;
+
+ // same as patch.jar but without a manifest file
+ private String jarName2;
+
+ private final String entryName = "foo/bar/A.class";
+
+ private static final int indexofDSA = 2;
+
+ private static final int indexofTESTCLASS = 4;
+
+ private static final int totalEntries = 4;
+
+ @Override
+ protected void setUp() {
+ jarName = Support_Resources.getURL("morestuff/hyts_patch.jar");
+ jarName2 = Support_Resources.getURL("morestuff/hyts_patch2.jar");
+ }
+
+ /**
+ * @tests java.util.jar.JarInputStream#JarInputStream(java.io.InputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarInputStream",
+ args = {java.io.InputStream.class}
+ )
+ public void test_ConstructorLjava_io_InputStream() {
+ // Test for method java.util.jar.JarInputStream(java.io.InputStream)
+ InputStream is = null;
+ JarInputStream jis = null;
+ try {
+ is = new URL(jarName).openConnection().getInputStream();
+ boolean hasCorrectEntry = false;
+ jis = new JarInputStream(is);
+ assertNotNull("The jar input stream should have a manifest", jis
+ .getManifest());
+ JarEntry je = jis.getNextJarEntry();
+ while (je != null) {
+ if (je.getName().equals(entryName)) {
+ hasCorrectEntry = true;
+ }
+ je = jis.getNextJarEntry();
+ }
+ assertTrue(
+ "The jar input stream does not contain the correct entries",
+ hasCorrectEntry);
+ } catch (Exception e) {
+ fail("Exception during test: " + e.toString());
+ }
+
+ try {
+ is.close();
+ jis = new JarInputStream(is);
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarInputStream#getManifest()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getManifest",
+ args = {}
+ )
+ public void test_getManifest() {
+ // Test for method java.util.jar.Manifest
+ // java.util.jar.JarInputStream.getManifest()
+ try {
+ Manifest m;
+
+ InputStream is = new URL(jarName2).openConnection()
+ .getInputStream();
+ JarInputStream jis = new JarInputStream(is);
+ m = jis.getManifest();
+ assertNull("The jar input stream should not have a manifest", m);
+
+ is = new URL(jarName).openConnection().getInputStream();
+ jis = new JarInputStream(is);
+ m = jis.getManifest();
+ assertNotNull("The jar input stream should have a manifest", m);
+ } catch (Exception e) {
+ fail("Exception during test: " + e.toString());
+ }
+
+ }
+
+ /**
+ * @tests java.util.jar.JarInputStream#getNextJarEntry()
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "getNextJarEntry",
+ args = {}
+ )
+ public void test_getNextJarEntry() throws Exception {
+ final Set<String> desired = new HashSet<String>(Arrays
+ .asList(new String[] {
+ "foo/", "foo/bar/", "foo/bar/A.class", "Blah.txt"}));
+ Set<String> actual = new HashSet<String>();
+ InputStream is = new URL(jarName).openConnection().getInputStream();
+ JarInputStream jis = new JarInputStream(is);
+ JarEntry je = jis.getNextJarEntry();
+ while (je != null) {
+ actual.add(je.toString());
+ je = jis.getNextJarEntry();
+ }
+ assertEquals(actual, desired);
+ jis.close();
+
+// try {
+// jis.getNextJarEntry(); //Android implementation does not throw exception
+// fail("IOException expected");
+// } catch (IOException ee) {
+// // expected
+// }
+
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_entry.jar");
+ is = Support_Resources.getStream("Broken_entry.jar");
+ jis = new JarInputStream(is, false);
+ jis.getNextJarEntry();
+ try {
+ jis.getNextJarEntry();
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "getNextJarEntry",
+ args = {}
+ )
+ @KnownFailure("IOException not thrown when using getNextJarEntry() after close().")
+ // This is the original test_getNextJarEntry including the failing section.
+ public void test_getNextJarEntry_Ex() throws Exception {
+ final Set<String> desired = new HashSet<String>(Arrays
+ .asList(new String[] {
+ "foo/", "foo/bar/", "foo/bar/A.class", "Blah.txt"}));
+ Set<String> actual = new HashSet<String>();
+ InputStream is = new URL(jarName).openConnection().getInputStream();
+ JarInputStream jis = new JarInputStream(is);
+ JarEntry je = jis.getNextJarEntry();
+ while (je != null) {
+ actual.add(je.toString());
+ je = jis.getNextJarEntry();
+ }
+ assertEquals(actual, desired);
+ jis.close();
+
+ try {
+ jis.getNextJarEntry(); //Android implementation does not throw exception
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_entry.jar");
+ is = Support_Resources.getStream("Broken_entry.jar");
+ jis = new JarInputStream(is, false);
+ jis.getNextJarEntry();
+ try {
+ jis.getNextJarEntry();
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "Exceptions checking missed. Case2",
+ method = "getNextJarEntry",
+ args = {}
+ )
+ public void test_JarInputStream_Integrate_Jar_getNextEntry()
+ throws IOException {
+ String intJarName = Support_Resources.getURL("Integrate.jar");
+ InputStream is = new URL(intJarName).openConnection().getInputStream();
+ JarInputStream jin = new JarInputStream(is, true);
+ ZipEntry entry = null;
+ int count = 0;
+ while (count == 0 || entry != null) {
+ count++;
+ entry = jin.getNextEntry();
+ }
+ assertEquals(totalEntries + 1, count);
+ jin.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException & ZipException checking missed.",
+ method = "getNextEntry",
+ args = {}
+ )
+ public void test_JarInputStream_Modified_Class_getNextEntry()
+ throws IOException {
+ String modJarName = Support_Resources.getURL("Modified_Class.jar");
+ InputStream is = new URL(modJarName).openConnection().getInputStream();
+ JarInputStream jin = new JarInputStream(is, true);
+ ZipEntry zipEntry = null;
+
+ int count = 0;
+ while (count == 0 || zipEntry != null) {
+ count++;
+ try {
+ zipEntry = jin.getNextEntry();
+ if (count == indexofTESTCLASS + 1) {
+ fail("Should throw Security Exception");
+ }
+ } catch (SecurityException e) {
+ if (count != indexofTESTCLASS + 1) {
+ throw e;
+ }
+
+ }
+ }
+ assertEquals(totalEntries + 2, count);
+ jin.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException & ZipException checking missed.",
+ method = "getNextEntry",
+ args = {}
+ )
+ public void test_JarInputStream_Modified_Manifest_MainAttributes_getNextEntry()
+ throws IOException {
+ String modJarName = Support_Resources
+ .getURL("Modified_Manifest_MainAttributes.jar");
+ InputStream is = new URL(modJarName).openConnection().getInputStream();
+ JarInputStream jin = new JarInputStream(is, true);
+ ZipEntry zipEntry = null;
+
+ final int indexofDSA = 2;
+ final int totalEntries = 4;
+ int count = 0;
+ while (count == 0 || zipEntry != null) {
+ count++;
+ try {
+ zipEntry = jin.getNextEntry();
+ if (count == indexofDSA + 1) {
+ fail("Should throw Security Exception");
+ }
+ } catch (SecurityException e) {
+ if (count != indexofDSA + 1) {
+ throw e;
+ }
+ }
+ }
+ assertEquals(totalEntries + 2, count);
+ jin.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException & ZipException checking missed.",
+ method = "getNextEntry",
+ args = {}
+ )
+ public void test_JarInputStream_Modified_Manifest_EntryAttributes_getNextEntry()
+ throws IOException {
+ String modJarName = Support_Resources
+ .getURL("Modified_Manifest_EntryAttributes.jar");
+ InputStream is = new URL(modJarName).openConnection().getInputStream();
+ JarInputStream jin = new JarInputStream(is, true);
+ ZipEntry zipEntry = null;
+
+ int count = 0;
+ while (count == 0 || zipEntry != null) {
+ count++;
+ try {
+ zipEntry = jin.getNextEntry();
+ if (count == indexofDSA + 1) {
+ fail("Should throw Security Exception");
+ }
+ } catch (SecurityException e) {
+ if (count != indexofDSA + 1) {
+ throw e;
+ }
+ }
+ }
+ assertEquals(totalEntries + 2, count);
+ jin.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException & ZipException checking missed.",
+ method = "getNextEntry",
+ args = {}
+ )
+ public void test_JarInputStream_Modified_SF_EntryAttributes_getNextEntry()
+ throws IOException {
+ String modJarName = Support_Resources
+ .getURL("Modified_SF_EntryAttributes.jar");
+ InputStream is = new URL(modJarName).openConnection().getInputStream();
+ JarInputStream jin = new JarInputStream(is, true);
+ ZipEntry zipEntry = null;
+
+ int count = 0;
+ while (count == 0 || zipEntry != null) {
+ count++;
+ try {
+ zipEntry = jin.getNextEntry();
+ if (count == indexofDSA + 1) {
+ fail("Should throw Security Exception");
+ }
+ } catch (SecurityException e) {
+ if (count != indexofDSA + 1) {
+ throw e;
+ }
+ }
+ }
+ assertEquals(totalEntries + 2, count);
+ jin.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException & ZipException checking missed.",
+ method = "read",
+ args = {byte[].class}
+ )
+ public void test_JarInputStream_Modified_Class_read() throws IOException {
+ String modJarName = Support_Resources.getURL("Modified_Class.jar");
+ InputStream is = new URL(modJarName).openConnection().getInputStream();
+ JarInputStream jin = new JarInputStream(is, true);
+ int count = 0;
+ ZipEntry zipEntry = null;
+ while (count == 0 || zipEntry != null) {
+ count++;
+ zipEntry = jin.getNextEntry();
+ byte[] buffer = new byte[1024];
+ try {
+ int length = 0;
+ while (length >= 0) {
+ length = jin.read(buffer);
+ }
+ if (count == indexofTESTCLASS) {
+ fail("Should throw Security Exception");
+ }
+ } catch (SecurityException e) {
+ if (count < indexofTESTCLASS) {
+ throw e;
+ }
+ }
+ }
+ assertEquals(totalEntries + 1, count);
+ jin.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Exception checking missed.",
+ method = "read",
+ args = {byte[].class}
+ )
+ public void test_Integrate_Jar_read() throws IOException {
+ String intJarName = Support_Resources.getURL("Integrate.jar");
+ InputStream is = new URL(intJarName).openConnection().getInputStream();
+ JarInputStream jin = new JarInputStream(is, true);
+ int count = 0;
+ ZipEntry zipEntry = null;
+ while (count == 0 || zipEntry != null) {
+ count++;
+ zipEntry = jin.getNextEntry();
+ byte[] buffer = new byte[1024];
+ int length = 0;
+ while (length >= 0) {
+ length = jin.read(buffer);
+ }
+
+ }
+ assertEquals(totalEntries + 1, count);
+ jin.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException & ZipException checking missed.",
+ method = "read",
+ args = {byte[].class}
+ )
+ public void test_JarInputStream_Modified_Manifest_MainAttributes_read()
+ throws IOException {
+ String modJarName = Support_Resources
+ .getURL("Modified_Manifest_MainAttributes.jar");
+ InputStream is = new URL(modJarName).openConnection().getInputStream();
+ JarInputStream jin = new JarInputStream(is, true);
+ int count = 0;
+ ZipEntry zipEntry = null;
+ while (count == 0 || zipEntry != null) {
+ count++;
+ zipEntry = jin.getNextEntry();
+ byte[] buffer = new byte[1024];
+ try {
+ int length = 0;
+ while (length >= 0) {
+ length = jin.read(buffer);
+ }
+ if (count == indexofDSA) {
+ fail("Should throw Security Exception");
+ }
+ } catch (SecurityException e) {
+ if (count != indexofDSA) {
+ throw e;
+ }
+ }
+ }
+ assertEquals(totalEntries + 1, count);
+ jin.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException & ZipException checking missed.",
+ method = "read",
+ args = {byte[].class}
+ )
+ public void test_JarInputStream_Modified_SF_EntryAttributes_read()
+ throws IOException {
+ String modJarName = Support_Resources
+ .getURL("Modified_SF_EntryAttributes.jar");
+ InputStream is = new URL(modJarName).openConnection().getInputStream();
+ JarInputStream jin = new JarInputStream(is, true);
+ int count = 0;
+ ZipEntry zipEntry = null;
+ while (count == 0 || zipEntry != null) {
+ count++;
+ zipEntry = jin.getNextEntry();
+ byte[] buffer = new byte[1024];
+ try {
+ int length = 0;
+ while (length >= 0) {
+ length = jin.read(buffer);
+ }
+ if (count == indexofDSA) {
+ fail("Should throw Security Exception");
+ }
+ } catch (SecurityException e) {
+ if (count != indexofDSA) {
+ throw e;
+ }
+ }
+ }
+ assertEquals(totalEntries + 1, count);
+ jin.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "JarInputStream",
+ args = {java.io.InputStream.class, boolean.class}
+ )
+ public void test_ConstructorLjava_io_InputStreamZ() {
+ // Test for method java.util.jar.JarInputStream(java.io.InputStream)
+ InputStream is = null;
+ JarInputStream jis = null;
+ try {
+ is = new URL(jarName).openConnection().getInputStream();
+ boolean hasCorrectEntry = false;
+ jis = new JarInputStream(is, true);
+ assertNotNull("The jar input stream should have a manifest", jis
+ .getManifest());
+ JarEntry je = jis.getNextJarEntry();
+ while (je != null) {
+ if (je.getName().equals(entryName)) {
+ hasCorrectEntry = true;
+ }
+ je = jis.getNextJarEntry();
+ }
+ assertTrue(
+ "The jar input stream does not contain the correct entries",
+ hasCorrectEntry);
+ } catch (Exception e) {
+ fail("Exception during test: " + e.toString());
+ }
+
+ try {
+ is.close();
+ jis = new JarInputStream(is, false);
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "close",
+ args = {}
+ )
+ @KnownFailure("The behaviour is different from RI, but not neccessarily wrong. However a strange exception message is given anyway!")
+ public void test_closeAfterException() throws Exception {
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_entry.jar");
+ InputStream is = Support_Resources.getStream("Broken_entry.jar");
+ JarInputStream jis = new JarInputStream(is, false);
+ jis.getNextEntry();
+ try {
+ jis.getNextEntry();
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+ jis.close(); // Android throws exception here, but RI throws when getNextEntry/read/skip are called.
+ try {
+ jis.getNextEntry();
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getNextEntry",
+ args = {}
+ )
+ public void test_getNextEntry() throws Exception {
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_entry.jar");
+ InputStream is = Support_Resources.getStream("Broken_entry.jar");
+ JarInputStream jis = new JarInputStream(is, false);
+ jis.getNextEntry();
+ try {
+ jis.getNextEntry();
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+
+ try {
+ jis.close(); // Android throws exception here, already!
+ jis.getNextEntry(); // But RI here, only!
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ class Mock_JarInputStream extends JarInputStream {
+
+ public Mock_JarInputStream(InputStream in) throws IOException {
+ super(in);
+ }
+
+ public ZipEntry createZipEntry(String str) {
+ return super.createZipEntry(str);
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "createZipEntry",
+ args = {java.lang.String.class}
+ )
+ public void test_createZipEntryLjava_lang_String() throws Exception {
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_entry.jar");
+ InputStream is = Support_Resources.getStream("Broken_entry.jar");
+ Mock_JarInputStream mjis = new Mock_JarInputStream(is);
+ assertNotNull(mjis.createZipEntry("New entry"));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "read",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_read$ZII() throws Exception {
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_entry_data.jar");
+ InputStream is = Support_Resources.getStream("Broken_entry_data.jar");
+ JarInputStream jis = new JarInputStream(is, true);
+ byte b[] = new byte[100];
+
+ jis.getNextEntry();
+ jis.read(b, 0, 100);
+ jis.getNextEntry();
+ jis.getNextEntry();
+ jis.getNextEntry();
+
+ try {
+ jis.read(b, 0, 100);
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+
+ try {
+ jis.close(); // Android throws exception here, already!
+ jis.read(b, 0, 100); // But RI here, only!
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java
new file mode 100644
index 0000000..e652137
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import tests.support.Support_Exec;
+import tests.support.resource.Support_Resources;
+
+@TestTargetClass(JarOutputStream.class)
+public class JarOutputStreamTest extends junit.framework.TestCase {
+
+ /**
+ * @tests java.util.jar.JarOutputStream#putNextEntry(java.util.zip.ZipEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "putNextEntry",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_putNextEntryLjava_util_zip_ZipEntry() {
+ // testClass file`s actual extension is .class, since having .class
+ // extension files in source dir causes
+ // problems on eclipse, the extension is changed into .ser or it can be
+ // anything. The file is being
+ // read by inputstream and being written to other file,
+ // as long as the content of the file is not changed, the extension does
+ // not matter
+ final String testClass = "hyts_mainClass.ser";
+ final String entryName = "foo/bar/execjartest/MainClass.class";
+
+ // test whether specifying the main class in the manifest
+ // works using either /'s or .'s as a separator
+ final String[] manifestMain = {
+ "foo.bar.execjartest.MainClass",
+ "foo/bar/execjartest/MainClass"};
+
+ for (String element : manifestMain) {
+
+ // create the manifest
+ Manifest newman = new Manifest();
+ Attributes att = newman.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, element);
+
+ File outputJar = null;
+ JarOutputStream jout = null;
+
+ try {
+ // open the output jarfile
+ outputJar = File.createTempFile("hyts_", ".jar");
+ jout = new JarOutputStream(new FileOutputStream(outputJar),
+ newman);
+ jout.putNextEntry(new JarEntry(entryName));
+ } catch (Exception e) {
+ fail("Error creating JarOutputStream: " + e);
+ }
+ File resources = Support_Resources.createTempFolder();
+ try {
+ // read in the class file, and output it to the jar
+ Support_Resources.copyFile(resources, null, testClass);
+ URL jarURL = new URL((new File(resources, testClass)).toURL()
+ .toString());
+ InputStream jis = jarURL.openStream();
+
+ byte[] bytes = new byte[1024];
+ int len;
+ while ((len = jis.read(bytes)) != -1) {
+ jout.write(bytes, 0, len);
+ }
+
+ jout.flush();
+ jout.close();
+ jis.close();
+ } catch (Exception e) {
+ fail("Error writing JAR file for testing: " + e);
+ }
+ String res = null;
+ // set up the VM parameters
+ String[] args = new String[2];
+ args[0] = "-jar";
+ args[1] = outputJar.getAbsolutePath();
+
+// It's not that simple to execute a JAR against Dalvik VM (see DalvikExecTest):
+//
+// try {
+// // execute the JAR and read the result
+// res = Support_Exec.execJava(args, null, true);
+// } catch (Exception e) {
+// fail("Exception executing test JAR: " + e);
+// }
+//
+// assertTrue("Error executing JAR test on: " + element
+// + ". Result returned was incorrect.", res
+// .startsWith("TEST"));
+ outputJar.delete();
+
+ try {
+ // open the output jarfile
+ outputJar = File.createTempFile("hyts_", ".jar");
+ OutputStream os = new FileOutputStream(outputJar);
+ jout = new JarOutputStream(os, newman);
+ os.close();
+ jout.putNextEntry(new JarEntry(entryName));
+ fail("IOException expected");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "Checks IOException",
+ method = "JarOutputStream",
+ args = {java.io.OutputStream.class, java.util.jar.Manifest.class}
+ )
+ public void test_JarOutputStreamLjava_io_OutputStreamLjava_util_jar_Manifest()
+ throws IOException {
+ File fooJar = File.createTempFile("hyts_", ".jar");
+ File barZip = File.createTempFile("hyts_", ".zip");
+
+ FileOutputStream fos = new FileOutputStream(fooJar);
+
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+ att.put(Attributes.Name.CLASS_PATH, barZip.getName());
+
+ fos.close();
+ try {
+ JarOutputStream joutFoo = new JarOutputStream(fos, man);
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Can not check IOException",
+ method = "JarOutputStream",
+ args = {java.io.OutputStream.class}
+ )
+ public void test_JarOutputStreamLjava_io_OutputStream() throws IOException {
+ File fooJar = File.createTempFile("hyts_", ".jar");
+
+ FileOutputStream fos = new FileOutputStream(fooJar);
+ ZipEntry ze = new ZipEntry("Test");
+
+ try {
+ JarOutputStream joutFoo = new JarOutputStream(fos);
+ joutFoo.putNextEntry(ze);
+ joutFoo.write(33);
+ } catch (IOException ee) {
+ fail("IOException is not expected");
+ }
+
+ fos.close();
+ fooJar.delete();
+ try {
+ JarOutputStream joutFoo = new JarOutputStream(fos);
+ joutFoo.putNextEntry(ze);
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ @Override
+ protected void setUp() {
+ }
+
+ @Override
+ protected void tearDown() {
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java
new file mode 100644
index 0000000..57e4744
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java
@@ -0,0 +1,513 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import junit.framework.TestCase;
+import tests.support.resource.Support_Resources;
+
+@TestTargetClass(Manifest.class)
+public class ManifestTest extends TestCase {
+
+ private final String jarName = "hyts_patch.jar";
+
+ private final String attJarName = "hyts_att.jar";
+
+ private Manifest m;
+
+ private Manifest m2;
+
+ private File resources;
+
+ @Override
+ protected void setUp() {
+ resources = Support_Resources.createTempFolder();
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ m = jarFile.getManifest();
+ jarFile.close();
+ Support_Resources.copyFile(resources, null, attJarName);
+ jarFile = new JarFile(new File(resources, attJarName));
+ m2 = jarFile.getManifest();
+ jarFile.close();
+ } catch (Exception e) {
+ fail("Exception during setup: " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#Manifest()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Manifest",
+ args = {}
+ )
+ public void test_Constructor() {
+ // Test for method java.util.jar.Manifest()
+ Manifest emptyManifest = new Manifest();
+ assertTrue("Should have no entries", emptyManifest.getEntries()
+ .isEmpty());
+ assertTrue("Should have no main attributes", emptyManifest
+ .getMainAttributes().isEmpty());
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#Manifest(java.io.InputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "IOException checking missed.",
+ method = "Manifest",
+ args = {java.io.InputStream.class}
+ )
+ public void test_ConstructorLjava_io_InputStream() {
+ // Test for method java.util.jar.Manifest(java.io.InputStream)
+ /*
+ * ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ * m2.write(baos); InputSteam is = new ByteArrayInputStream
+ * (baos.toByteArray()); Manifest myManifest = new Manifest (is);
+ * assertTrue("Manifests should be equal", myManifest.equals(m2));
+ */
+
+ Manifest manifest = null;
+ InputStream is = null;
+ try {
+ is = new URL(Support_Resources.getURL("manifest/hyts_MANIFEST.MF"))
+ .openStream();
+ } catch (MalformedURLException e1) {
+ fail("Failed to create InputStream object");
+ } catch (IOException e1) {
+ fail("Failed to create InputStream object");
+ }
+ try {
+ manifest = new Manifest(is);
+ } catch (MalformedURLException e) {
+ fail("Malformed URL");
+ } catch (IOException e) {
+ fail("IOException");
+ }
+ Attributes main = manifest.getMainAttributes();
+ assertEquals("Bundle-Name not correct", "ClientSupport", main
+ .getValue("Bundle-Name"));
+ assertEquals(
+ "Bundle-Description not correct",
+
+ "Provides SessionService, AuthenticationService. Extends RegistryService.",
+ main.getValue("Bundle-Description"));
+ assertEquals("Bundle-Activator not correct",
+ "com.ibm.ive.eccomm.client.support.ClientSupportActivator",
+ main.getValue("Bundle-Activator"));
+ assertEquals(
+ "Import-Package not correct",
+
+ "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client",
+ main.getValue("Import-Package"));
+ assertEquals(
+ "Import-Service not correct",
+
+ "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService",
+ main.getValue("Import-Service"));
+ assertEquals(
+ "Export-Package not correct",
+
+ "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0",
+ main.getValue("Export-Package"));
+ assertEquals(
+ "Export-Service not correct",
+
+ "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService",
+ main.getValue("Export-Service"));
+ assertEquals("Bundle-Vendor not correct", "IBM", main
+ .getValue("Bundle-Vendor"));
+ assertEquals("Bundle-Version not correct", "1.2.0", main
+ .getValue("Bundle-Version"));
+ try {
+ is.close();
+ } catch (IOException e1) {
+ fail("Failed to close InputStream object");
+ }
+ try {
+ manifest = new Manifest(is);
+ fail("IOException expected");
+ } catch (MalformedURLException e) {
+ fail("IOException expected");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#clear()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clear",
+ args = {}
+ )
+ public void test_clear() {
+ // Test for method void java.util.jar.Manifest.clear()
+ m2.clear();
+ assertTrue("Should have no entries", m2.getEntries().isEmpty());
+ assertTrue("Should have no main attributes", m2.getMainAttributes()
+ .isEmpty());
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#getAttributes(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getAttributes",
+ args = {java.lang.String.class}
+ )
+ public void test_getAttributesLjava_lang_String() {
+ // Test for method java.util.jar.Attributes
+ // java.util.jar.Manifest.getAttributes(java.lang.String)
+ assertNull("Should not exist", m2.getAttributes("Doesn't Exist"));
+ assertEquals("Should exist", "OK", m2
+ .getAttributes("HasAttributes.txt").get(
+ new Attributes.Name("MyAttribute")));
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#getEntries()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getEntries",
+ args = {}
+ )
+ public void test_getEntries() {
+ // Test for method java.util.Map java.util.jar.Manifest.getEntries()
+ Map<String, Attributes> myMap = m2.getEntries();
+ assertNull("Shouldn't exist", myMap.get("Doesn't exist"));
+ assertEquals("Should exist", "OK", myMap.get("HasAttributes.txt").get(
+ new Attributes.Name("MyAttribute")));
+
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#getMainAttributes()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getMainAttributes",
+ args = {}
+ )
+ public void test_getMainAttributes() {
+ // Test for method java.util.jar.Attributes
+ // java.util.jar.Manifest.getMainAttributes()
+ Attributes a = m.getMainAttributes();
+ assertEquals("Manifest_Version should return 1.0", "1.0", a
+ .get(Attributes.Name.MANIFEST_VERSION));
+ }
+
+ /**
+ * @tests {@link java.util.jar.Manifest#read(java.io.InputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "read",
+ args = {java.io.InputStream.class}
+ )
+ public void test_readLjava_io_InputStream() {
+ // Regression for HARMONY-89
+ InputStream is = new InputStreamImpl();
+ try {
+ new Manifest().read(is);
+ fail("Assert 0: Should have thrown IOException");
+ } catch (IOException e) {
+ // expected
+ }
+
+ Manifest manifest = new Manifest();
+ try {
+ manifest.read(new URL(Support_Resources
+ .getURL("manifest/hyts_MANIFEST.MF")).openStream());
+ } catch (MalformedURLException e) {
+ fail("Can nor read manifest");
+ } catch (IOException e) {
+ fail("Can nor read manifest");
+ }
+ Attributes main = manifest.getMainAttributes();
+ assertEquals("Bundle-Name not correct", "ClientSupport", main
+ .getValue("Bundle-Name"));
+ assertEquals(
+ "Bundle-Description not correct",
+
+ "Provides SessionService, AuthenticationService. Extends RegistryService.",
+ main.getValue("Bundle-Description"));
+ assertEquals("Bundle-Activator not correct",
+ "com.ibm.ive.eccomm.client.support.ClientSupportActivator",
+ main.getValue("Bundle-Activator"));
+ assertEquals(
+ "Import-Package not correct",
+
+ "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client",
+ main.getValue("Import-Package"));
+ assertEquals(
+ "Import-Service not correct",
+
+ "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService",
+ main.getValue("Import-Service"));
+ assertEquals(
+ "Export-Package not correct",
+
+ "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0",
+ main.getValue("Export-Package"));
+ assertEquals(
+ "Export-Service not correct",
+
+ "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService",
+ main.getValue("Export-Service"));
+ assertEquals("Bundle-Vendor not correct", "IBM", main
+ .getValue("Bundle-Vendor"));
+ assertEquals("Bundle-Version not correct", "1.2.0", main
+ .getValue("Bundle-Version"));
+ }
+
+ // helper class
+ class InputStreamImpl extends InputStream {
+ public InputStreamImpl() {
+ super();
+ }
+
+ @Override
+ public int read() {
+ return 0;
+ }
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#Manifest(Manifest)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Manifest",
+ args = {java.util.jar.Manifest.class}
+ )
+ public void test_ConstructorLjava_util_jar_Manifest() {
+ // Test for method java.util.jar.Manifest()
+ Manifest emptyManifest = new Manifest();
+ Manifest emptyClone = new Manifest(emptyManifest);
+ assertTrue("Should have no entries", emptyClone.getEntries().isEmpty());
+ assertTrue("Should have no main attributes", emptyClone
+ .getMainAttributes().isEmpty());
+ assertEquals(emptyClone, emptyManifest);
+ assertEquals(emptyClone, emptyManifest.clone());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clone",
+ args = {}
+ )
+ public void test_clone() {
+ Manifest emptyManifest = new Manifest();
+ Manifest emptyClone = (Manifest) emptyManifest.clone();
+ assertTrue("Should have no entries", emptyClone.getEntries().isEmpty());
+ assertTrue("Should have no main attributes", emptyClone
+ .getMainAttributes().isEmpty());
+ assertEquals(emptyClone, emptyManifest);
+ assertEquals(emptyManifest.clone().getClass().getName(),
+ "java.util.jar.Manifest");
+
+ Manifest manifest = null;
+ try {
+ manifest = new Manifest(new URL(Support_Resources
+ .getURL("manifest/hyts_MANIFEST.MF")).openStream());
+ } catch (MalformedURLException e) {
+ fail("Malformed URL");
+ } catch (IOException e) {
+ fail("IOException");
+ }
+ Manifest manifestClone = (Manifest) manifest.clone();
+ Attributes main = manifestClone.getMainAttributes();
+ assertEquals("Bundle-Name not correct", "ClientSupport", main
+ .getValue("Bundle-Name"));
+ assertEquals(
+ "Bundle-Description not correct",
+
+ "Provides SessionService, AuthenticationService. Extends RegistryService.",
+ main.getValue("Bundle-Description"));
+ assertEquals("Bundle-Activator not correct",
+ "com.ibm.ive.eccomm.client.support.ClientSupportActivator",
+ main.getValue("Bundle-Activator"));
+ assertEquals(
+ "Import-Package not correct",
+
+ "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client",
+ main.getValue("Import-Package"));
+ assertEquals(
+ "Import-Service not correct",
+
+ "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService",
+ main.getValue("Import-Service"));
+ assertEquals(
+ "Export-Package not correct",
+
+ "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0",
+ main.getValue("Export-Package"));
+ assertEquals(
+ "Export-Service not correct",
+
+ "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService",
+ main.getValue("Export-Service"));
+ assertEquals("Bundle-Vendor not correct", "IBM", main
+ .getValue("Bundle-Vendor"));
+ assertEquals("Bundle-Version not correct", "1.2.0", main
+ .getValue("Bundle-Version"));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "equals",
+ args = {java.lang.Object.class}
+ )
+ public void test_equals() {
+ Manifest manifest1 = null;
+ Manifest manifest2 = null;
+ Manifest manifest3 = new Manifest();
+ InputStream is = null;
+ try {
+ is = new URL(Support_Resources.getURL("manifest/hyts_MANIFEST.MF"))
+ .openStream();
+ } catch (MalformedURLException e1) {
+ fail("Failed to create InputStream object");
+ } catch (IOException e1) {
+ fail("Failed to create InputStream object");
+ }
+ try {
+ manifest1 = new Manifest(is);
+ } catch (MalformedURLException e) {
+ fail("Malformed URL");
+ } catch (IOException e) {
+ fail("IOException");
+ }
+
+ try {
+ manifest2 = new Manifest(new URL(Support_Resources
+ .getURL("manifest/hyts_MANIFEST.MF")).openStream());
+ } catch (MalformedURLException e) {
+ fail("Malformed URL");
+ } catch (IOException e) {
+ fail("IOException");
+ }
+
+ assertTrue(manifest1.equals(manifest1));
+ assertTrue(manifest1.equals(manifest2));
+ assertFalse(manifest1.equals(manifest3));
+ assertFalse(manifest1.equals(this));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "hashCode",
+ args = {}
+ )
+ public void test_hashCode() {
+ Manifest manifest1 = null;
+ Manifest manifest2 = new Manifest();
+ InputStream is = null;
+ try {
+ manifest1 = new Manifest(new URL(Support_Resources
+ .getURL("manifest/hyts_MANIFEST.MF")).openStream());
+ } catch (MalformedURLException e) {
+ fail("Malformed URL");
+ } catch (IOException e) {
+ fail("IOException");
+ }
+ assertEquals(manifest1.hashCode(), manifest1.hashCode());
+ assertNotSame(manifest1.hashCode(), manifest2.hashCode());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "write",
+ args = {java.io.OutputStream.class}
+ )
+ public void test_writeLjava_io_OutputStream() throws IOException {
+ byte b[] = null;
+ Manifest manifest1 = null;
+ Manifest manifest2 = null;
+ InputStream is = null;
+ try {
+ manifest1 = new Manifest(new URL(Support_Resources
+ .getURL("manifest/hyts_MANIFEST.MF")).openStream());
+ } catch (MalformedURLException e) {
+ fail("Malformed URL");
+ }
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ manifest1.write(baos);
+
+ b = baos.toByteArray();
+
+ File f = File.createTempFile("111", "111");
+ FileOutputStream fos = new FileOutputStream(f);
+ fos.close();
+ try {
+ manifest1.write(fos);
+ fail("IOException expected");
+ } catch (IOException e) {
+ // expected
+ }
+ f.delete();
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(b);
+
+ try {
+ manifest2 = new Manifest(bais);
+ } catch (MalformedURLException e) {
+ fail("Malformed URL");
+ }
+
+ assertTrue(manifest1.equals(manifest2));
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200PackerTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200PackerTest.java
new file mode 100644
index 0000000..355fd27
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200PackerTest.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+
+import junit.framework.TestCase;
+
+import tests.support.resource.Support_Resources;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.jar.Pack200;
+import java.util.jar.Pack200.Packer;
+
+@TestTargetClass(Pack200.Packer.class)
+public class Pack200PackerTest extends TestCase {
+ Packer packer;
+ Map properties;
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "properties",
+ args = {}
+ )
+ @KnownFailure("No Implementation in Android!")
+ public void testProperties() {
+ assertTrue(properties.size()>0);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "pack",
+ args = {java.util.jar.JarFile.class, java.io.OutputStream.class}
+ )
+ @KnownFailure("No Implementation in Android!")
+ public void testPackJarFileOutputStream() throws IOException {
+ File resources = Support_Resources.createTempFolder();
+ //Use junit4.jar file for testing pack200 compressing rate.
+ //file can be changed to any other.
+ Support_Resources.copyFile(resources, null, "junit4-4.3.1.jar");
+ File jarFile = new File(resources, "junit4-4.3.1.jar");
+ JarFile jf = new JarFile(jarFile);
+
+ File packFile1 = Support_Resources.createTempFile("pack200_1");
+ File packFile2 = Support_Resources.createTempFile("pack200_2");
+ File packFile3 = Support_Resources.createTempFile("pack200_3");
+ FileOutputStream fos1 = new FileOutputStream(packFile1);
+ FileOutputStream fos2 = new FileOutputStream(packFile2);
+ FileOutputStream fos3 = new FileOutputStream(packFile3);
+ properties.put(Packer.EFFORT, "0");
+ packer.pack(jf, fos1);
+ jf.close();
+ fos1.close();
+ jf = new JarFile(jarFile);
+ properties.put(Packer.EFFORT, "1");
+ packer.pack(jf, fos2);
+ jf.close();
+ fos2.close();
+ jf = new JarFile(jarFile);
+ properties.put(Packer.EFFORT, "9");
+ packer.pack(jf, fos3);
+ jf.close();
+ fos3.close();
+ assertTrue(jarFile.length()!=packFile1.length());
+ assertTrue(packFile1.length()>packFile2.length());
+ assertTrue(packFile2.length()>packFile3.length());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "pack",
+ args = {java.util.jar.JarInputStream.class, java.io.OutputStream.class}
+ )
+ @KnownFailure("No Implementation in Android!")
+ public void testPackJarInputStreamOutputStream() throws IOException {
+ File resources = Support_Resources.createTempFolder();
+ //Use junit4.jar file for testing pack200 compressing rate.
+ //file can be changed to any other.
+ Support_Resources.copyFile(resources, null, "junit4-4.3.1.jar");
+ File jarFile = new File(resources, "junit4-4.3.1.jar");
+ JarInputStream jis = new JarInputStream(new FileInputStream(jarFile));
+
+ File packFile1 = Support_Resources.createTempFile("pack200_1");
+ File packFile2 = Support_Resources.createTempFile("pack200_2");
+ File packFile3 = Support_Resources.createTempFile("pack200_3");
+ FileOutputStream fos1 = new FileOutputStream(packFile1);
+ FileOutputStream fos2 = new FileOutputStream(packFile2);
+ FileOutputStream fos3 = new FileOutputStream(packFile3);
+ properties.put(Packer.EFFORT, "0");
+ packer.pack(jis, fos1);
+ fos1.close();
+ jis = new JarInputStream(new FileInputStream(jarFile));
+ properties.put(Packer.EFFORT, "1");
+ packer.pack(jis, fos2);
+ fos2.close();
+ jis = new JarInputStream(new FileInputStream(jarFile));
+ properties.put(Packer.EFFORT, "9");
+ packer.pack(jis, fos3);
+ fos3.close();
+ assertTrue(jarFile.length()!=packFile1.length());
+ assertTrue(packFile1.length()>packFile2.length());
+ assertTrue(packFile2.length()>packFile3.length());
+ }
+
+/*
+ * java.beans.* not implemented yet on android platform
+ * class MyPCL implements PropertyChangeListener {
+ boolean flag = false;
+
+ public boolean isCalled() {
+ return flag;
+ }
+
+ public void propertyChange(PropertyChangeEvent arg0) {
+ flag = true;
+ }
+ }
+@TestInfo(
+ level = TestLevel.COMPLETE,
+
+ targets = {
+ @TestTarget(
+ methodName = "addPropertyChangeListener",
+ methodArgs = {java.beans.PropertyChangeListener.class}
+ )
+ })
+ public void testAddPropertyChangeListener() {
+ MyPCL pcl = new MyPCL();
+ packer.addPropertyChangeListener(pcl);
+ assertFalse(pcl.isCalled());
+ properties.put(Packer.EFFORT, "7");
+ assertTrue(pcl.isCalled());
+ }
+
+@TestInfo(
+ level = TestLevel.COMPLETE,
+
+ targets = {
+ @TestTarget(
+ methodName = "removePropertyChangeListener",
+ methodArgs = {java.beans.PropertyChangeListener.class}
+ )
+ })
+ public void testRemovePropertyChangeListener() {
+ MyPCL pcl = new MyPCL();
+ packer.addPropertyChangeListener(pcl);
+ assertFalse(pcl.isCalled());
+ packer.removePropertyChangeListener(pcl);
+ properties.put(Packer.EFFORT, "7");
+ assertFalse(pcl.isCalled());
+ }
+*/
+ @Override
+ protected void setUp() {
+ packer = Pack200.newPacker();
+ properties = packer.properties();
+ }
+
+ @Override
+ protected void tearDown() {
+ packer = null;
+ properties = null;
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200Test.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200Test.java
new file mode 100644
index 0000000..9fb3cf9
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200Test.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.jar.Pack200;
+
+@TestTargetClass(Pack200.class)
+public class Pack200Test extends TestCase {
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "newPacker",
+ args = {}
+ )
+ @KnownFailure("No Implementation in Android!")
+ public void testNewPacker() {
+ Method[] methodsInt = Pack200.Packer.class.getDeclaredMethods();
+ Method[] methodsImpl = Pack200.newPacker().getClass()
+ .getDeclaredMethods();
+ Field[] fieldsInt = Pack200.Packer.class.getFields();
+ Field[] fieldsImpl = Pack200.newPacker().getClass().getFields();
+ int i, k;
+ boolean flag;
+ for (i = 0; i < methodsInt.length; i++) {
+ flag = false;
+ for (k = 0; k < methodsImpl.length; k++) {
+ if (methodsInt[i].getName().equals(methodsImpl[k].getName())) {
+ flag = true;
+ break;
+ }
+ }
+ assertTrue("Not all methods were implemented", flag);
+ }
+
+ for (i = 0; i < fieldsInt.length; i++) {
+ flag = false;
+ for (k = 0; k < fieldsImpl.length; k++) {
+ if (fieldsInt[i].getName().equals(fieldsImpl[k].getName())) {
+ flag = true;
+ break;
+ }
+ }
+ assertTrue("Not all fields were existed", flag);
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "newUnpacker",
+ args = {}
+ )
+ @KnownFailure("No Implementation in Android!")
+ public void testNewUnpacker() {
+ assertNotNull(Pack200.newUnpacker().getClass());
+ Method[] methodsInt = Pack200.Unpacker.class.getDeclaredMethods();
+ Method[] methodsImpl = Pack200.newUnpacker().getClass()
+ .getDeclaredMethods();
+ Field[] fieldsInt = Pack200.Unpacker.class.getFields();
+ Field[] fieldsImpl = Pack200.newUnpacker().getClass().getFields();
+ int i, k;
+ boolean flag;
+ for (i = 0; i < methodsInt.length; i++) {
+ flag = false;
+ for (k = 0; k < methodsImpl.length; k++) {
+ if (methodsInt[i].getName().equals(methodsImpl[k].getName())) {
+ flag = true;
+ break;
+ }
+ }
+ assertTrue("Not all methods were implemented", flag);
+ }
+
+ for (i = 0; i < fieldsInt.length; i++) {
+ flag = false;
+ for (k = 0; k < fieldsImpl.length; k++) {
+ if (fieldsInt[i].getName().equals(fieldsImpl[k].getName())) {
+ flag = true;
+ break;
+ }
+ }
+ assertTrue("Not all fields were existed", flag);
+ }
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200UnpackerTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200UnpackerTest.java
new file mode 100644
index 0000000..4d5ede3
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/Pack200UnpackerTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+
+import junit.framework.TestCase;
+
+import tests.support.resource.Support_Resources;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Pack200;
+import java.util.jar.Pack200.Packer;
+import java.util.jar.Pack200.Unpacker;
+
+@TestTargetClass(Pack200.Unpacker.class)
+public class Pack200UnpackerTest extends TestCase {
+ Unpacker unpacker;
+ Map properties;
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "properties",
+ args = {}
+ )
+ @KnownFailure("No Implementation in Android!")
+ public void testProperties() {
+ assertTrue(properties.size()>0);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "unpack",
+ args = {java.io.File.class, java.util.jar.JarOutputStream.class}
+ )
+ @KnownFailure("No Implementation in Android!")
+ public void testUnpackInputStreamJarOutputStream() throws IOException {
+ File resources = Support_Resources.createTempFolder();
+ //Use junit4.jar file for testing pack200 compressing rate.
+ //file can be changed to any other.
+ Support_Resources.copyFile(resources, null, "junit4-4.3.1.jar");
+ File jarFile = new File(resources, "junit4-4.3.1.jar");
+ JarFile jf = new JarFile(jarFile);
+ int jarEntries = jf.size();
+
+ File packFile1 = Support_Resources.createTempFile("pack200_1");
+ File packFile2 = Support_Resources.createTempFile("pack200_2");
+ File packFile3 = Support_Resources.createTempFile("pack200_3");
+ FileOutputStream fos1 = new FileOutputStream(packFile1);
+ FileOutputStream fos2 = new FileOutputStream(packFile2);
+ FileOutputStream fos3 = new FileOutputStream(packFile3);
+ properties.put(Packer.EFFORT, "0");
+ Packer packer = Pack200.newPacker();
+ packer.pack(jf, fos1);
+ jf.close();
+ fos1.close();
+ jf = new JarFile(jarFile);
+ properties.put(Packer.EFFORT, "1");
+ packer.pack(jf, fos2);
+ jf.close();
+ fos2.close();
+ jf = new JarFile(jarFile);
+ properties.put(Packer.EFFORT, "9");
+ packer.pack(jf, fos3);
+ jf.close();
+ fos3.close();
+
+ File jarFile1 = Support_Resources.createTempFile("jar_1");
+ File jarFile2 = Support_Resources.createTempFile("jar_2");
+ File jarFile3 = Support_Resources.createTempFile("jar_3");
+ JarOutputStream jos1 = new JarOutputStream(new FileOutputStream(jarFile1));
+ JarOutputStream jos2 = new JarOutputStream(new FileOutputStream(jarFile2));
+ JarOutputStream jos3 = new JarOutputStream(new FileOutputStream(jarFile3));
+
+ unpacker.unpack(packFile1, jos1);
+ unpacker.unpack(packFile2, jos2);
+ unpacker.unpack(packFile3, jos3);
+
+ jos1.close();
+ jos2.close();
+ jos3.close();
+
+ assertEquals(jarFile1.length(), jarFile2.length());
+ assertEquals(jarFile2.length(), jarFile3.length());
+
+ assertEquals(jarEntries, new JarFile(jarFile1).size());
+ assertEquals(jarEntries, new JarFile(jarFile2).size());
+ assertEquals(jarEntries, new JarFile(jarFile3).size());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "unpack",
+ args = {java.io.InputStream.class, java.util.jar.JarOutputStream.class}
+ )
+ @KnownFailure("No Implementation in Android!")
+ public void testUnpackFileJarOutputStream() throws IOException {
+ File resources = Support_Resources.createTempFolder();
+ //Use junit4.jar file for testing pack200 compressing rate.
+ //file can be changed to any other.
+ Support_Resources.copyFile(resources, null, "junit4-4.3.1.jar");
+ File jarFile = new File(resources, "junit4-4.3.1.jar");
+ JarFile jf = new JarFile(jarFile);
+ int jarEntries = jf.size();
+
+ File packFile1 = Support_Resources.createTempFile("pack200_1");
+ File packFile2 = Support_Resources.createTempFile("pack200_2");
+ File packFile3 = Support_Resources.createTempFile("pack200_3");
+ FileOutputStream fos1 = new FileOutputStream(packFile1);
+ FileOutputStream fos2 = new FileOutputStream(packFile2);
+ FileOutputStream fos3 = new FileOutputStream(packFile3);
+ properties.put(Packer.EFFORT, "0");
+ Packer packer = Pack200.newPacker();
+ packer.pack(jf, fos1);
+ jf.close();
+ fos1.close();
+ jf = new JarFile(jarFile);
+ properties.put(Packer.EFFORT, "1");
+ packer.pack(jf, fos2);
+ jf.close();
+ fos2.close();
+ jf = new JarFile(jarFile);
+ properties.put(Packer.EFFORT, "9");
+ packer.pack(jf, fos3);
+ jf.close();
+ fos3.close();
+
+ File jarFile1 = Support_Resources.createTempFile("jar_1");
+ File jarFile2 = Support_Resources.createTempFile("jar_2");
+ File jarFile3 = Support_Resources.createTempFile("jar_3");
+ JarOutputStream jos1 = new JarOutputStream(new FileOutputStream(jarFile1));
+ JarOutputStream jos2 = new JarOutputStream(new FileOutputStream(jarFile2));
+ JarOutputStream jos3 = new JarOutputStream(new FileOutputStream(jarFile3));
+ FileInputStream fis1 = new FileInputStream(packFile1);
+ FileInputStream fis2 = new FileInputStream(packFile2);
+ FileInputStream fis3 = new FileInputStream(packFile3);
+
+ unpacker.unpack(fis1, jos1);
+ unpacker.unpack(fis2, jos2);
+ unpacker.unpack(fis3, jos3);
+
+ jos1.close();
+ jos2.close();
+ jos3.close();
+
+ assertEquals(jarFile1.length(), jarFile2.length());
+ assertEquals(jarFile2.length(), jarFile3.length());
+
+ assertEquals(jarEntries, new JarFile(jarFile1).size());
+ assertEquals(jarEntries, new JarFile(jarFile2).size());
+ assertEquals(jarEntries, new JarFile(jarFile3).size());
+ }
+/*
+ * java.beans.* not implemented yet on android platform
+ * class MyPCL implements PropertyChangeListener {
+ boolean flag = false;
+
+ public boolean isCalled() {
+ return flag;
+ }
+
+ public void propertyChange(PropertyChangeEvent arg0) {
+ flag = true;
+ }
+ }
+
+@TestInfo(
+ level = TestLevel.COMPLETE,
+
+ targets = {
+ @TestTarget(
+ methodName = "addPropertyChangeListener",
+ methodArgs = {java.beans.PropertyChangeListener.class}
+ )
+ })
+ public void testAddPropertyChangeListener() {
+ MyPCL pcl = new MyPCL();
+ unpacker.addPropertyChangeListener(pcl);
+ assertFalse(pcl.isCalled());
+ properties.put(Unpacker.PROGRESS, "0");
+ assertTrue(pcl.isCalled());
+ }
+
+@TestInfo(
+ level = TestLevel.COMPLETE,
+
+ targets = {
+ @TestTarget(
+ methodName = "removePropertyChangeListener",
+ methodArgs = {java.beans.PropertyChangeListener.class}
+ )
+ })
+ public void testRemovePropertyChangeListener() {
+ MyPCL pcl = new MyPCL();
+ unpacker.addPropertyChangeListener(pcl);
+ assertFalse(pcl.isCalled());
+ unpacker.removePropertyChangeListener(pcl);
+ properties.put(Unpacker.PROGRESS, "7");
+ assertFalse(pcl.isCalled());
+ }
+*/
+ @Override
+ protected void setUp() {
+ unpacker = Pack200.newUnpacker();
+ properties = unpacker.properties();
+ }
+
+ @Override
+ protected void tearDown() {
+ unpacker = null;
+ properties = null;
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ZipExecTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ZipExecTest.java
new file mode 100644
index 0000000..c6f07de
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ZipExecTest.java
@@ -0,0 +1,324 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.jar;
+
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import tests.support.Support_Exec;
+import tests.support.resource.Support_Resources;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ *
+ * tests for various cases of java -jar ... execution with .zip files as args
+ * some tests are just copy of JarExecTest ones
+ */
+
+@TestTargetClass(ZipOutputStream.class)
+public class ZipExecTest extends junit.framework.TestCase {
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Regression functional test. Exception checking missed.",
+ method = "putNextEntry",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
+ public void test_1562() throws Exception {
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+
+ File outputZip = File.createTempFile("hyts_", ".zip");
+ outputZip.deleteOnExit();
+ ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(
+ outputZip));
+ File resources = Support_Resources.createTempFolder();
+
+ for (String zipClass : new String[] {"Foo", "Bar"}) {
+ zout.putNextEntry(new ZipEntry("foo/bar/execjartest/" + zipClass
+ + ".class"));
+ zout.write(getResource(resources, "hyts_" + zipClass + ".ser"));
+ }
+
+ zout.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
+ man.write(zout);
+ zout.close();
+
+
+ // set up the VM parameters
+ String[] args = new String[] {"-jar", outputZip.getAbsolutePath()};
+
+ // execute the JAR and read the result
+ String res = Support_Exec.execJava(args, null, false);
+
+ assertTrue("Error executing ZIP : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+ }
+
+ /**
+ * tests Class-Path entry in manifest
+ *
+ * @throws Exception in case of troubles
+ */
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Functional test.",
+ method = "ZipOutputStream",
+ args = {java.io.OutputStream.class}
+ )
+ @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
+ public void test_zip_class_path() throws Exception {
+ File fooZip = File.createTempFile("hyts_", ".zip");
+ File barZip = File.createTempFile("hyts_", ".zip");
+ fooZip.deleteOnExit();
+ barZip.deleteOnExit();
+
+ // create the manifest
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+ att.put(Attributes.Name.CLASS_PATH, barZip.getName());
+
+ File resources = Support_Resources.createTempFolder();
+
+ ZipOutputStream zoutFoo = new ZipOutputStream(new FileOutputStream(
+ fooZip));
+ zoutFoo.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
+ man.write(zoutFoo);
+ zoutFoo.putNextEntry(new ZipEntry("foo/bar/execjartest/Foo.class"));
+ zoutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ zoutFoo.close();
+
+ ZipOutputStream zoutBar = new ZipOutputStream(new FileOutputStream(
+ barZip));
+ zoutBar.putNextEntry(new ZipEntry("foo/bar/execjartest/Bar.class"));
+ zoutBar.write(getResource(resources, "hyts_Bar.ser"));
+ zoutBar.close();
+
+ String[] args = new String[] {"-jar", fooZip.getAbsolutePath()};
+
+ // execute the JAR and read the result
+ String res = Support_Exec.execJava(args, null, false);
+
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+
+ // rewrite manifest so it contains not only reference to bar but useless
+ // entries as well
+ att.put(Attributes.Name.CLASS_PATH, "xx yy zz " + barZip.getName());
+ zoutFoo = new ZipOutputStream(new FileOutputStream(fooZip));
+ zoutFoo.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
+ man.write(zoutFoo);
+ zoutFoo.putNextEntry(new ZipEntry("foo/bar/execjartest/Foo.class"));
+ zoutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ zoutFoo.close();
+ // execute the JAR and read the result
+ res = Support_Exec.execJava(args, null, false);
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+
+
+ // play with relative file names - put relative path as ../<parent dir
+ // name>/xx.zip
+ att.put(Attributes.Name.CLASS_PATH, ".." + File.separator
+ + barZip.getParentFile().getName() + File.separator
+ + barZip.getName());
+ zoutFoo = new ZipOutputStream(new FileOutputStream(fooZip));
+ zoutFoo.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
+ man.write(zoutFoo);
+ zoutFoo.putNextEntry(new ZipEntry("foo/bar/execjartest/Foo.class"));
+ zoutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ zoutFoo.close();
+ // execute the ZIP and read the result
+ res = Support_Exec.execJava(args, null, false);
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+ }
+
+
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Functional test.",
+ method = "ZipOutputStream",
+ args = {java.io.OutputStream.class}
+ )
+ @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
+ public void test_zip_jar_mix() throws Exception {
+ File fooJar = File.createTempFile("hyts_", ".jar");
+ File barZip = File.createTempFile("hyts_", ".zip");
+ fooJar.deleteOnExit();
+ barZip.deleteOnExit();
+
+ // create the manifest
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+ att.put(Attributes.Name.CLASS_PATH, barZip.getName());
+
+ File resources = Support_Resources.createTempFolder();
+
+ JarOutputStream joutFoo = new JarOutputStream(new FileOutputStream(
+ fooJar), man);
+ joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
+ joutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ joutFoo.close();
+
+ ZipOutputStream zoutBar = new ZipOutputStream(new FileOutputStream(
+ barZip));
+ zoutBar.putNextEntry(new ZipEntry("foo/bar/execjartest/Bar.class"));
+ zoutBar.write(getResource(resources, "hyts_Bar.ser"));
+ zoutBar.close();
+
+ String[] args = new String[] {"-jar", fooJar.getAbsolutePath()};
+
+ // execute the JAR and read the result
+ String res = Support_Exec.execJava(args, null, false);
+
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Functional test.",
+ method = "ZipOutputStream",
+ args = {java.io.OutputStream.class}
+ )
+ @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
+ public void test_zip_jar_mix_1() throws Exception {
+ File fooZip = File.createTempFile("hyts_", ".zip");
+ File barJar = File.createTempFile("hyts_", ".jar");
+ fooZip.deleteOnExit();
+ barJar.deleteOnExit();
+
+ // create the manifest
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+ att.put(Attributes.Name.CLASS_PATH, barJar.getName());
+
+ File resources = Support_Resources.createTempFolder();
+
+ ZipOutputStream zoutFoo = new ZipOutputStream(new FileOutputStream(
+ fooZip));
+ zoutFoo.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
+ man.write(zoutFoo);
+ zoutFoo.putNextEntry(new ZipEntry("foo/bar/execjartest/Foo.class"));
+ zoutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ zoutFoo.close();
+
+ JarOutputStream joutBar = new JarOutputStream(new FileOutputStream(
+ barJar));
+ joutBar.putNextEntry(new ZipEntry("foo/bar/execjartest/Bar.class"));
+ joutBar.write(getResource(resources, "hyts_Bar.ser"));
+ joutBar.close();
+
+ String[] args = new String[] {"-jar", fooZip.getAbsolutePath()};
+
+ // execute the JAR and read the result
+ String res = Support_Exec.execJava(args, null, false);
+
+ assertTrue("Error executing ZIP : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+ }
+
+ /**
+ * tests case when Main-Class is not in the zip launched but in another zip
+ * referenced by Class-Path
+ *
+ * @throws Exception in case of troubles
+ */
+ @TestTargetNew(
+ level = TestLevel.ADDITIONAL,
+ notes = "Functional test.",
+ method = "ZipOutputStream",
+ args = {java.io.OutputStream.class}
+ )
+ @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
+ public void test_main_class_in_another_zip() throws Exception {
+ File fooZip = File.createTempFile("hyts_", ".zip");
+ File barZip = File.createTempFile("hyts_", ".zip");
+ fooZip.deleteOnExit();
+ barZip.deleteOnExit();
+
+ // create the manifest
+ Manifest man = new Manifest();
+ Attributes att = man.getMainAttributes();
+ att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
+ att.put(Attributes.Name.CLASS_PATH, fooZip.getName());
+
+ File resources = Support_Resources.createTempFolder();
+
+ ZipOutputStream zoutFoo = new ZipOutputStream(new FileOutputStream(
+ fooZip));
+ zoutFoo.putNextEntry(new ZipEntry("foo/bar/execjartest/Foo.class"));
+ zoutFoo.write(getResource(resources, "hyts_Foo.ser"));
+ zoutFoo.close();
+
+ ZipOutputStream zoutBar = new ZipOutputStream(new FileOutputStream(
+ barZip));
+ zoutBar.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
+ man.write(zoutBar);
+
+ zoutBar.putNextEntry(new ZipEntry("foo/bar/execjartest/Bar.class"));
+ zoutBar.write(getResource(resources, "hyts_Bar.ser"));
+ zoutBar.close();
+
+ String[] args = new String[] {"-jar", barZip.getAbsolutePath()};
+
+ // execute the JAR and read the result
+ String res = Support_Exec.execJava(args, null, false);
+
+ assertTrue("Error executing JAR : result returned was incorrect.", res
+ .startsWith("FOOBAR"));
+ }
+
+
+ private static byte[] getResource(File tempDir, String resourceName)
+ throws IOException {
+ Support_Resources.copyFile(tempDir, null, resourceName);
+ File resourceFile = new File(tempDir, resourceName);
+ resourceFile.deleteOnExit();
+
+ // read whole resource data into memory
+ byte[] resourceBody = new byte[(int) resourceFile.length()];
+ FileInputStream fis = new FileInputStream(resourceFile);
+ fis.read(resourceBody);
+ fis.close();
+
+ return resourceBody;
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/Adler32Test.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/Adler32Test.java
new file mode 100644
index 0000000..532a3a6
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/Adler32Test.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.util.zip.Adler32;
+
+@TestTargetClass(Adler32.class)
+public class Adler32Test extends junit.framework.TestCase {
+
+ /**
+ * @tests java.util.zip.Adler32#Adler32()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Adler32",
+ args = {}
+ )
+ public void test_Constructor() {
+ // test method of java.util.zip.Adler32()
+ Adler32 adl = new Adler32();
+ assertEquals("Constructor of adl32 failed", 1, adl.getValue());
+ }
+
+ /**
+ * @tests java.util.zip.Adler32#getValue()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getValue",
+ args = {}
+ )
+ public void test_getValue() {
+ // test methods of java.util.zip.getValue()
+ Adler32 adl = new Adler32();
+ assertEquals(
+ "GetValue should return a zero as a result of construction an object of Adler32",
+ 1, adl.getValue());
+
+ adl.reset();
+ adl.update(1);
+ // System.out.print("value of adl"+adl.getValue());
+ // The value of the adl should be 131074
+ assertEquals(
+ "update(int) failed to update the checksum to the correct value ",
+ 131074, adl.getValue());
+ adl.reset();
+ assertEquals("reset failed to reset the checksum value to zero", 1, adl
+ .getValue());
+
+ adl.reset();
+ adl.update(Integer.MIN_VALUE);
+ // System.out.print("value of adl " + adl.getValue());
+ // The value of the adl should be 65537
+ assertEquals(
+ "update(min) failed to update the checksum to the correct value ",
+ 65537L, adl.getValue());
+ }
+
+ /**
+ * @tests java.util.zip.Adler32#reset()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "reset",
+ args = {}
+ )
+ public void test_reset() {
+ // test methods of java.util.zip.reset()
+ Adler32 adl = new Adler32();
+ adl.update(1);
+ // System.out.print("value of adl"+adl.getValue());
+ // The value of the adl should be 131074
+ assertEquals(
+ "update(int) failed to update the checksum to the correct value ",
+ 131074, adl.getValue());
+ adl.reset();
+ assertEquals("reset failed to reset the checksum value to zero", 1, adl
+ .getValue());
+ }
+
+ /**
+ * @tests java.util.zip.Adler32#update(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "update",
+ args = {int.class}
+ )
+ public void test_updateI() {
+ // test methods of java.util.zip.update(int)
+ Adler32 adl = new Adler32();
+ adl.update(1);
+ // The value of the adl should be 131074
+ assertEquals(
+ "update(int) failed to update the checksum to the correct value ",
+ 131074, adl.getValue());
+
+ adl.reset();
+ adl.update(Integer.MAX_VALUE);
+ // System.out.print("value of adl " + adl.getValue());
+ // The value of the adl should be 16777472
+ assertEquals(
+ "update(max) failed to update the checksum to the correct value ",
+ 16777472L, adl.getValue());
+
+ adl.reset();
+ adl.update(Integer.MIN_VALUE);
+ // System.out.print("value of adl " + adl.getValue());
+ // The value of the adl should be 65537
+ assertEquals(
+ "update(min) failed to update the checksum to the correct value ",
+ 65537L, adl.getValue());
+
+ }
+
+ /**
+ * @tests java.util.zip.Adler32#update(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "update",
+ args = {byte[].class}
+ )
+ public void test_update$B() {
+ // test method of java.util.zip.update(byte[])
+ byte byteArray[] = {1, 2};
+ Adler32 adl = new Adler32();
+ adl.update(byteArray);
+ // System.out.print("value of adl"+adl.getValue());
+ // The value of the adl should be 393220
+ assertEquals(
+ "update(byte[]) failed to update the checksum to the correct value ",
+ 393220, adl.getValue());
+
+ adl.reset();
+ byte byteEmpty[] = new byte[10000];
+ adl.update(byteEmpty);
+ // System.out.print("value of adl"+adl.getValue());
+ // The value of the adl should be 655360001
+ assertEquals(
+ "update(byte[]) failed to update the checksum to the correct value ",
+ 655360001L, adl.getValue());
+
+ }
+
+ /**
+ * @tests java.util.zip.Adler32#update(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "update",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_update$BII() {
+ // test methods of java.util.zip.update(byte[],int,int)
+ byte[] byteArray = {1, 2, 3};
+ Adler32 adl = new Adler32();
+ int off = 2;// accessing the 2nd element of byteArray
+ int len = 1;
+ int lenError = 3;
+ int offError = 4;
+ adl.update(byteArray, off, len);
+ // System.out.print("value of adl"+adl.getValue());
+ // The value of the adl should be 262148
+ assertEquals(
+ "update(byte[],int,int) failed to update the checksum to the correct value ",
+ 262148, adl.getValue());
+ int r = 0;
+
+ try {
+ adl.update(byteArray, off, lenError);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ r = 1;
+ }
+ assertEquals(
+ "update(byte[],int,int) failed b/c lenError>byte[].length-off",
+ 1, r);
+
+ try {
+ adl.update(byteArray, offError, len);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ r = 2;
+ }
+ assertEquals(
+ "update(byte[],int,int) failed b/c offError>byte[].length", 2,
+ r);
+
+ }
+
+ @Override
+ protected void setUp() {
+ }
+
+ @Override
+ protected void tearDown() {
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/AllTests.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/AllTests.java
new file mode 100644
index 0000000..acde889
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/AllTests.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite for java.util.zip package.
+ */
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite = tests.TestSuiteFactory.createTestSuite(
+ "Suite org.apache.harmony.archive.tests.java.util.zip");
+ // $JUnit-BEGIN$
+ suite.addTestSuite(Adler32Test.class);
+ suite.addTestSuite(CheckedInputStreamTest.class);
+ suite.addTestSuite(CheckedOutputStreamTest.class);
+ suite.addTestSuite(CRC32Test.class);
+ suite.addTestSuite(DataFormatExceptionTest.class);
+ suite.addTestSuite(DeflaterOutputStreamTest.class);
+ suite.addTestSuite(DeflaterTest.class);
+ suite.addTestSuite(GZIPInputStreamTest.class);
+ suite.addTestSuite(GZIPOutputStreamTest.class);
+ suite.addTestSuite(InflaterInputStreamTest.class);
+ suite.addTestSuite(InflaterTest.class);
+ suite.addTestSuite(ZipEntryTest.class);
+ suite.addTestSuite(ZipExceptionTest.class);
+ suite.addTestSuite(ZipFileTest.class);
+ suite.addTestSuite(ZipInputStreamTest.class);
+ suite.addTestSuite(ZipOutputStreamTest.class);
+ // $JUnit-END$
+ return suite;
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CRC32Test.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CRC32Test.java
new file mode 100644
index 0000000..805cab3
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CRC32Test.java
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.util.zip.CRC32;
+
+@TestTargetClass(CRC32.class)
+public class CRC32Test extends junit.framework.TestCase {
+
+ /**
+ * @tests java.util.zip.CRC32#CRC32()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "CRC32",
+ args = {}
+ )
+ public void test_Constructor() {
+ // test methods of java.util.zip.CRC32()
+ CRC32 crc = new CRC32();
+ assertEquals("Constructor of CRC32 failed", 0, crc.getValue());
+ }
+
+ /**
+ * @tests java.util.zip.CRC32#getValue()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getValue",
+ args = {}
+ )
+ public void test_getValue() {
+ // test methods of java.util.zip.crc32.getValue()
+ CRC32 crc = new CRC32();
+ assertEquals(
+ "getValue() should return a zero as a result of constructing a CRC32 instance",
+ 0, crc.getValue());
+
+ crc.reset();
+ crc.update(Integer.MAX_VALUE);
+ // System.out.print("value of crc " + crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 4278190080
+ assertEquals(
+ "update(max) failed to update the checksum to the correct value ",
+ 4278190080L, crc.getValue());
+
+ crc.reset();
+ byte byteEmpty[] = new byte[10000];
+ crc.update(byteEmpty);
+ // System.out.print("value of crc"+crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 1295764014
+ assertEquals(
+ "update(byte[]) failed to update the checksum to the correct value ",
+ 1295764014L, crc.getValue());
+
+ crc.reset();
+ crc.update(1);
+ // System.out.print("value of crc"+crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 2768625435
+ // assertEquals("update(int) failed to update the checksum to the
+ // correct
+ // value ",2768625435L, crc.getValue());
+ crc.reset();
+ assertEquals("reset failed to reset the checksum value to zero", 0, crc
+ .getValue());
+ }
+
+ /**
+ * @tests java.util.zip.CRC32#reset()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "reset",
+ args = {}
+ )
+ public void test_reset() {
+ // test methods of java.util.zip.crc32.reset()
+ CRC32 crc = new CRC32();
+ crc.update(1);
+ // System.out.print("value of crc"+crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 2768625435
+ assertEquals(
+ "update(int) failed to update the checksum to the correct value ",
+ 2768625435L, crc.getValue());
+ crc.reset();
+ assertEquals("reset failed to reset the checksum value to zero", 0, crc
+ .getValue());
+
+ }
+
+ /**
+ * @tests java.util.zip.CRC32#update(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "update",
+ args = {int.class}
+ )
+ public void test_updateI() {
+ // test methods of java.util.zip.crc32.update(int)
+ CRC32 crc = new CRC32();
+ crc.update(1);
+ // System.out.print("value of crc"+crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 2768625435
+ assertEquals(
+ "update(1) failed to update the checksum to the correct value ",
+ 2768625435L, crc.getValue());
+
+ crc.reset();
+ crc.update(Integer.MAX_VALUE);
+ // System.out.print("value of crc " + crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 4278190080
+ assertEquals(
+ "update(max) failed to update the checksum to the correct value ",
+ 4278190080L, crc.getValue());
+
+ crc.reset();
+ crc.update(Integer.MIN_VALUE);
+ // System.out.print("value of crc " + crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 3523407757
+ assertEquals(
+ "update(min) failed to update the checksum to the correct value ",
+ 3523407757L, crc.getValue());
+ }
+
+ /**
+ * @tests java.util.zip.CRC32#update(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "update",
+ args = {byte[].class}
+ )
+ public void test_update$B() {
+ // test methods of java.util.zip.crc32.update(byte[])
+ byte byteArray[] = {1, 2};
+ CRC32 crc = new CRC32();
+ crc.update(byteArray);
+ // System.out.print("value of crc"+crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 3066839698
+ assertEquals(
+ "update(byte[]) failed to update the checksum to the correct value ",
+ 3066839698L, crc.getValue());
+
+ crc.reset();
+ byte byteEmpty[] = new byte[10000];
+ crc.update(byteEmpty);
+ // System.out.print("value of crc"+crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 1295764014
+ assertEquals(
+ "update(byte[]) failed to update the checksum to the correct value ",
+ 1295764014L, crc.getValue());
+ }
+
+ /**
+ * @tests java.util.zip.CRC32#update(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "update",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_update$BII() {
+ // test methods of java.util.zip.update(byte[],int,int)
+ byte[] byteArray = {1, 2, 3};
+ CRC32 crc = new CRC32();
+ int off = 2;// accessing the 2nd element of byteArray
+ int len = 1;
+ int lenError = 3;
+ int offError = 4;
+ crc.update(byteArray, off, len);
+ // System.out.print("value of crc"+crc.getValue());
+ // Ran JDK and discovered that the value of the CRC should be
+ // 1259060791
+ assertEquals(
+ "update(byte[],int,int) failed to update the checksum to the correct value ",
+ 1259060791L, crc.getValue());
+ int r = 0;
+ try {
+ crc.update(byteArray, off, lenError);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ r = 1;
+ }
+ assertEquals(
+ "update(byte[],int,int) failed b/c lenError>byte[].length-off",
+ 1, r);
+
+ try {
+ crc.update(byteArray, offError, len);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ r = 2;
+ }
+ assertEquals(
+ "update(byte[],int,int) failed b/c offError>byte[].length", 2,
+ r);
+ }
+
+ @Override
+ protected void setUp() {
+
+ }
+
+ @Override
+ protected void tearDown() {
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CheckedInputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CheckedInputStreamTest.java
new file mode 100644
index 0000000..3b5cdb4
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CheckedInputStreamTest.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedInputStream;
+import junit.framework.TestCase;
+import tests.support.resource.Support_Resources;
+
+
+@TestTargetClass(CheckedInputStream.class)
+public class CheckedInputStreamTest extends TestCase {
+
+ @Override
+ protected void tearDown() {
+ try {
+ File deletedFile = new File("empty.txt");
+ deletedFile.delete();
+ } catch (SecurityException e) {
+ fail("Cannot delete file for security reasons");
+ }
+
+ }
+
+ /**
+ * @tests java.util.zip.CheckedInputStream#CheckedInputStream(java.io.InputStream,
+ * java.util.zip.Checksum)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "CheckedInputStream",
+ args = {java.io.InputStream.class, java.util.zip.Checksum.class}
+ )
+ public void test_ConstructorLjava_io_InputStreamLjava_util_zip_Checksum()
+ throws Exception {
+ InputStream checkInput = Support_Resources
+ .getStream("hyts_checkInput.txt");
+ CheckedInputStream checkIn = new CheckedInputStream(checkInput,
+ new CRC32());
+ assertEquals("constructor of checkedInputStream has failed", 0, checkIn
+ .getChecksum().getValue());
+ checkInput.close();
+ }
+
+ /**
+ * @tests java.util.zip.CheckedInputStream#getChecksum()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getChecksum",
+ args = {}
+ )
+ public void test_getChecksum() throws Exception {
+ byte outBuf[] = new byte[100];
+ // testing getChecksum for an empty file
+ FileOutputStream outEmp = new FileOutputStream("empty.txt");
+ outEmp.close();
+ InputStream inEmp = new FileInputStream("empty.txt");
+ CheckedInputStream checkEmpty = new CheckedInputStream(inEmp,
+ new CRC32());
+ while (checkEmpty.read() >= 0) {
+ }
+ assertEquals("the checkSum value of an empty file is not zero", 0,
+ checkEmpty.getChecksum().getValue());
+ inEmp.close();
+
+ // testing getChecksum for the file checkInput
+ InputStream checkInput = Support_Resources
+ .getStream("hyts_checkInput.txt");
+ CheckedInputStream checkIn = new CheckedInputStream(checkInput,
+ new CRC32());
+ while (checkIn.read() >= 0) {
+ }
+ // ran JDK and found that the checkSum value of this is 2036203193
+ // System.out.print(" " + checkIn.getChecksum().getValue());
+ assertEquals("the checksum value is incorrect", 2036203193, checkIn
+ .getChecksum().getValue());
+ checkInput.close();
+ // testing getChecksum for file checkInput
+ checkInput = Support_Resources.getStream("hyts_checkInput.txt");
+ CheckedInputStream checkIn2 = new CheckedInputStream(checkInput,
+ new CRC32());
+ checkIn2.read(outBuf, 0, 10);
+ // ran JDK and found that the checkSum value of this is 2235765342
+ // System.out.print(" " + checkIn2.getChecksum().getValue());
+ assertEquals("the checksum value is incorrect", 2235765342L, checkIn2
+ .getChecksum().getValue());
+ checkInput.close();
+ }
+
+ /**
+ * @tests java.util.zip.CheckedInputStream#skip(long)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "skip",
+ args = {long.class}
+ )
+ public void test_skipJ() throws Exception {
+ // testing that the return by skip is valid
+ InputStream checkInput = Support_Resources
+ .getStream("hyts_checkInput.txt");
+ CheckedInputStream checkIn = new CheckedInputStream(checkInput,
+ new CRC32());
+ long skipValue = 5;
+ assertEquals(
+ "the value returned by skip(n) is not the same as its parameter",
+ skipValue, checkIn.skip(skipValue));
+ checkIn.skip(skipValue);
+ // ran JDK and found the checkSum value is 2235765342
+ // System.out.print(checkIn.getChecksum().getValue());
+ assertEquals("checkSum value is not correct", 2235765342L, checkIn
+ .getChecksum().getValue());
+ checkInput.close();
+ try {
+ checkInput.skip(33);
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.CheckedInputStream#read()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "read",
+ args = {}
+ )
+ public void test_read() throws Exception {
+ // testing that the return by skip is valid
+ InputStream checkInput = Support_Resources
+ .getStream("hyts_checkInput.txt");
+ CheckedInputStream checkIn = new CheckedInputStream(checkInput,
+ new CRC32());
+ checkIn.read();
+ checkIn.close();
+ try {
+ checkIn.read();
+ fail("IOException expected.");
+ } catch (IOException ee) {
+ // expected
+ }
+ long skipValue = 5;
+ checkInput.close();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "read",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_read$byteII() throws Exception {
+ // testing that the return by skip is valid
+ InputStream checkInput = Support_Resources
+ .getStream("hyts_checkInput.txt");
+ CheckedInputStream checkIn = new CheckedInputStream(checkInput,
+ new CRC32());
+ byte buff[] = new byte[50];
+ checkIn.read(buff, 10, 5);
+ checkIn.close();
+ try {
+ checkIn.read(buff, 10, 5);
+ fail("IOException expected.");
+ } catch (IOException ee) {
+ // expected
+ }
+ long skipValue = 5;
+ checkInput.close();
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CheckedOutputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CheckedOutputStreamTest.java
new file mode 100644
index 0000000..c0a83d2
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/CheckedOutputStreamTest.java
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.zip.Adler32;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedOutputStream;
+
+@TestTargetClass(CheckedOutputStream.class)
+public class CheckedOutputStreamTest extends junit.framework.TestCase {
+
+ /**
+ * @tests java.util.zip.CheckedOutputStream#CheckedOutputStream(java.io.OutputStream,
+ * java.util.zip.Checksum)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "CheckedOutputStream",
+ args = {java.io.OutputStream.class, java.util.zip.Checksum.class}
+ )
+ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_Checksum() {
+ // test method java.util.zip.checkedOutputStream.constructor
+ try {
+ FileOutputStream outFile = new FileOutputStream("chkOut.txt");
+ CheckedOutputStream chkOut = new CheckedOutputStream(outFile,
+ new CRC32());
+ assertEquals("the checkSum value of the constructor is not 0", 0,
+ chkOut.getChecksum().getValue());
+ outFile.close();
+ } catch (IOException e) {
+ fail("Unable to find file");
+ } catch (SecurityException e) {
+ fail("file cannot be opened for writing due to security reasons");
+ }
+ }
+
+ /**
+ * @tests java.util.zip.CheckedOutputStream#getChecksum()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getChecksum",
+ args = {}
+ )
+ public void test_getChecksum() {
+ // test method java.util.zip.checkedOutputStream.getChecksum()
+ byte byteArray[] = {1, 2, 3, 'e', 'r', 't', 'g', 3, 6};
+ try {
+ FileOutputStream outFile = new FileOutputStream("chkOut.txt");
+ CheckedOutputStream chkOut = new CheckedOutputStream(outFile,
+ new Adler32());
+ chkOut.write(byteArray[4]);
+ // ran JDK and found that checkSum value is 7536755
+ // System.out.print(chkOut.getChecksum().getValue());
+
+ assertEquals("the checkSum value for writeI is incorrect", 7536755,
+ chkOut.getChecksum().getValue());
+ chkOut.getChecksum().reset();
+ chkOut.write(byteArray, 5, 4);
+ // ran JDK and found that checkSum value is 51708133
+ // System.out.print(" " +chkOut.getChecksum().getValue());
+
+ assertEquals("the checkSum value for writeBII is incorrect ",
+ 51708133, chkOut.getChecksum().getValue());
+ outFile.close();
+ } catch (IOException e) {
+ fail("Unable to find file");
+ } catch (SecurityException e) {
+ fail("file cannot be opened for writing due to security reasons");
+ }
+ }
+
+ /**
+ * @tests java.util.zip.CheckedOutputStream#write(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "write",
+ args = {int.class}
+ )
+ public void test_writeI() {
+ // test method java.util.zip.checkedOutputStream.writeI()
+ CheckedOutputStream chkOut = null;
+ byte byteArray[] = {1, 2, 3, 'e', 'r', 't', 'g', 3, 6};
+ try {
+ FileOutputStream outFile = new FileOutputStream("chkOut.txt");
+ chkOut = new CheckedOutputStream(outFile, new CRC32());
+ for (byte element : byteArray) {
+ chkOut.write(element);
+ }
+ assertTrue(
+ "the checkSum value is zero, no bytes are written to the output file",
+ chkOut.getChecksum().getValue() != 0);
+ outFile.close();
+ } catch (IOException e) {
+ fail("Unable to find file");
+ } catch (SecurityException e) {
+ fail("File cannot be opened for writing due to security reasons");
+ }
+ try {
+ chkOut.write(0);
+ fail("IOException expected");
+ } catch (IOException e) {
+ // expected.
+ }
+ }
+
+ /**
+ * @tests java.util.zip.CheckedOutputStream#write(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "write",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_write$BII() {
+ // test method java.util.zip.checkOutputStream.writeBII()
+ CheckedOutputStream chkOut = null;
+ byte byteArray[] = {1, 2, 3, 'e', 'r', 't', 'g', 3, 6};
+ try {
+ FileOutputStream outFile = new FileOutputStream("chkOut.txt");
+ chkOut = new CheckedOutputStream(outFile, new CRC32());
+ chkOut.write(byteArray, 4, 5);
+ assertTrue(
+ "the checkSum value is zero, no bytes are written to the output file",
+ chkOut.getChecksum().getValue() != 0);
+ int r = 0;
+ try {
+ chkOut.write(byteArray, 4, 6);
+ } catch (IndexOutOfBoundsException e) {
+ r = 1;
+ }
+ assertEquals("boundary check is not performed", 1, r);
+ outFile.close();
+ } catch (IOException e) {
+ fail("Unable to find file");
+ } catch (SecurityException e) {
+ fail("file cannot be opened for writing due to security reasons");
+ } catch (IndexOutOfBoundsException e) {
+ fail("Index for write is out of bounds");
+ }
+ try {
+ chkOut.write(byteArray, 4, 5);
+ fail("IOException expected");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ @Override
+ protected void setUp() {
+ }
+
+ @Override
+ protected void tearDown() {
+ try {
+ File deletedFile = new File("chkOut.txt");
+ deletedFile.delete();
+ } catch (SecurityException e) {
+ fail("Cannot delete file for security reasons");
+ }
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DataFormatExceptionTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DataFormatExceptionTest.java
new file mode 100644
index 0000000..6561bbd
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DataFormatExceptionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargetClass;
+
+import junit.framework.TestCase;
+
+import java.util.zip.DataFormatException;
+
+@TestTargetClass(DataFormatException.class)
+public class DataFormatExceptionTest extends TestCase {
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "DataFormatException",
+ args = {}
+ )
+ public void testDataFormatException() {
+ DataFormatException dfe = new DataFormatException();
+ assertEquals(dfe.getMessage(), null);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "DataFormatException",
+ args = {java.lang.String.class}
+ )
+ public void testDataFormatExceptionString() {
+ DataFormatException dfe = new DataFormatException("Test");
+ assertEquals(dfe.getMessage(), "Test");
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterOutputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterOutputStreamTest.java
new file mode 100644
index 0000000..9a804c1
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterOutputStreamTest.java
@@ -0,0 +1,461 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+import junit.framework.TestCase;
+
+@TestTargetClass(DeflaterOutputStream.class)
+public class DeflaterOutputStreamTest extends TestCase {
+
+ private class MyDeflaterOutputStream extends DeflaterOutputStream {
+ boolean deflateFlag = false;
+
+ MyDeflaterOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ MyDeflaterOutputStream(OutputStream out, Deflater defl) {
+ super(out, defl);
+ }
+
+ MyDeflaterOutputStream(OutputStream out, Deflater defl, int size) {
+ super(out, defl, size);
+ }
+
+ byte[] getProtectedBuf() {
+ return buf;
+ }
+
+ protected void deflate() throws IOException {
+ deflateFlag = true;
+ super.deflate();
+ }
+
+ boolean getDaflateFlag() {
+ return deflateFlag;
+ }
+
+ void cleanDaflateFlag() {
+ deflateFlag = false;
+ }
+ }
+
+ private byte outPutBuf[] = new byte[500];
+
+ @Override
+ protected void setUp() {
+ // setting up a deflater to be used
+ byte byteArray[] = {1, 3, 4, 7, 8};
+ int x = 0;
+ Deflater deflate = new Deflater(1);
+ deflate.setInput(byteArray);
+ while (!(deflate.needsInput())) {
+ x += deflate.deflate(outPutBuf, x, outPutBuf.length - x);
+ }
+ deflate.finish();
+ while (!(deflate.finished())) {
+ x = x + deflate.deflate(outPutBuf, x, outPutBuf.length - x);
+ }
+ deflate.end();
+ }
+
+ /**
+ * @tests java.util.zip.DeflaterOutputStream#DeflaterOutputStream(java.io.OutputStream,
+ * java.util.zip.Deflater)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "DeflaterOutputStream",
+ args = {java.io.OutputStream.class, java.util.zip.Deflater.class}
+ )
+ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_Deflater()
+ throws Exception {
+ byte byteArray[] = {1, 3, 4, 7, 8};
+ File f1 = new File("hyts_Constru_OD.tst");
+ FileOutputStream fos = new FileOutputStream(f1);
+ Deflater defl = null;
+ MyDeflaterOutputStream dos;
+ // Test for a null Deflater.
+ try {
+ dos = new MyDeflaterOutputStream(fos, defl);
+ fail("NullPointerException Not Thrown");
+ } catch (NullPointerException e) {
+ }
+ defl = new Deflater();
+ dos = new MyDeflaterOutputStream(fos, defl);
+
+ // Test to see if DeflaterOutputStream was created with the correct
+ // buffer.
+ assertEquals("Incorrect Buffer Size", 512, dos.getProtectedBuf().length);
+
+ dos.write(byteArray);
+ dos.close();
+ f1.delete();
+ }
+
+ /**
+ * @tests java.util.zip.DeflaterOutputStream#DeflaterOutputStream(java.io.OutputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "DeflaterOutputStream",
+ args = {java.io.OutputStream.class}
+ )
+ public void test_ConstructorLjava_io_OutputStream() throws Exception {
+ File f1 = new File("hyts_Constru_O.tst");
+ FileOutputStream fos = new FileOutputStream(f1);
+ MyDeflaterOutputStream dos = new MyDeflaterOutputStream(fos);
+
+ // Test to see if DeflaterOutputStream was created with the correct
+ // buffer.
+ assertEquals("Incorrect Buffer Size", 512, dos.getProtectedBuf().length);
+
+ dos.write(outPutBuf);
+ dos.close();
+ f1.delete();
+ }
+
+ /**
+ * @tests java.util.zip.DeflaterOutputStream#DeflaterOutputStream(java.io.OutputStream,
+ * java.util.zip.Deflater, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "DeflaterOutputStream",
+ args = {java.io.OutputStream.class, java.util.zip.Deflater.class, int.class}
+ )
+ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_DeflaterI()
+ throws Exception {
+ int buf = 5;
+ int negBuf = -5;
+ int zeroBuf = 0;
+ byte byteArray[] = {1, 3, 4, 7, 8, 3, 6};
+ File f1 = new File("hyts_Constru_ODI.tst");
+ FileOutputStream fos = new FileOutputStream(f1);
+ Deflater defl = null;
+ MyDeflaterOutputStream dos;
+
+ // Test for a null Deflater.
+ try {
+ dos = new MyDeflaterOutputStream(fos, defl, buf);
+ fail("NullPointerException Not Thrown");
+ } catch (NullPointerException e) {
+ }
+ defl = new Deflater();
+
+ // Test for a negative buf.
+ try {
+ dos = new MyDeflaterOutputStream(fos, defl, negBuf);
+ fail("IllegalArgumentException Not Thrown");
+ } catch (IllegalArgumentException e) {
+ }
+
+ // Test for a zero buf.
+ try {
+ dos = new MyDeflaterOutputStream(fos, defl, zeroBuf);
+ fail("IllegalArgumentException Not Thrown");
+ } catch (IllegalArgumentException e) {
+ }
+
+ // Test to see if DeflaterOutputStream was created with the correct
+ // buffer.
+ dos = new MyDeflaterOutputStream(fos, defl, buf);
+ assertEquals("Incorrect Buffer Size", 5, dos.getProtectedBuf().length);
+
+ dos.write(byteArray);
+ dos.close();
+ f1.delete();
+ }
+
+ /**
+ * @tests java.util.zip.DeflaterOutputStream#close()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "IOException can not be checked.",
+ method = "close",
+ args = {}
+ )
+ public void test_close() throws Exception {
+ File f1 = new File("close.tst");
+ FileOutputStream fos = new FileOutputStream(f1);
+ DeflaterOutputStream dos = new DeflaterOutputStream(fos);
+ byte byteArray[] = {1, 3, 4, 6};
+ dos.write(byteArray);
+
+ FileInputStream fis = new FileInputStream(f1);
+ InflaterInputStream iis = new InflaterInputStream(fis);
+ try {
+ iis.read();
+ fail("EOFException Not Thrown");
+ } catch (EOFException e) {
+ }
+
+ dos.close();
+
+ // Test to see if the finish method wrote the bytes to the file.
+ assertEquals("Incorrect Byte Returned.", 1, iis.read());
+ assertEquals("Incorrect Byte Returned.", 3, iis.read());
+ assertEquals("Incorrect Byte Returned.", 4, iis.read());
+ assertEquals("Incorrect Byte Returned.", 6, iis.read());
+ assertEquals("Incorrect Byte Returned.", -1, iis.read());
+ assertEquals("Incorrect Byte Returned.", -1, iis.read());
+ iis.close();
+
+ // Not sure if this test will stay.
+ FileOutputStream fos2 = new FileOutputStream(f1);
+ DeflaterOutputStream dos2 = new DeflaterOutputStream(fos2);
+ fos2.close();
+ try {
+ dos2.close();
+ fail("IOException not thrown");
+ } catch (IOException e) {
+ }
+
+ // Test to write to a closed DeflaterOutputStream
+ try {
+ dos.write(5);
+ fail("DeflaterOutputStream Able To Write After Being Closed.");
+ } catch (IOException e) {
+ }
+
+ // Test to write to a FileOutputStream that should have been closed
+ // by
+ // the DeflaterOutputStream.
+ try {
+ fos.write(("testing").getBytes());
+ fail("FileOutputStream Able To Write After Being Closed.");
+ } catch (IOException e) {
+ }
+
+ f1.delete();
+ }
+
+ /**
+ * @tests java.util.zip.DeflaterOutputStream#finish()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "finish",
+ args = {}
+ )
+ public void test_finish() throws Exception {
+ // Need test to see if method finish() actually finishes
+ // Only testing possible errors, not if it actually works
+
+ File f1 = new File("finish.tst");
+ FileOutputStream fos1 = new FileOutputStream(f1);
+ DeflaterOutputStream dos = new DeflaterOutputStream(fos1);
+ byte byteArray[] = {1, 3, 4, 6};
+ dos.write(byteArray);
+ dos.finish();
+
+ // Test to see if the same FileOutputStream can be used with the
+ // DeflaterOutputStream after finish is called.
+ try {
+ dos.write(1);
+ fail("IOException not thrown");
+ } catch (IOException e) {
+ }
+
+ // Test for writing with a new FileOutputStream using the same
+ // DeflaterOutputStream.
+ FileOutputStream fos2 = new FileOutputStream(f1);
+ dos = new DeflaterOutputStream(fos2);
+ dos.write(1);
+
+ // Test for writing to FileOutputStream fos1, which should be open.
+ fos1.write(("testing").getBytes());
+
+ // Test for writing to FileOutputStream fos2, which should be open.
+ fos2.write(("testing").getBytes());
+
+ // Not sure if this test will stay.
+ FileOutputStream fos3 = new FileOutputStream(f1);
+ DeflaterOutputStream dos3 = new DeflaterOutputStream(fos3);
+ fos3.close();
+ try {
+ dos3.finish();
+ fail("IOException not thrown");
+ } catch (IOException e) {
+ }
+
+ // dos.close() won't close fos1 because it has been re-assigned to
+ // fos2
+ fos1.close();
+ dos.close();
+ f1.delete();
+ }
+
+ /**
+ * @tests java.util.zip.DeflaterOutputStream#write(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "write",
+ args = {int.class}
+ )
+ public void test_writeI() throws Exception {
+ File f1 = new File("writeI1.tst");
+ FileOutputStream fos = new FileOutputStream(f1);
+ DeflaterOutputStream dos = new DeflaterOutputStream(fos);
+ for (int i = 0; i < 3; i++) {
+ dos.write(i);
+ }
+ dos.close();
+ FileInputStream fis = new FileInputStream(f1);
+ InflaterInputStream iis = new InflaterInputStream(fis);
+ for (int i = 0; i < 3; i++) {
+ assertEquals("Incorrect Byte Returned.", i, iis.read());
+ }
+ assertEquals("Incorrect Byte Returned (EOF).", -1, iis.read());
+ assertEquals("Incorrect Byte Returned (EOF).", -1, iis.read());
+ iis.close();
+
+ // Not sure if this test is that important.
+ // Checks to see if you can write using the DeflaterOutputStream
+ // after
+ // the FileOutputStream has been closed.
+ FileOutputStream fos2 = new FileOutputStream(f1);
+ DeflaterOutputStream dos2 = new DeflaterOutputStream(fos2);
+ fos2.close();
+ try {
+ dos2.write(2);
+ fail("IOException not thrown");
+ } catch (IOException e) {
+ }
+
+ f1.delete();
+ }
+
+ /**
+ * @tests java.util.zip.DeflaterOutputStream#write(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "write",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_write$BII() throws Exception {
+ byte byteArray[] = {1, 3, 4, 7, 8, 3, 6};
+
+ // Test to see if the correct bytes are saved.
+ File f1 = new File("writeBII.tst");
+ FileOutputStream fos1 = new FileOutputStream(f1);
+ DeflaterOutputStream dos1 = new DeflaterOutputStream(fos1);
+ dos1.write(byteArray, 2, 3);
+ dos1.close();
+ FileInputStream fis = new FileInputStream(f1);
+ InflaterInputStream iis = new InflaterInputStream(fis);
+ assertEquals("Incorrect Byte Returned.", 4, iis.read());
+ assertEquals("Incorrect Byte Returned.", 7, iis.read());
+ assertEquals("Incorrect Byte Returned.", 8, iis.read());
+ assertEquals("Incorrect Byte Returned (EOF).", -1, iis.read());
+ assertEquals("Incorrect Byte Returned (EOF).", -1, iis.read());
+ iis.close();
+ f1.delete();
+
+ // Test for trying to write more bytes than available from the array
+ File f2 = new File("writeBII2.tst");
+ FileOutputStream fos2 = new FileOutputStream(f2);
+ DeflaterOutputStream dos2 = new DeflaterOutputStream(fos2);
+ try {
+ dos2.write(byteArray, 2, 10);
+ fail("IndexOutOfBoundsException not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // Test for trying to write a negative number of bytes.
+ try {
+ dos2.write(byteArray, 2, Integer.MIN_VALUE);
+ fail("IndexOutOfBoundsException not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // Test for trying to start writing from a byte < 0 from the array.
+ try {
+ dos2.write(byteArray, Integer.MIN_VALUE, 2);
+ fail("IndexOutOfBoundsException not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // Test for trying to start writing from a byte > than the array
+ // size.
+ try {
+ dos2.write(byteArray, 10, 2);
+ fail("IndexOutOfBoundsException not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ dos2.close();
+
+ // Not sure if this test is that important.
+ // Checks to see if you can write using the DeflaterOutputStream
+ // after
+ // the FileOutputStream has been closed.
+ FileOutputStream fos3 = new FileOutputStream(f2);
+ DeflaterOutputStream dos3 = new DeflaterOutputStream(fos3);
+ fos3.close();
+ try {
+ dos3.write(byteArray, 2, 3);
+ fail("IOException not thrown");
+ } catch (IOException e) {
+ }
+
+ f2.delete();
+ }
+
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "deflate",
+ args = {}
+ )
+ public void test_deflate() throws Exception {
+ File f1 = new File("writeI1.tst");
+ FileOutputStream fos = new FileOutputStream(f1);
+ MyDeflaterOutputStream dos = new MyDeflaterOutputStream(fos);
+ assertFalse(dos.getDaflateFlag());
+ for (int i = 0; i < 3; i++) {
+ dos.write(i);
+ }
+ assertTrue(dos.getDaflateFlag());
+ dos.close();
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterTest.java
new file mode 100644
index 0000000..ae77450
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterTest.java
@@ -0,0 +1,1243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.zip.Adler32;
+
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import junit.framework.TestCase;
+import tests.support.resource.Support_Resources;
+
+@TestTargetClass(Deflater.class)
+public class DeflaterTest extends TestCase {
+
+ class MyDeflater extends Deflater {
+ MyDeflater() {
+ super();
+ }
+
+ MyDeflater(int lvl) {
+ super(lvl);
+ }
+
+ MyDeflater(int lvl, boolean noHeader) {
+ super(lvl, noHeader);
+ }
+
+ void myFinalize() {
+ finalize();
+ }
+
+ int getDefCompression() {
+ return DEFAULT_COMPRESSION;
+ }
+
+ int getDefStrategy() {
+ return DEFAULT_STRATEGY;
+ }
+
+ int getHuffman() {
+ return HUFFMAN_ONLY;
+ }
+
+ int getFiltered() {
+ return FILTERED;
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#deflate(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "deflate",
+ args = {byte[].class}
+ )
+ public void test_deflate$B() {
+ byte outPutBuf[] = new byte[50];
+ byte byteArray[] = {1, 3, 4, 7, 8};
+ byte outPutInf[] = new byte[50];
+ int x = 0;
+
+ Deflater defl = new Deflater();
+ defl.setInput(byteArray);
+ defl.finish();
+ while (!defl.finished()) {
+ x += defl.deflate(outPutBuf);
+ }
+ assertEquals("Deflater at end of stream, should return 0", 0, defl
+ .deflate(outPutBuf));
+ int totalOut = defl.getTotalOut();
+ int totalIn = defl.getTotalIn();
+ assertEquals(x, totalOut);
+ assertEquals(byteArray.length, totalIn);
+ defl.end();
+
+ Inflater infl = new Inflater();
+ try {
+ infl.setInput(outPutBuf);
+ while (!infl.finished()) {
+ infl.inflate(outPutInf);
+ }
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ }
+ assertEquals(totalIn, infl.getTotalOut());
+ assertEquals(totalOut, infl.getTotalIn());
+ for (int i = 0; i < byteArray.length; i++) {
+ assertEquals(byteArray[i], outPutInf[i]);
+ }
+ assertEquals(
+ "Final decompressed data contained more bytes than original",
+ 0, outPutInf[byteArray.length]);
+ infl.end();
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#deflate(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "deflate",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_deflate$BII() {
+ byte outPutBuf[] = new byte[50];
+ byte byteArray[] = {5, 2, 3, 7, 8};
+ byte outPutInf[] = new byte[50];
+ int offSet = 1;
+ int length = outPutBuf.length - 1;
+ int x = 0;
+
+ Deflater defl = new Deflater();
+ defl.setInput(byteArray);
+ defl.finish();
+ while (!defl.finished()) {
+ x += defl.deflate(outPutBuf, offSet, length);
+ }
+ assertEquals("Deflater at end of stream, should return 0", 0, defl
+ .deflate(outPutBuf, offSet, length));
+ int totalOut = defl.getTotalOut();
+ int totalIn = defl.getTotalIn();
+ assertEquals(x, totalOut);
+ assertEquals(byteArray.length, totalIn);
+ defl.end();
+
+ Inflater infl = new Inflater();
+ try {
+ infl.setInput(outPutBuf, offSet, length);
+ while (!infl.finished()) {
+ infl.inflate(outPutInf);
+ }
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ }
+ assertEquals(totalIn, infl.getTotalOut());
+ assertEquals(totalOut, infl.getTotalIn());
+ for (int i = 0; i < byteArray.length; i++) {
+ assertEquals(byteArray[i], outPutInf[i]);
+ }
+ assertEquals(
+ "Final decompressed data contained more bytes than original",
+ 0, outPutInf[byteArray.length]);
+ infl.end();
+
+ // Set of tests testing the boundaries of the offSet/length
+ defl = new Deflater();
+ outPutBuf = new byte[100];
+ defl.setInput(byteArray);
+ for (int i = 0; i < 2; i++) {
+ if (i == 0) {
+ offSet = outPutBuf.length + 1;
+ length = outPutBuf.length;
+ } else {
+ offSet = 0;
+ length = outPutBuf.length + 1;
+ }
+ try {
+ defl.deflate(outPutBuf, offSet, length);
+ fail("Test " + i
+ + ": ArrayIndexOutOfBoundsException not thrown");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ }
+ defl.end();
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#end()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "end",
+ args = {}
+ )
+ public void test_end() {
+ byte byteArray[] = {5, 2, 3, 7, 8};
+ byte outPutBuf[] = new byte[100];
+
+ Deflater defl = new Deflater();
+ defl.setInput(byteArray);
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.end();
+ helper_end_test(defl, "end");
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#finalize()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "finalize",
+ args = {}
+ )
+ public void test_finalize() {
+ MyDeflater mdefl = new MyDeflater();
+ mdefl.myFinalize();
+ System.gc();
+ helper_end_test(mdefl, "finalize");
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#finish()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "finish",
+ args = {}
+ )
+ public void test_finish() throws Exception {
+ // This test already here, its the same as test_deflate()
+ byte byteArray[] = {5, 2, 3, 7, 8};
+ byte outPutBuf[] = new byte[100];
+ byte outPutInf[] = new byte[100];
+ int x = 0;
+ Deflater defl = new Deflater();
+ defl.setInput(byteArray);
+ defl.finish();
+
+ // needsInput should never return true after finish() is called
+ if (System.getProperty("java.vendor").startsWith("IBM")) {
+ assertFalse(
+ "needsInput() should return false after finish() is called",
+ defl.needsInput());
+ }
+
+ while (!defl.finished()) {
+ x += defl.deflate(outPutBuf);
+ }
+ int totalOut = defl.getTotalOut();
+ int totalIn = defl.getTotalIn();
+ assertEquals(x, totalOut);
+ assertEquals(byteArray.length, totalIn);
+ defl.end();
+
+ Inflater infl = new Inflater();
+ infl.setInput(outPutBuf);
+ while (!infl.finished()) {
+ infl.inflate(outPutInf);
+ }
+ assertEquals(totalIn, infl.getTotalOut());
+ assertEquals(totalOut, infl.getTotalIn());
+ for (int i = 0; i < byteArray.length; i++) {
+ assertEquals(byteArray[i], outPutInf[i]);
+ }
+ assertEquals(
+ "Final decompressed data contained more bytes than original",
+ 0, outPutInf[byteArray.length]);
+ infl.end();
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#finished()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "finished",
+ args = {}
+ )
+ public void test_finished() {
+ byte byteArray[] = {5, 2, 3, 7, 8};
+ byte outPutBuf[] = new byte[100];
+ Deflater defl = new Deflater();
+ assertTrue("Test 1: Deflater should not be finished.", !defl.finished());
+ defl.setInput(byteArray);
+ assertTrue("Test 2: Deflater should not be finished.", !defl.finished());
+ defl.finish();
+ assertTrue("Test 3: Deflater should not be finished.", !defl.finished());
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ assertTrue("Test 4: Deflater should be finished.", defl.finished());
+ defl.end();
+ assertTrue("Test 5: Deflater should be finished.", defl.finished());
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#getAdler()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getAdler",
+ args = {}
+ )
+ public void test_getAdler() {
+ byte byteArray[] = {'a', 'b', 'c', 1, 2, 3};
+ byte outPutBuf[] = new byte[100];
+ Deflater defl = new Deflater();
+
+ // getting the checkSum value using the Adler
+ defl.setInput(byteArray);
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ long checkSumD = defl.getAdler();
+ defl.end();
+
+ // getting the checkSum value through the Adler32 class
+ Adler32 adl = new Adler32();
+ adl.update(byteArray);
+ long checkSumR = adl.getValue();
+ assertEquals(
+ "The checksum value returned by getAdler() is not the same as the checksum returned by creating the adler32 instance",
+ checkSumD, checkSumR);
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#getTotalIn()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getTotalIn",
+ args = {}
+ )
+ public void test_getTotalIn() {
+ byte outPutBuf[] = new byte[5];
+ byte byteArray[] = {1, 3, 4, 7, 8};
+
+ Deflater defl = new Deflater();
+ defl.setInput(byteArray);
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ assertEquals(byteArray.length, defl.getTotalIn());
+ defl.end();
+
+ defl = new Deflater();
+ int offSet = 2;
+ int length = 3;
+ outPutBuf = new byte[5];
+ defl.setInput(byteArray, offSet, length);
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ assertEquals(length, defl.getTotalIn());
+ defl.end();
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#getTotalOut()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getTotalOut",
+ args = {}
+ )
+ public void test_getTotalOut() {
+ // the getTotalOut should equal the sum of value returned by deflate()
+ byte outPutBuf[] = new byte[5];
+ byte byteArray[] = {5, 2, 3, 7, 8};
+ int x = 0;
+ Deflater defl = new Deflater();
+ defl.setInput(byteArray);
+ defl.finish();
+ while (!defl.finished()) {
+ x += defl.deflate(outPutBuf);
+ }
+ assertEquals(x, defl.getTotalOut());
+ defl.end();
+
+ x = 0;
+ int offSet = 2;
+ int length = 3;
+ defl = new Deflater();
+ outPutBuf = new byte[5];
+ defl.setInput(byteArray, offSet, length);
+ defl.finish();
+ while (!defl.finished()) {
+ x += defl.deflate(outPutBuf);
+ }
+ assertEquals(x, defl.getTotalOut());
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#needsInput()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "needsInput",
+ args = {}
+ )
+ public void test_needsInput() {
+ Deflater defl = new Deflater();
+ assertTrue(
+ "needsInput give the wrong boolean value as a result of no input buffer",
+ defl.needsInput());
+ byte byteArray[] = {1, 2, 3};
+ defl.setInput(byteArray);
+ assertFalse(
+ "needsInput give wrong boolean value as a result of a full input buffer",
+ defl.needsInput());
+ byte[] outPutBuf = new byte[50];
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ byte emptyByteArray[] = new byte[0];
+ defl.setInput(emptyByteArray);
+ assertTrue(
+ "needsInput give wrong boolean value as a result of an empty input buffer",
+ defl.needsInput());
+ defl.setInput(byteArray);
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ // needsInput should NOT return true after finish() has been
+ // called.
+ if (System.getProperty("java.vendor").startsWith("IBM")) {
+ assertFalse(
+ "needsInput gave wrong boolean value as a result of finish() being called",
+ defl.needsInput());
+ }
+ defl.end();
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#reset()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "reset",
+ args = {}
+ )
+ public void test_reset() {
+ byte outPutBuf[] = new byte[100];
+ byte outPutInf[] = new byte[100];
+ byte curArray[] = new byte[5];
+ byte byteArray[] = {1, 3, 4, 7, 8};
+ byte byteArray2[] = {8, 7, 4, 3, 1};
+ int x = 0;
+ int orgValue = 0;
+ Deflater defl = new Deflater();
+
+ for (int i = 0; i < 3; i++) {
+ if (i == 0) {
+ curArray = byteArray;
+ } else if (i == 1) {
+ curArray = byteArray2;
+ } else {
+ defl.reset();
+ }
+
+ defl.setInput(curArray);
+ defl.finish();
+ while (!defl.finished()) {
+ x += defl.deflate(outPutBuf);
+ }
+
+ if (i == 0) {
+ assertEquals(x, defl.getTotalOut());
+ } else if (i == 1) {
+ assertEquals(x, orgValue);
+ } else {
+ assertEquals(x, orgValue * 2);
+ }
+
+ if (i == 0) {
+ orgValue = x;
+ }
+
+ try {
+ Inflater infl = new Inflater();
+ infl.setInput(outPutBuf);
+ while (!infl.finished()) {
+ infl.inflate(outPutInf);
+ }
+ infl.end();
+ } catch (DataFormatException e) {
+ fail("Test " + i + ": Invalid input to be decompressed");
+ }
+
+ if (i == 1) {
+ curArray = byteArray;
+ }
+
+ for (int j = 0; j < curArray.length; j++) {
+ assertEquals(curArray[j], outPutInf[j]);
+ }
+ assertEquals(0, outPutInf[curArray.length]);
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#setDictionary(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setDictionary",
+ args = {byte[].class}
+ )
+ public void test_setDictionary$B() {
+ // This test is very close to getAdler()
+ byte dictionaryArray[] = {'e', 'r', 't', 'a', 'b', 2, 3};
+ byte byteArray[] = {
+ 4, 5, 3, 2, 'a', 'b', 6, 7, 8, 9, 0, 's', '3', 'w', 'r'};
+ byte outPutBuf[] = new byte[100];
+
+ Deflater defl = new Deflater();
+ long deflAdler = defl.getAdler();
+ assertEquals(
+ "No dictionary set, no data deflated, getAdler should return 1",
+ 1, deflAdler);
+ defl.setDictionary(dictionaryArray);
+ deflAdler = defl.getAdler();
+
+ // getting the checkSum value through the Adler32 class
+ Adler32 adl = new Adler32();
+ adl.update(dictionaryArray);
+ long realAdler = adl.getValue();
+ assertEquals(deflAdler, realAdler);
+
+ defl.setInput(byteArray);
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ deflAdler = defl.getAdler();
+ adl = new Adler32();
+ adl.update(byteArray);
+ realAdler = adl.getValue();
+ // Deflate is finished and there were bytes deflated that did not occur
+ // in the dictionaryArray, therefore a new dictionary was automatically
+ // set.
+ assertEquals(realAdler, deflAdler);
+ defl.end();
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#setDictionary(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setDictionary",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_setDictionary$BII() {
+ // This test is very close to getAdler()
+ byte dictionaryArray[] = {'e', 'r', 't', 'a', 'b', 2, 3, 'o', 't'};
+ byte byteArray[] = {
+ 4, 5, 3, 2, 'a', 'b', 6, 7, 8, 9, 0, 's', '3', 'w', 'r', 't',
+ 'u', 'i', 'o', 4, 5, 6, 7};
+ byte outPutBuf[] = new byte[500];
+
+ int offSet = 4;
+ int length = 5;
+
+ Deflater defl = new Deflater();
+ long deflAdler = defl.getAdler();
+ assertEquals(
+ "No dictionary set, no data deflated, getAdler should return 1",
+ 1, deflAdler);
+ defl.setDictionary(dictionaryArray, offSet, length);
+ deflAdler = defl.getAdler();
+
+ // getting the checkSum value through the Adler32 class
+ Adler32 adl = new Adler32();
+ adl.update(dictionaryArray, offSet, length);
+ long realAdler = adl.getValue();
+ assertEquals(deflAdler, realAdler);
+
+ defl.setInput(byteArray);
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ deflAdler = defl.getAdler();
+ adl = new Adler32();
+ adl.update(byteArray);
+ realAdler = adl.getValue();
+ // Deflate is finished and there were bytes deflated that did not occur
+ // in the dictionaryArray, therefore a new dictionary was automatically
+ // set.
+ assertEquals(realAdler, deflAdler);
+ defl.end();
+
+ // boundary check
+ defl = new Deflater();
+ for (int i = 0; i < 2; i++) {
+ if (i == 0) {
+ offSet = 0;
+ length = dictionaryArray.length + 1;
+ } else {
+ offSet = dictionaryArray.length + 1;
+ length = 1;
+ }
+ try {
+ defl.setDictionary(dictionaryArray, offSet, length);
+ fail("Test "
+ + i
+ + ": boundary check for setDictionary failed for offset "
+ + offSet + " and length " + length);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#setInput(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setInput",
+ args = {byte[].class}
+ )
+ public void test_setInput$B() {
+ byte[] byteArray = {1, 2, 3};
+ byte[] outPutBuf = new byte[50];
+ byte[] outPutInf = new byte[50];
+
+ Deflater defl = new Deflater();
+ defl.setInput(byteArray);
+ assertTrue("the array buffer in setInput() is empty", !defl
+ .needsInput());
+ // The second setInput() should be ignored since needsInput() return
+ // false
+ defl.setInput(byteArray);
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.end();
+
+ Inflater infl = new Inflater();
+ try {
+ infl.setInput(outPutBuf);
+ while (!infl.finished()) {
+ infl.inflate(outPutInf);
+ }
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ }
+ for (int i = 0; i < byteArray.length; i++) {
+ assertEquals(byteArray[i], outPutInf[i]);
+ }
+ assertEquals(byteArray.length, infl.getTotalOut());
+ infl.end();
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#setInput(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setInput",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_setInput$BII() throws Exception {
+ byte[] byteArray = {1, 2, 3, 4, 5};
+ byte[] outPutBuf = new byte[50];
+ byte[] outPutInf = new byte[50];
+ int offSet = 1;
+ int length = 3;
+
+ Deflater defl = new Deflater();
+ defl.setInput(byteArray, offSet, length);
+ assertFalse("the array buffer in setInput() is empty", defl
+ .needsInput());
+ // The second setInput() should be ignored since needsInput() return
+ // false
+ defl.setInput(byteArray, offSet, length);
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.end();
+
+ Inflater infl = new Inflater();
+ infl.setInput(outPutBuf);
+ while (!infl.finished()) {
+ infl.inflate(outPutInf);
+ }
+ for (int i = 0; i < length; i++) {
+ assertEquals(byteArray[i + offSet], outPutInf[i]);
+ }
+ assertEquals(length, infl.getTotalOut());
+ infl.end();
+
+ // boundary check
+ defl = new Deflater();
+ for (int i = 0; i < 2; i++) {
+ if (i == 0) {
+ offSet = 0;
+ length = byteArray.length + 1;
+ } else {
+ offSet = byteArray.length + 1;
+ length = 1;
+ }
+ try {
+ defl.setInput(byteArray, offSet, length);
+ fail("Test " + i
+ + ": boundary check for setInput failed for offset "
+ + offSet + " and length " + length);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#setLevel(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setLevel",
+ args = {int.class}
+ )
+ public void test_setLevelI() throws Exception {
+ // Very similar to test_Constructor(int)
+ byte[] byteArray = new byte[100];
+ InputStream inFile = Support_Resources.getStream("hyts_checkInput.txt");
+ inFile.read(byteArray);
+ inFile.close();
+
+ byte[] outPutBuf;
+ int totalOut;
+ for (int i = 0; i < 10; i++) {
+ Deflater defl = new Deflater();
+ defl.setLevel(i);
+ outPutBuf = new byte[500];
+ defl.setInput(byteArray);
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ totalOut = defl.getTotalOut();
+ defl.end();
+
+ outPutBuf = new byte[500];
+ defl = new Deflater(i);
+ defl.setInput(byteArray);
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ assertEquals(totalOut, defl.getTotalOut());
+ defl.end();
+ }
+
+ // testing boundaries
+ try {
+ Deflater boundDefl = new Deflater();
+ // Level must be between 0-9
+ boundDefl.setLevel(-2);
+ fail("IllegalArgumentException not thrown when setting level to a number < 0.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ Deflater boundDefl = new Deflater();
+ boundDefl.setLevel(10);
+ fail("IllegalArgumentException not thrown when setting level to a number > 9.");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#setStrategy(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setStrategy",
+ args = {int.class}
+ )
+ public void test_setStrategyI() throws Exception {
+ byte[] byteArray = new byte[100];
+ InputStream inFile = Support_Resources.getStream("hyts_checkInput.txt");
+ inFile.read(byteArray);
+ inFile.close();
+
+ for (int i = 0; i < 3; i++) {
+ byte outPutBuf[] = new byte[500];
+ MyDeflater mdefl = new MyDeflater();
+
+ if (i == 0) {
+ mdefl.setStrategy(mdefl.getDefStrategy());
+ } else if (i == 1) {
+ mdefl.setStrategy(mdefl.getHuffman());
+ } else {
+ mdefl.setStrategy(mdefl.getFiltered());
+ }
+
+ mdefl.setInput(byteArray);
+ while (!mdefl.needsInput()) {
+ mdefl.deflate(outPutBuf);
+ }
+ mdefl.finish();
+ while (!mdefl.finished()) {
+ mdefl.deflate(outPutBuf);
+ }
+
+ if (i == 0) {
+ // System.out.println(mdefl.getTotalOut());
+ // ran JDK and found that getTotalOut() = 86 for this particular
+ // file
+ assertEquals(
+ "getTotalOut() for the default strategy did not correspond with JDK",
+ 86, mdefl.getTotalOut());
+ } else if (i == 1) {
+ // System.out.println(mdefl.getTotalOut());
+ // ran JDK and found that getTotalOut() = 100 for this
+ // particular file
+ assertEquals(
+ "getTotalOut() for the Huffman strategy did not correspond with JDK",
+ 100, mdefl.getTotalOut());
+ } else {
+ // System.out.println(mdefl.getTotalOut());
+ // ran JDK and found that totalOut = 93 for this particular file
+ assertEquals(
+ "Total Out for the Filtered strategy did not correspond with JDK",
+ 93, mdefl.getTotalOut());
+ }
+ mdefl.end();
+ }
+
+ // Attempting to setStrategy to an invalid value
+ try {
+ Deflater defl = new Deflater();
+ defl.setStrategy(-412);
+ fail("IllegalArgumentException not thrown when setting strategy to an invalid value.");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#Deflater()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Deflater",
+ args = {}
+ )
+ public void test_Constructor() throws Exception {
+ byte[] byteArray = new byte[100];
+ InputStream inFile = Support_Resources.getStream("hyts_checkInput.txt");
+ inFile.read(byteArray);
+ inFile.close();
+
+ Deflater defl = new Deflater();
+ byte[] outPutBuf = new byte[500];
+ defl.setInput(byteArray);
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ int totalOut = defl.getTotalOut();
+ defl.end();
+
+ // creating a Deflater using the DEFAULT_COMPRESSION as the int
+ MyDeflater mdefl = new MyDeflater();
+ mdefl = new MyDeflater(mdefl.getDefCompression());
+ outPutBuf = new byte[500];
+ mdefl.setInput(byteArray);
+ while (!mdefl.needsInput()) {
+ mdefl.deflate(outPutBuf);
+ }
+ mdefl.finish();
+ while (!mdefl.finished()) {
+ mdefl.deflate(outPutBuf);
+ }
+ assertEquals(totalOut, mdefl.getTotalOut());
+ mdefl.end();
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#Deflater(int, boolean)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Deflater",
+ args = {int.class, boolean.class}
+ )
+ public void test_ConstructorIZ() throws Exception {
+ byte byteArray[] = {
+ 4, 5, 3, 2, 'a', 'b', 6, 7, 8, 9, 0, 's', '3', 'w', 'r'};
+
+ Deflater defl = new Deflater();
+ byte outPutBuf[] = new byte[500];
+ defl.setLevel(2);
+ defl.setInput(byteArray);
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ int totalOut = defl.getTotalOut();
+ defl.end();
+
+ outPutBuf = new byte[500];
+ defl = new Deflater(2, false);
+ defl.setInput(byteArray);
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ assertEquals(totalOut, defl.getTotalOut());
+ defl.end();
+
+ outPutBuf = new byte[500];
+ defl = new Deflater(2, true);
+ defl.setInput(byteArray);
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ assertTrue(
+ "getTotalOut() should not be equal comparing two Deflaters with different header options.",
+ defl.getTotalOut() != totalOut);
+ defl.end();
+
+ byte outPutInf[] = new byte[500];
+ Inflater infl = new Inflater(true);
+ while (!infl.finished()) {
+ if (infl.needsInput()) {
+ infl.setInput(outPutBuf);
+ }
+ infl.inflate(outPutInf);
+ }
+ for (int i = 0; i < byteArray.length; i++) {
+ assertEquals(byteArray[i], outPutInf[i]);
+ }
+ assertEquals(
+ "final decompressed data contained more bytes than original - constructorIZ",
+ 0, outPutInf[byteArray.length]);
+ infl.end();
+
+ infl = new Inflater(false);
+ outPutInf = new byte[500];
+ int r = 0;
+ try {
+ while (!infl.finished()) {
+ if (infl.needsInput()) {
+ infl.setInput(outPutBuf);
+ }
+ infl.inflate(outPutInf);
+ }
+ } catch (DataFormatException e) {
+ r = 1;
+ }
+ assertEquals("header option did not correspond", 1, r);
+
+ // testing boundaries
+ try {
+ Deflater boundDefl = new Deflater();
+ // Level must be between 0-9
+ boundDefl.setLevel(-2);
+ fail("IllegalArgumentException not thrown when setting level to a number < 0.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ Deflater boundDefl = new Deflater();
+ boundDefl.setLevel(10);
+ fail("IllegalArgumentException not thrown when setting level to a number > 9.");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#Deflater(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Deflater",
+ args = {int.class}
+ )
+ public void test_ConstructorI() throws Exception {
+ byte[] byteArray = new byte[100];
+ InputStream inFile = Support_Resources.getStream("hyts_checkInput.txt");
+ inFile.read(byteArray);
+ inFile.close();
+
+ byte outPutBuf[] = new byte[500];
+ Deflater defl = new Deflater(3);
+ defl.setInput(byteArray);
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ int totalOut = defl.getTotalOut();
+ defl.end();
+
+ // test to see if the compression ratio is the same as setting the level
+ // on a deflater
+ outPutBuf = new byte[500];
+ defl = new Deflater();
+ defl.setLevel(3);
+ defl.setInput(byteArray);
+ while (!defl.needsInput()) {
+ defl.deflate(outPutBuf);
+ }
+ defl.finish();
+ while (!defl.finished()) {
+ defl.deflate(outPutBuf);
+ }
+ assertEquals(totalOut, defl.getTotalOut());
+ defl.end();
+
+ // testing boundaries
+ try {
+ Deflater boundDefl = new Deflater();
+ // Level must be between 0-9
+ boundDefl.setLevel(-2);
+ fail("IllegalArgumentException not thrown when setting level to a number < 0.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ Deflater boundDefl = new Deflater();
+ boundDefl.setLevel(10);
+ fail("IllegalArgumentException not thrown when setting level to a number > 9.");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ private void helper_end_test(Deflater defl, String desc) {
+ // Help tests for test_end() and test_reset().
+ byte byteArray[] = {5, 2, 3, 7, 8};
+
+ // Methods where we expect IllegalStateException or NullPointerException
+ // to be thrown
+ try {
+ defl.getTotalOut();
+ fail("defl.getTotalOut() can still be used after " + desc
+ + " is called in test_" + desc);
+ } catch (IllegalStateException e) {
+ } catch (NullPointerException e) {
+ }
+ try {
+ defl.getTotalIn();
+ fail("defl.getTotalIn() can still be used after " + desc
+ + " is called in test_" + desc);
+ } catch (IllegalStateException e) {
+ } catch (NullPointerException e) {
+ }
+ try {
+ defl.getAdler();
+ fail("defl.getAdler() can still be used after " + desc
+ + " is called in test_" + desc);
+ } catch (IllegalStateException e) {
+ } catch (NullPointerException e) {
+ }
+ try {
+ byte[] dict = {'a', 'b', 'c'};
+ defl.setDictionary(dict);
+ fail("defl.setDictionary() can still be used after " + desc
+ + " is called in test_" + desc);
+ } catch (IllegalStateException e) {
+ } catch (NullPointerException e) {
+ }
+ try {
+ defl.getTotalIn();
+ fail("defl.getTotalIn() can still be used after " + desc
+ + " is called in test_" + desc);
+ } catch (IllegalStateException e) {
+ } catch (NullPointerException e) {
+ }
+ try {
+ defl.getTotalIn();
+ fail("defl.getTotalIn() can still be used after " + desc
+ + " is called in test_" + desc);
+ } catch (IllegalStateException e) {
+ } catch (NullPointerException e) {
+ }
+ try {
+ defl.deflate(byteArray);
+ fail("defl.deflate() can still be used after " + desc
+ + " is called in test_" + desc);
+ } catch (IllegalStateException e) {
+ } catch (NullPointerException e) {
+ }
+
+ // Methods where we expect NullPointerException to be thrown
+ try {
+ defl.reset();
+ fail("defl.reset() can still be used after " + desc
+ + " is called in test_" + desc);
+ } catch (NullPointerException e) {
+ }
+
+ // Methods that should be allowed to be called after end() is called
+ defl.needsInput();
+ defl.setStrategy(1);
+ defl.setLevel(1);
+ defl.end();
+
+ // Methods where exceptions should be thrown
+ String vendor = System.getProperty("java.vendor");
+ if (vendor.indexOf("IBM") != -1) {
+ try {
+ defl.setInput(byteArray);
+ fail("defl.setInput() can still be used after " + desc
+ + " is called in test_" + desc);
+ } catch (IllegalStateException e) {
+ }
+ }
+ }
+
+ /**
+ * @throws DataFormatException
+ * @throws UnsupportedEncodingException
+ * @tests java.util.zip.Deflater#getBytesRead()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getBytesRead",
+ args = {}
+ )
+ public void test_getBytesRead() throws DataFormatException,
+ UnsupportedEncodingException {
+ // Regression test for HARMONY-158
+ Deflater def = new Deflater();
+ assertEquals(0, def.getTotalIn());
+ assertEquals(0, def.getTotalOut());
+ assertEquals(0, def.getBytesRead());
+ // Encode a String into bytes
+ String inputString = "blahblahblah??";
+ byte[] input = inputString.getBytes("UTF-8");
+
+ // Compress the bytes
+ byte[] output = new byte[100];
+ def.setInput(input);
+ def.finish();
+ int compressedDataLength = def.deflate(output);
+ assertEquals(14, def.getTotalIn());
+ assertEquals(compressedDataLength, def.getTotalOut());
+ assertEquals(14, def.getBytesRead());
+ }
+
+ /**
+ * @throws DataFormatException
+ * @throws UnsupportedEncodingException
+ * @tests java.util.zip.Deflater#getBytesRead()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getBytesWritten",
+ args = {}
+ )
+ public void test_getBytesWritten() throws DataFormatException,
+ UnsupportedEncodingException {
+ // Regression test for HARMONY-158
+ Deflater def = new Deflater();
+ assertEquals(0, def.getTotalIn());
+ assertEquals(0, def.getTotalOut());
+ assertEquals(0, def.getBytesWritten());
+ // Encode a String into bytes
+ String inputString = "blahblahblah??";
+ byte[] input = inputString.getBytes("UTF-8");
+
+ // Compress the bytes
+ byte[] output = new byte[100];
+ def.setInput(input);
+ def.finish();
+ int compressedDataLength = def.deflate(output);
+ assertEquals(14, def.getTotalIn());
+ assertEquals(compressedDataLength, def.getTotalOut());
+ assertEquals(compressedDataLength, def.getBytesWritten());
+ }
+
+ // BEGIN android-removed
+ // We use different default settings for deflating, so our output won't be
+ // the
+ // same.
+ // //Regression Test for HARMONY-2481
+ // public void test_deflate_beforeSetInput() throws Exception {
+ // Deflater deflater = new Deflater();
+ // deflater.finish();
+ // byte[] buffer = new byte[1024];
+ // assertEquals(8, deflater.deflate(buffer));
+ // byte[] expectedBytes = { 120, -100, 3, 0, 0, 0, 0, 1 };
+ // for (int i = 0; i < expectedBytes.length; i++) {
+ // assertEquals(expectedBytes[i], buffer[i]);
+ // }
+ // }
+ // END android-removed
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java
new file mode 100644
index 0000000..75060bd
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java
@@ -0,0 +1,322 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.zip.Checksum;
+
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import tests.support.resource.Support_Resources;
+
+@TestTargetClass(GZIPInputStream.class)
+public class GZIPInputStreamTest extends junit.framework.TestCase {
+ File resources;
+
+ class TestGZIPInputStream extends GZIPInputStream {
+ TestGZIPInputStream(InputStream in) throws IOException {
+ super(in);
+ }
+
+ TestGZIPInputStream(InputStream in, int size) throws IOException {
+ super(in, size);
+ }
+
+ Checksum getChecksum() {
+ return crc;
+ }
+
+ boolean endofInput() {
+ return eos;
+ }
+ }
+
+ /**
+ * @tests java.util.zip.GZIPInputStream#GZIPInputStream(java.io.InputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "GZIPInputStream",
+ args = {java.io.InputStream.class}
+ )
+ public void test_ConstructorLjava_io_InputStream() {
+ // test method java.util.zip.GZIPInputStream.constructor
+ try {
+ Support_Resources.copyFile(resources, "GZIPInputStream",
+ "hyts_gInput.txt.gz");
+ final URL gInput = new File(resources.toString()
+ + "/GZIPInputStream/hyts_gInput.txt.gz").toURL();
+ TestGZIPInputStream inGZIP = new TestGZIPInputStream(gInput
+ .openConnection().getInputStream());
+ assertNotNull("the constructor for GZIPInputStream is null", inGZIP);
+ assertEquals("the CRC value of the inputStream is not zero", 0,
+ inGZIP.getChecksum().getValue());
+ inGZIP.close();
+ } catch (IOException e) {
+ fail("an IO error occured while trying to open the input file");
+ }
+ }
+
+ /**
+ * @tests java.util.zip.GZIPInputStream#GZIPInputStream(java.io.InputStream,
+ * int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "GZIPInputStream",
+ args = {java.io.InputStream.class, int.class}
+ )
+ public void test_ConstructorLjava_io_InputStreamI() {
+ // test method java.util.zip.GZIPInputStream.constructorI
+ try {
+ Support_Resources.copyFile(resources, "GZIPInputStream",
+ "hyts_gInput.txt.gz");
+ final URL gInput = new File(resources.toString()
+ + "/GZIPInputStream/hyts_gInput.txt.gz").toURL();
+ TestGZIPInputStream inGZIP = new TestGZIPInputStream(gInput
+ .openConnection().getInputStream(), 200);
+ assertNotNull("the constructor for GZIPInputStream is null", inGZIP);
+ assertEquals("the CRC value of the inputStream is not zero", 0,
+ inGZIP.getChecksum().getValue());
+ inGZIP.close();
+ } catch (IOException e) {
+ fail("an IO error occured while trying to open the input file");
+ }
+ try {
+ Support_Resources.copyFile(resources, "GZIPInputStream",
+ "hyts_gInput.txt.gz");
+ final URL gInput = new File(resources.toString()
+ + "/GZIPInputStream/hyts_gInput.txt.gz").toURL();
+ TestGZIPInputStream inGZIP = new TestGZIPInputStream(gInput
+ .openConnection().getInputStream(), 0);
+ fail("Expected IllegalArgumentException");
+ } catch (IOException e) {
+ fail("an IO error occured while trying to open the input file");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+ try {
+ Support_Resources.copyFile(resources, "GZIPInputStream",
+ "hyts_gInput.txt.gz");
+ final URL gInput = new File(resources.toString()
+ + "/GZIPInputStream/hyts_gInput.txt.gz").toURL();
+ TestGZIPInputStream inGZIP = new TestGZIPInputStream(gInput
+ .openConnection().getInputStream(), -1);
+ fail("Expected IllegalArgumentException");
+ } catch (IOException e) {
+ fail("an IO error occured while trying to open the input file");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.GZIPInputStream#read(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "read",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_read$BII() throws IOException {
+ // test method java.util.zip.GZIPInputStream.readBII
+ byte orgBuf[] = {'3', '5', '2', 'r', 'g', 'e', 'f', 'd', 'e', 'w'};
+ byte outBuf[] = new byte[100];
+ int result = 0;
+ Support_Resources.copyFile(resources, "GZIPInputStream",
+ "hyts_gInput.txt.gz");
+ String resPath = resources.toString();
+ if (resPath.charAt(0) == '/' || resPath.charAt(0) == '\\') {
+ resPath = resPath.substring(1);
+ }
+ final URL gInput = new URL("file:/" + resPath
+ + "/GZIPInputStream/hyts_gInput.txt.gz");
+ TestGZIPInputStream inGZIP = new TestGZIPInputStream(gInput
+ .openConnection().getInputStream());
+ while (!(inGZIP.endofInput())) {
+ result += inGZIP.read(outBuf, result, outBuf.length - result);
+ }
+ assertEquals(
+ "the checkSum value of the compressed and decompressed data does not equal",
+ 2074883667L, inGZIP.getChecksum().getValue());
+ for (int i = 0; i < orgBuf.length; i++) {
+ assertTrue(
+ "the decompressed data does not equal the original data decompressed",
+ orgBuf[i] == outBuf[i]);
+ // System.out.println(orgBuf[i] + " " + outBuf[i]);
+ }
+ int r = 0;
+ try {
+ inGZIP.read(outBuf, 100, 1);
+ } catch (IndexOutOfBoundsException e) {
+ r = 1;
+ }
+ inGZIP.close();
+ // line below fails on RI also, comment out.
+ // assertEquals("Boundary Check was not present", 1, r);
+
+ // Create compressed data which is exactly 512 bytes (after the
+ // header),
+ // the size of the InflaterStream internal buffer
+ byte[] test = new byte[507];
+ for (int i = 0; i < 256; i++) {
+ test[i] = (byte) i;
+ }
+ for (int i = 256; i < test.length; i++) {
+ test[i] = (byte) (256 - i);
+ }
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ GZIPOutputStream out = new GZIPOutputStream(bout);
+ out.write(test);
+ out.close();
+ byte[] comp = bout.toByteArray();
+ GZIPInputStream gin2 = new GZIPInputStream(new ByteArrayInputStream(
+ comp), 512);
+ int total = 0;
+ while ((result = gin2.read(test)) != -1) {
+ total += result;
+ }
+ assertEquals("Should return -1", -1, gin2.read());
+ gin2.close();
+ assertTrue("Incorrectly decompressed", total == test.length);
+
+ gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 512);
+ total = 0;
+ while ((result = gin2.read(new byte[200])) != -1) {
+ total += result;
+ }
+ assertEquals("Should return -1", -1, gin2.read());
+ gin2.close();
+ assertTrue("Incorrectly decompressed", total == test.length);
+
+ gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 516);
+ total = 0;
+ while ((result = gin2.read(new byte[200])) != -1) {
+ total += result;
+ }
+ assertEquals("Should return -1", -1, gin2.read());
+ gin2.close();
+ assertTrue("Incorrectly decompressed", total == test.length);
+
+ comp[40] = 0;
+ gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 512);
+ boolean exception = false;
+ try {
+ while (gin2.read(test) != -1) {
+ ;
+ }
+ } catch (IOException e) {
+ exception = true;
+ }
+ assertTrue("Exception expected", exception);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ GZIPOutputStream zipout = new GZIPOutputStream(baos);
+ zipout.write(test);
+ zipout.close();
+ outBuf = new byte[530];
+ GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(baos
+ .toByteArray()));
+ try {
+ in.read(outBuf, 530, 1);
+ fail("Test failed IOOBE was not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ while (true) {
+ result = in.read(outBuf, 0, 5);
+ if (result == -1) {
+ // "EOF was reached";
+ break;
+ }
+ }
+ result = -10;
+ result = in.read(null, 100, 1);
+ result = in.read(outBuf, -100, 1);
+ result = in.read(outBuf, -1, 1);// 100, 1);
+ }
+
+ /**
+ * @tests java.util.zip.GZIPInputStream#close()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "close",
+ args = {}
+ )
+ public void test_close() {
+ // test method java.util.zip.GZIPInputStream.close
+ byte outBuf[] = new byte[100];
+ try {
+ int result = 0;
+ Support_Resources.copyFile(resources, "GZIPInputStream",
+ "hyts_gInput.txt.gz");
+ String resPath = resources.toString();
+ if (resPath.charAt(0) == '/' || resPath.charAt(0) == '\\') {
+ resPath = resPath.substring(1);
+ }
+ final URL gInput = new URL("file:/" + resPath
+ + "/GZIPInputStream/hyts_gInput.txt.gz");
+ TestGZIPInputStream inGZIP = new TestGZIPInputStream(gInput
+ .openConnection().getInputStream());
+ while (!(inGZIP.endofInput())) {
+ result += inGZIP.read(outBuf, result, outBuf.length - result);
+ }
+ assertEquals(
+ "the checkSum value of the compressed and decompressed data does not equal",
+ 2074883667L, inGZIP.getChecksum().getValue());
+ inGZIP.close();
+ int r = 0;
+ try {
+ inGZIP.read(outBuf, 0, 1);
+ } catch (IOException e) {
+ r = 1;
+ }
+ assertEquals(
+ "GZIPInputStream can still be used after close is called",
+ 1, r);
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail("unexpected: " + e);
+ }
+ }
+
+ @Override
+ protected void setUp() {
+ resources = Support_Resources.createTempFolder();
+ }
+
+ @Override
+ protected void tearDown() {
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java
new file mode 100644
index 0000000..298f63a
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.Checksum;
+import java.util.zip.GZIPOutputStream;
+
+@TestTargetClass(GZIPOutputStream.class)
+public class GZIPOutputStreamTest extends junit.framework.TestCase {
+
+ class TestGZIPOutputStream extends GZIPOutputStream {
+ TestGZIPOutputStream(OutputStream out) throws IOException {
+ super(out);
+ }
+
+ TestGZIPOutputStream(OutputStream out, int size) throws IOException {
+ super(out, size);
+ }
+
+ Checksum getChecksum() {
+ return crc;
+ }
+ }
+
+ /**
+ * @tests java.util.zip.GZIPOutputStream#GZIPOutputStream(java.io.OutputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "GZIPOutputStream",
+ args = {java.io.OutputStream.class}
+ )
+ public void test_ConstructorLjava_io_OutputStream() {
+ try {
+ FileOutputStream outFile = new FileOutputStream("GZIPOutCon.txt");
+ TestGZIPOutputStream outGZIP = new TestGZIPOutputStream(outFile);
+ assertNotNull("the constructor for GZIPOutputStream is null",
+ outGZIP);
+ assertEquals("the CRC value of the outputStream is not zero", 0,
+ outGZIP.getChecksum().getValue());
+ outGZIP.close();
+ } catch (IOException e) {
+ fail("an IO error occured while trying to find the output file or creating GZIP constructor");
+ }
+ }
+
+ /**
+ * @tests java.util.zip.GZIPOutputStream#GZIPOutputStream(java.io.OutputStream,
+ * int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "GZIPOutputStream",
+ args = {java.io.OutputStream.class, int.class}
+ )
+ public void test_ConstructorLjava_io_OutputStreamI() {
+ try {
+ FileOutputStream outFile = new FileOutputStream("GZIPOutCon.txt");
+ TestGZIPOutputStream outGZIP = new TestGZIPOutputStream(outFile,
+ 100);
+ assertNotNull("the constructor for GZIPOutputStream is null",
+ outGZIP);
+ assertEquals("the CRC value of the outputStream is not zero", 0,
+ outGZIP.getChecksum().getValue());
+ outGZIP.close();
+ } catch (IOException e) {
+ fail("an IO error occured while trying to find the output file or creating GZIP constructor");
+ }
+ }
+
+ /**
+ * @tests java.util.zip.GZIPOutputStream#finish()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "finish",
+ args = {}
+ )
+ public void test_finish() {
+ // test method java.util.zip.GZIPOutputStream.finish()
+ byte byteArray[] = {3, 5, 2, 'r', 'g', 'e', 'f', 'd', 'e', 'w'};
+ TestGZIPOutputStream outGZIP = null;
+ FileOutputStream outFile = null;
+ try {
+ outFile = new FileOutputStream("GZIPOutFinish.txt");
+ outGZIP = new TestGZIPOutputStream(outFile);
+
+ outGZIP.finish();
+ int r = 0;
+ try {
+ outGZIP.write(byteArray, 0, 1);
+ } catch (IOException e) {
+ r = 1;
+ }
+
+ assertEquals(
+ "GZIP instance can still be used after finish is called",
+ 1, r);
+ outGZIP.close();
+ } catch (IOException e) {
+ fail("an IO error occured while trying to find the output file or creating GZIP constructor");
+ }
+ try {
+ outFile = new FileOutputStream("GZIPOutFinish.txt");
+ outGZIP = new TestGZIPOutputStream(outFile);
+ outFile.close();
+
+ outGZIP.finish();
+ fail("Expected IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.GZIPOutputStream#close()
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException checking missed.",
+ method = "close",
+ args = {}
+ )
+ public void test_close() {
+ // test method java.util.zip.GZIPOutputStream.close()
+ byte byteArray[] = {3, 5, 2, 'r', 'g', 'e', 'f', 'd', 'e', 'w'};
+ try {
+ FileOutputStream outFile = new FileOutputStream("GZIPOutClose2.txt");
+ TestGZIPOutputStream outGZIP = new TestGZIPOutputStream(outFile);
+ outGZIP.close();
+ int r = 0;
+ try {
+ outGZIP.write(byteArray, 0, 1);
+ } catch (IOException e) {
+ r = 1;
+ }
+ assertEquals(
+ "GZIP instance can still be used after close is called", 1,
+ r);
+ } catch (IOException e) {
+ fail("an IO error occured while trying to find the output file or creating GZIP constructor");
+ }
+ }
+
+ /**
+ * @tests java.util.zip.GZIPOutputStream#write(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "write",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_write$BII() {
+ // test method java.util.zip.GZIPOutputStream.writeBII
+ byte byteArray[] = {3, 5, 2, 'r', 'g', 'e', 'f', 'd', 'e', 'w'};
+ TestGZIPOutputStream outGZIP = null;
+ try {
+ FileOutputStream outFile = new FileOutputStream("GZIPOutWrite.txt");
+ outGZIP = new TestGZIPOutputStream(outFile);
+ outGZIP.write(byteArray, 0, 10);
+ // ran JDK and found this CRC32 value is 3097700292
+ // System.out.print(outGZIP.getChecksum().getValue());
+ assertEquals(
+ "the checksum value was incorrect result of write from GZIP",
+ 3097700292L, outGZIP.getChecksum().getValue());
+
+ // test for boundary check
+ int r = 0;
+ try {
+ outGZIP.write(byteArray, 0, 11);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ r = 1;
+ } catch (IndexOutOfBoundsException ee) {
+ r = 1;
+ }
+ assertEquals("out of bounds exception is not present", 1, r);
+ outGZIP.close();
+ } catch (IOException e) {
+ fail("an IO error occured while trying to find the output file or creating GZIP constructor");
+ }
+ try {
+ outGZIP.write(byteArray, 0, 10);
+ fail("Expected IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ @Override
+ protected void setUp() {
+ }
+
+ @Override
+ protected void tearDown() {
+
+ try {
+ File dFile = new File("GZIPOutCon.txt");
+ dFile.delete();
+ File dFile2 = new File("GZIPOutFinish.txt");
+ dFile2.delete();
+ File dFile3 = new File("GZIPOutWrite.txt");
+ dFile3.delete();
+ File dFile4 = new File("GZIPOutClose2.txt");
+ dFile4.delete();
+ } catch (SecurityException e) {
+ fail("Cannot delete file for security reasons");
+ }
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterInputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterInputStreamTest.java
new file mode 100644
index 0000000..2e91510
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterInputStreamTest.java
@@ -0,0 +1,514 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+import junit.framework.TestCase;
+
+import tests.support.resource.Support_Resources;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+import java.util.zip.ZipException;
+
+@TestTargetClass(InflaterInputStream.class)
+public class InflaterInputStreamTest extends TestCase {
+
+ // files hyts_constru(O),hyts_constru(OD),hyts_constru(ODI) needs to be
+ // included as resources
+ byte outPutBuf[] = new byte[500];
+
+ class MyInflaterInputStream extends InflaterInputStream {
+ MyInflaterInputStream(InputStream in) {
+ super(in);
+ }
+
+ MyInflaterInputStream(InputStream in, Inflater infl) {
+ super(in, infl);
+ }
+
+ MyInflaterInputStream(InputStream in, Inflater infl, int size) {
+ super(in, infl, size);
+ }
+
+ void myFill() throws IOException {
+ fill();
+ }
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#InflaterInputStream(java.io.InputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "InflaterInputStream",
+ args = {java.io.InputStream.class}
+ )
+ public void test_ConstructorLjava_io_InputStream() throws IOException {
+ byte byteArray[] = new byte[100];
+ InputStream infile = Support_Resources.getStream("hyts_constru_OD.txt");
+ InflaterInputStream inflatIP = new InflaterInputStream(infile);
+
+ inflatIP.read(byteArray, 0, 5);// only suppose to read in 5 bytes
+ inflatIP.close();
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#InflaterInputStream(java.io.InputStream,
+ * java.util.zip.Inflater)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "InflaterInputStream",
+ args = {java.io.InputStream.class, java.util.zip.Inflater.class}
+ )
+ public void test_ConstructorLjava_io_InputStreamLjava_util_zip_Inflater()
+ throws IOException {
+ byte byteArray[] = new byte[100];
+ InputStream infile = Support_Resources.getStream("hyts_constru_OD.txt");
+ Inflater inflate = new Inflater();
+ InflaterInputStream inflatIP = new InflaterInputStream(infile, inflate);
+
+ inflatIP.read(byteArray, 0, 5);// only suppose to read in 5 bytes
+ inflatIP.close();
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#InflaterInputStream(java.io.InputStream,
+ * java.util.zip.Inflater, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "IllegalArgumentException checking missed.",
+ method = "InflaterInputStream",
+ args = {java.io.InputStream.class, java.util.zip.Inflater.class, int.class}
+ )
+ public void test_ConstructorLjava_io_InputStreamLjava_util_zip_InflaterI()
+ throws IOException {
+ int result = 0;
+ int buffer[] = new int[500];
+ InputStream infile = Support_Resources
+ .getStream("hyts_constru_ODI.txt");
+ Inflater inflate = new Inflater();
+ InflaterInputStream inflatIP = new InflaterInputStream(infile, inflate,
+ 1);
+
+ int i = 0;
+ while ((result = inflatIP.read()) != -1) {
+ buffer[i] = result;
+ i++;
+ }
+ inflatIP.close();
+
+ try {
+ inflatIP = new InflaterInputStream(infile, inflate, -1);
+ fail("IllegalArgumentException expected.");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#mark(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "mark",
+ args = {int.class}
+ )
+ public void test_markI() {
+ InputStream is = new ByteArrayInputStream(new byte[10]);
+ InflaterInputStream iis = new InflaterInputStream(is);
+ // mark do nothing, do no check
+ iis.mark(0);
+ iis.mark(-1);
+ iis.mark(10000000);
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#markSupported()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "markSupported",
+ args = {}
+ )
+ public void test_markSupported() {
+ InputStream is = new ByteArrayInputStream(new byte[10]);
+ InflaterInputStream iis = new InflaterInputStream(is);
+ assertFalse(iis.markSupported());
+ assertTrue(is.markSupported());
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#read()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "read",
+ args = {}
+ )
+ public void test_read() throws IOException {
+ int result = 0;
+ int buffer[] = new int[500];
+ byte orgBuffer[] = {1, 3, 4, 7, 8};
+ InputStream infile = Support_Resources.getStream("hyts_constru_OD.txt");
+ Inflater inflate = new Inflater();
+ InflaterInputStream inflatIP = new InflaterInputStream(infile, inflate);
+
+ int i = 0;
+ while ((result = inflatIP.read()) != -1) {
+ buffer[i] = result;
+ i++;
+ }
+ inflatIP.close();
+
+ for (int j = 0; j < orgBuffer.length; j++) {
+ assertTrue(
+ "original compressed data did not equal decompressed data",
+ buffer[j] == orgBuffer[j]);
+ }
+ inflatIP.close();
+ try {
+ inflatIP.read();
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected.
+ }
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#read(byte[], int, int)
+ */
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException & ZipException checking missed. Additional tests for fill method is not needed.",
+ method = "read",
+ args = {byte[].class, int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException & ZipException checking missed. Additional tests for fill method is not needed.",
+ method = "fill",
+ args = {}
+ )
+ })
+ public void test_read$BII() throws IOException {
+ byte[] test = new byte[507];
+ for (int i = 0; i < 256; i++) {
+ test[i] = (byte) i;
+ }
+ for (int i = 256; i < test.length; i++) {
+ test[i] = (byte) (256 - i);
+ }
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DeflaterOutputStream dos = new DeflaterOutputStream(baos);
+ dos.write(test);
+ dos.close();
+ InputStream is = new ByteArrayInputStream(baos.toByteArray());
+ InflaterInputStream iis = new InflaterInputStream(is);
+ byte[] outBuf = new byte[530];
+ int result = 0;
+ while (true) {
+ result = iis.read(outBuf, 0, 5);
+ if (result == -1) {
+ // "EOF was reached";
+ break;
+ }
+ }
+ try {
+ iis.read(outBuf, -1, 10);
+ fail("should throw IOOBE.");
+ } catch (IndexOutOfBoundsException e) {
+ // expected;
+ }
+ iis.close();
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#read(byte[], int, int)
+ */
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException checking.",
+ method = "read",
+ args = {byte[].class, int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException checking.",
+ method = "fill",
+ args = {}
+ )
+ })
+ public void test_read$BII2() throws IOException {
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ FileInputStream fis = new FileInputStream(new File(resources,
+ "Broken_manifest.jar"));
+ InflaterInputStream iis = new InflaterInputStream(fis);
+ byte[] outBuf = new byte[530];
+
+ iis.close();
+ try {
+ iis.read(outBuf, 0, 5);
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected.
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException checking.",
+ method = "read",
+ args = {byte[].class, int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException checking.",
+ method = "fill",
+ args = {}
+ )
+ })
+ public void test_read$BII3() throws IOException {
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ FileInputStream fis = new FileInputStream(new File(resources,
+ "Broken_manifest.jar"));
+ InflaterInputStream iis = new InflaterInputStream(fis);
+ byte[] outBuf = new byte[530];
+
+ try {
+ iis.read();
+ fail("IOException expected.");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#reset()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "reset",
+ args = {}
+ )
+ public void test_reset() {
+ InputStream is = new ByteArrayInputStream(new byte[10]);
+ InflaterInputStream iis = new InflaterInputStream(is);
+ try {
+ iis.reset();
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // correct
+ }
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#skip(long)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IOException checking missed.",
+ method = "skip",
+ args = {long.class}
+ )
+ public void test_skipJ() throws IOException {
+ InputStream is = Support_Resources.getStream("hyts_available.tst");
+ InflaterInputStream iis = new InflaterInputStream(is);
+
+ // Tests for skipping a negative number of bytes.
+ try {
+ iis.skip(-3);
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ assertEquals("Incorrect Byte Returned.", 5, iis.read());
+
+ try {
+ iis.skip(Integer.MIN_VALUE);
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ assertEquals("Incorrect Byte Returned.", 4, iis.read());
+
+ // Test to make sure the correct number of bytes were skipped
+ assertEquals("Incorrect Number Of Bytes Skipped.", 3, iis.skip(3));
+
+ // Test to see if the number of bytes skipped returned is true.
+ assertEquals("Incorrect Byte Returned.", 7, iis.read());
+
+ assertEquals("Incorrect Number Of Bytes Skipped.", 0, iis.skip(0));
+ assertEquals("Incorrect Byte Returned.", 0, iis.read());
+
+ // Test for skipping more bytes than available in the stream
+ assertEquals("Incorrect Number Of Bytes Skipped.", 2, iis.skip(4));
+ assertEquals("Incorrect Byte Returned.", -1, iis.read());
+ iis.close();
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#skip(long)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "IOException checking missed.",
+ method = "skip",
+ args = {long.class}
+ )
+ public void test_skipJ2() throws IOException {
+ int result = 0;
+ int buffer[] = new int[100];
+ byte orgBuffer[] = {1, 3, 4, 7, 8};
+
+ // testing for negative input to skip
+ InputStream infile = Support_Resources.getStream("hyts_constru_OD.txt");
+ Inflater inflate = new Inflater();
+ InflaterInputStream inflatIP = new InflaterInputStream(infile, inflate,
+ 10);
+ long skip;
+ try {
+ skip = inflatIP.skip(Integer.MIN_VALUE);
+ fail("Expected IllegalArgumentException when skip() is called with negative parameter");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ inflatIP.close();
+
+ // testing for number of bytes greater than input.
+ InputStream infile2 = Support_Resources
+ .getStream("hyts_constru_OD.txt");
+ InflaterInputStream inflatIP2 = new InflaterInputStream(infile2);
+
+ // looked at how many bytes the skip skipped. It is
+ // 5 and its supposed to be the entire input stream.
+
+ skip = inflatIP2.skip(Integer.MAX_VALUE);
+ // System.out.println(skip);
+ assertEquals("method skip() returned wrong number of bytes skipped", 5,
+ skip);
+
+ // test for skipping of 2 bytes
+ InputStream infile3 = Support_Resources
+ .getStream("hyts_constru_OD.txt");
+ InflaterInputStream inflatIP3 = new InflaterInputStream(infile3);
+ skip = inflatIP3.skip(2);
+ assertEquals(
+ "the number of bytes returned by skip did not correspond with its input parameters",
+ 2, skip);
+ int i = 0;
+ result = 0;
+ while ((result = inflatIP3.read()) != -1) {
+ buffer[i] = result;
+ i++;
+ }
+ inflatIP2.close();
+
+ for (int j = 2; j < orgBuffer.length; j++) {
+ assertTrue(
+ "original compressed data did not equal decompressed data",
+ buffer[j - 2] == orgBuffer[j]);
+ }
+
+ try {
+ inflatIP2.skip(4);
+ fail("IOException expected.");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#available()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "available",
+ args = {}
+ )
+ public void test_available() throws IOException {
+ InputStream is = Support_Resources.getStream("hyts_available.tst");
+ InflaterInputStream iis = new InflaterInputStream(is);
+
+ int available;
+ int read;
+ for (int i = 0; i < 11; i++) {
+ read = iis.read();
+ available = iis.available();
+ if (read == -1) {
+ assertEquals("Bytes Available Should Return 0 ", 0, available);
+ } else {
+ assertEquals("Bytes Available Should Return 1.", 1, available);
+ }
+ }
+
+ iis.close();
+ try {
+ iis.available();
+ fail("available after close should throw IOException.");
+ } catch (IOException e) {
+ // Expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.InflaterInputStream#close()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "IOException can not be tested.",
+ method = "close",
+ args = {}
+ )
+ public void test_close() throws IOException {
+ InflaterInputStream iin = new InflaterInputStream(
+ new ByteArrayInputStream(new byte[0]));
+ iin.close();
+
+ // test for exception
+ iin.close();
+
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
new file mode 100644
index 0000000..8b89180
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
@@ -0,0 +1,1132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.BufferedInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.zip.Adler32;
+import java.io.UnsupportedEncodingException;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+import java.util.zip.ZipException;
+
+import tests.support.resource.Support_Resources;
+
+@TestTargetClass(Inflater.class)
+public class InflaterTest extends junit.framework.TestCase {
+ byte outPutBuff1[] = new byte[500];
+
+ byte outPutDiction[] = new byte[500];
+
+ /**
+ * @tests java.util.zip.Inflater#end()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "end",
+ args = {}
+ )
+ public void test_end() {
+ // test method of java.util.zip.inflater.end()
+ byte byteArray[] = {5, 2, 3, 7, 8};
+
+ int r = 0;
+ Inflater inflate = new Inflater();
+ inflate.setInput(byteArray);
+ inflate.end();
+ try {
+ inflate.reset();
+ inflate.setInput(byteArray);
+ } catch (NullPointerException e) {
+ r = 1;
+ }
+ assertEquals("inflate can still be used after end is called", 1, r);
+
+ Inflater i = new Inflater();
+ i.end();
+ // check for exception
+ i.end();
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#finished()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "finished",
+ args = {}
+ )
+ public void test_finished() {
+ // test method of java.util.zip.inflater.finished()
+ byte byteArray[] = {1, 3, 4, 7, 8, 'e', 'r', 't', 'y', '5'};
+ Inflater inflate = new Inflater(false);
+ byte outPutInf[] = new byte[500];
+ try {
+ while (!(inflate.finished())) {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuff1);
+ }
+
+ inflate.inflate(outPutInf);
+ }
+ assertTrue(
+ "the method finished() returned false when no more data needs to be decompressed",
+ inflate.finished());
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ }
+ for (int i = 0; i < byteArray.length; i++) {
+ assertTrue(
+ "Final decompressed data does not equal the original data",
+ byteArray[i] == outPutInf[i]);
+ }
+ assertEquals(
+ "final decompressed data contained more bytes than original - finished()",
+ 0, outPutInf[byteArray.length]);
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#getAdler()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getAdler",
+ args = {}
+ )
+ public void test_getAdler() {
+ // test method of java.util.zip.inflater.getAdler()
+ byte dictionaryArray[] = {'e', 'r', 't', 'a', 'b', 2, 3};
+
+ Inflater inflateDiction = new Inflater();
+ inflateDiction.setInput(outPutDiction);
+ if (inflateDiction.needsDictionary() == true) {
+ // getting the checkSum value through the Adler32 class
+ Adler32 adl = new Adler32();
+ adl.update(dictionaryArray);
+ long checkSumR = adl.getValue();
+ assertTrue(
+ "the checksum value returned by getAdler() is not the same as the checksum returned by creating the adler32 instance",
+ checkSumR == inflateDiction.getAdler());
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#getRemaining()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getRemaining",
+ args = {}
+ )
+ public void test_getRemaining() {
+ // test method of java.util.zip.inflater.getRemaining()
+ byte byteArray[] = {1, 3, 5, 6, 7};
+ Inflater inflate = new Inflater();
+ assertEquals(
+ "upon creating an instance of inflate, getRemaining returned a non zero value",
+ 0, inflate.getRemaining());
+ inflate.setInput(byteArray);
+ assertTrue(
+ "getRemaining returned zero when there is input in the input buffer",
+ inflate.getRemaining() != 0);
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#getTotalIn()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getTotalIn",
+ args = {}
+ )
+ public void test_getTotalIn() {
+ // test method of java.util.zip.inflater.getTotalIn()
+ // creating the decompressed data
+ byte outPutBuf[] = new byte[500];
+ byte byteArray[] = {1, 3, 4, 7, 8};
+ byte outPutInf[] = new byte[500];
+ int x = 0;
+ Deflater deflate = new Deflater(1);
+ deflate.setInput(byteArray);
+ while (!(deflate.needsInput())) {
+ x += deflate.deflate(outPutBuf, x, outPutBuf.length - x);
+ }
+ deflate.finish();
+ while (!(deflate.finished())) {
+ x = x + deflate.deflate(outPutBuf, x, outPutBuf.length - x);
+ }
+
+ Inflater inflate = new Inflater();
+ try {
+ while (!(inflate.finished())) {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuf);
+ }
+
+ inflate.inflate(outPutInf);
+ }
+ } catch (DataFormatException e) {
+ fail("Input to inflate is invalid or corrupted - getTotalIn");
+ }
+ // System.out.print(deflate.getTotalOut() + " " + inflate.getTotalIn());
+ assertTrue(
+ "the total byte in outPutBuf did not equal the byte returned in getTotalIn",
+ inflate.getTotalIn() == deflate.getTotalOut());
+
+ Inflater inflate2 = new Inflater();
+ int offSet = 0;// seems only can start as 0
+ int length = 4;
+ try {
+ // seems no while loops allowed
+ if (inflate2.needsInput()) {
+ inflate2.setInput(outPutBuff1, offSet, length);
+ }
+
+ inflate2.inflate(outPutInf);
+
+ } catch (DataFormatException e) {
+ fail("Input to inflate is invalid or corrupted - getTotalIn");
+ }
+ // System.out.print(inflate2.getTotalIn() + " " + length);
+ assertTrue(
+ "total byte dictated by length did not equal byte returned in getTotalIn",
+ inflate2.getTotalIn() == length);
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#getTotalOut()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getTotalOut",
+ args = {}
+ )
+ public void test_getTotalOut() {
+ // test method of java.util.zip.inflater.Inflater()
+ // creating the decompressed data
+ byte outPutBuf[] = new byte[500];
+ byte byteArray[] = {1, 3, 4, 7, 8};
+ int y = 0;
+ int x = 0;
+ Deflater deflate = new Deflater(1);
+ deflate.setInput(byteArray);
+ while (!(deflate.needsInput())) {
+ x += deflate.deflate(outPutBuf, x, outPutBuf.length - x);
+ }
+ deflate.finish();
+ while (!(deflate.finished())) {
+ x = x + deflate.deflate(outPutBuf, x, outPutBuf.length - x);
+ }
+
+ Inflater inflate = new Inflater();
+ byte outPutInf[] = new byte[500];
+ try {
+ while (!(inflate.finished())) {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuf);
+ }
+
+ y += inflate.inflate(outPutInf);
+ }
+ } catch (DataFormatException e) {
+ fail("Input to inflate is invalid or corrupted - getTotalIn");
+ }
+
+ assertTrue(
+ "the sum of the bytes returned from inflate does not equal the bytes of getTotalOut()",
+ y == inflate.getTotalOut());
+ assertTrue(
+ "the total number of bytes to be compressed does not equal the total bytes decompressed",
+ inflate.getTotalOut() == deflate.getTotalIn());
+
+ // testing inflate(byte,int,int)
+ inflate.reset();
+ y = 0;
+ int offSet = 0;// seems only can start as 0
+ int length = 4;
+ try {
+ while (!(inflate.finished())) {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuf);
+ }
+
+ y += inflate.inflate(outPutInf, offSet, length);
+ }
+ } catch (DataFormatException e) {
+ System.out
+ .println("Input to inflate is invalid or corrupted - getTotalIn");
+ }
+ assertTrue(
+ "the sum of the bytes returned from inflate does not equal the bytes of getTotalOut()",
+ y == inflate.getTotalOut());
+ assertTrue(
+ "the total number of bytes to be compressed does not equal the total bytes decompressed",
+ inflate.getTotalOut() == deflate.getTotalIn());
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#inflate(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "DataFormatException checking missed.",
+ method = "inflate",
+ args = {byte[].class}
+ )
+ public void test_inflate$B() {
+ // test method of java.util.zip.inflater.inflate(byte)
+
+ byte byteArray[] = {1, 3, 4, 7, 8, 'e', 'r', 't', 'y', '5'};
+ byte outPutInf[] = new byte[500];
+ Inflater inflate = new Inflater();
+ try {
+ while (!(inflate.finished())) {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuff1);
+ }
+ inflate.inflate(outPutInf);
+ }
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ }
+ for (int i = 0; i < byteArray.length; i++) {
+ assertTrue(
+ "Final decompressed data does not equal the original data",
+ byteArray[i] == outPutInf[i]);
+ }
+ assertEquals(
+ "final decompressed data contained more bytes than original - inflateB",
+ 0, outPutInf[byteArray.length]);
+ // testing for an empty input array
+ byte outPutBuf[] = new byte[500];
+ byte emptyArray[] = new byte[11];
+ int x = 0;
+ Deflater defEmpty = new Deflater(3);
+ defEmpty.setInput(emptyArray);
+ while (!(defEmpty.needsInput())) {
+ x += defEmpty.deflate(outPutBuf, x, outPutBuf.length - x);
+ }
+ defEmpty.finish();
+ while (!(defEmpty.finished())) {
+ x += defEmpty.deflate(outPutBuf, x, outPutBuf.length - x);
+ }
+ assertTrue(
+ "the total number of byte from deflate did not equal getTotalOut - inflate(byte)",
+ x == defEmpty.getTotalOut());
+ assertTrue(
+ "the number of input byte from the array did not correspond with getTotalIn - inflate(byte)",
+ defEmpty.getTotalIn() == emptyArray.length);
+ Inflater infEmpty = new Inflater();
+ try {
+ while (!(infEmpty.finished())) {
+ if (infEmpty.needsInput()) {
+ infEmpty.setInput(outPutBuf);
+ }
+ infEmpty.inflate(outPutInf);
+ }
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ }
+ for (int i = 0; i < emptyArray.length; i++) {
+ assertTrue(
+ "Final decompressed data does not equal the original data",
+ emptyArray[i] == outPutInf[i]);
+ assertEquals("Final decompressed data does not equal zero", 0,
+ outPutInf[i]);
+ }
+ assertEquals(
+ "Final decompressed data contains more element than original data",
+ 0, outPutInf[emptyArray.length]);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "inflate",
+ args = {byte[].class}
+ )
+ public void test_inflate$B1() {
+ byte codedData[] = {
+ 120, -38, 75, -54, 73, -52, 80, 40, 46, 41, -54, -52, 75, 87,
+ 72, -50, -49, 43, 73, -52, -52, 43, 86, 72, 2, 10, 34, 99,
+ -123, -60, -68, 20, -80, 32, 0, -101, -69, 17, 84};
+ String codedString = "blah string contains blahblahblahblah and blah";
+
+ Inflater infl1 = new Inflater();
+ Inflater infl2 = new Inflater();
+
+ byte[] result = new byte[100];
+ int decLen = 0;
+
+ infl1.setInput(codedData, 0, codedData.length);
+ try {
+ decLen = infl1.inflate(result);
+ } catch (DataFormatException e) {
+ fail("Unexpected DataFormatException");
+ }
+
+ infl1.end();
+ assertEquals(codedString, new String(result, 0, decLen));
+ codedData[5] = 0;
+
+ infl2.setInput(codedData, 0, codedData.length);
+ try {
+ decLen = infl2.inflate(result);
+ fail("Expected DataFormatException");
+ } catch (DataFormatException e) {
+ // expected
+ }
+
+ infl2.end();
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#inflate(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "DataFormatException checking missed.",
+ method = "inflate",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_inflate$BII() {
+ // test method of java.util.zip.inflater.inflate(byte,int,int)
+
+ byte byteArray[] = {1, 3, 4, 7, 8, 'e', 'r', 't', 'y', '5'};
+ byte outPutInf[] = new byte[100];
+ int y = 0;
+ Inflater inflate = new Inflater();
+ try {
+ while (!(inflate.finished())) {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuff1);
+ }
+ y += inflate.inflate(outPutInf, y, outPutInf.length - y);
+ }
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ }
+ for (int i = 0; i < byteArray.length; i++) {
+ assertTrue(
+ "Final decompressed data does not equal the original data",
+ byteArray[i] == outPutInf[i]);
+ }
+ assertEquals(
+ "final decompressed data contained more bytes than original - inflateB",
+ 0, outPutInf[byteArray.length]);
+
+ // test boundary checks
+ inflate.reset();
+ int r = 0;
+ int offSet = 0;
+ int lengthError = 101;
+ try {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuff1);
+ }
+ inflate.inflate(outPutInf, offSet, lengthError);
+
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ r = 1;
+ }
+ assertEquals("out of bounds error did not get caught", 1, r);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "inflate",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_inflate$BII1() {
+ byte codedData[] = {
+ 120, -38, 75, -54, 73, -52, 80, 40, 46, 41, -54, -52, 75, 87,
+ 72, -50, -49, 43, 73, -52, -52, 43, 86, 72, 2, 10, 34, 99,
+ -123, -60, -68, 20, -80, 32, 0, -101, -69, 17, 84};
+ String codedString = "blah string";
+
+ Inflater infl1 = new Inflater();
+ Inflater infl2 = new Inflater();
+
+ byte[] result = new byte[100];
+ int decLen = 0;
+
+ infl1.setInput(codedData, 0, codedData.length);
+ try {
+ decLen = infl1.inflate(result, 10, 11);
+ } catch (DataFormatException e) {
+ fail("Unexpected DataFormatException");
+ }
+
+ infl1.end();
+ assertEquals(codedString, new String(result, 10, decLen));
+ codedData[5] = 0;
+
+ infl2.setInput(codedData, 0, codedData.length);
+ try {
+ decLen = infl2.inflate(result, 10, 11);
+ fail("Expected DataFormatException");
+ } catch (DataFormatException e) {
+ // expected
+ }
+
+ infl2.end();
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#Inflater()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Inflater",
+ args = {}
+ )
+ public void test_Constructor() {
+ // test method of java.util.zip.inflater.Inflater()
+ try {
+ Inflater inflate = new Inflater();
+ assertNotNull("failed to create the instance of inflater", inflate);
+
+ } catch (Exception e) {
+
+ assertTrue("Inflate () constructor threw an exception", true);
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#Inflater(boolean)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Inflater",
+ args = {boolean.class}
+ )
+ public void test_ConstructorZ() {
+ // test method of java.util.zip.inflater.Inflater(boolean)
+ // note does not throw exception if deflater has a header, but inflater
+ // doesn't or vice versa.
+ byte byteArray[] = {1, 3, 4, 7, 8, 'e', 'r', 't', 'y', '5'};
+ Inflater inflate = new Inflater(true);
+ assertNotNull("failed to create the instance of inflater", inflate);
+ byte outPutInf[] = new byte[500];
+ int r = 0;
+ try {
+ while (!(inflate.finished())) {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuff1);
+ }
+
+ inflate.inflate(outPutInf);
+ }
+ for (int i = 0; i < byteArray.length; i++) {
+ assertEquals(
+ "the output array from inflate should contain 0 because the header of inflate and deflate did not match, but this failed",
+ 0, outPutBuff1[i]);
+ }
+ } catch (DataFormatException e) {
+ r = 1;
+ }
+ assertEquals(
+ "Error: exception should be thrown because of header inconsistency",
+ 1, r);
+
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#needsDictionary()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "needsDictionary",
+ args = {}
+ )
+ public void test_needsDictionary() {
+ // test method of java.util.zip.inflater.needsDictionary()
+ // note: this flag is set after inflate is called
+ byte outPutInf[] = new byte[500];
+
+ // testing with dictionary set.
+ Inflater inflateDiction = new Inflater();
+ if (inflateDiction.needsInput()) {
+ inflateDiction.setInput(outPutDiction);
+ }
+ try {
+ assertEquals("should return 0 because needs dictionary", 0,
+ inflateDiction.inflate(outPutInf));
+ } catch (DataFormatException e) {
+ fail("Should not cause exception");
+ }
+ assertTrue(
+ "method needsDictionary returned false when dictionary was used in deflater",
+ inflateDiction.needsDictionary());
+
+ // testing without dictionary
+ Inflater inflate = new Inflater();
+ try {
+ inflate.setInput(outPutBuff1);
+ inflate.inflate(outPutInf);
+ assertFalse(
+ "method needsDictionary returned true when dictionary was not used in deflater",
+ inflate.needsDictionary());
+ } catch (DataFormatException e) {
+ fail("Input to inflate is invalid or corrupted - needsDictionary");
+ }
+
+ // Regression test for HARMONY-86
+ Inflater inf = new Inflater();
+ assertFalse(inf.needsDictionary());
+ assertEquals(0, inf.getTotalIn());
+ assertEquals(0, inf.getTotalOut());
+ assertEquals(0, inf.getBytesRead());
+ assertEquals(0, inf.getBytesWritten());
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#needsInput()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "needsInput",
+ args = {}
+ )
+ public void test_needsInput() {
+ // test method of java.util.zip.inflater.needsInput()
+ Inflater inflate = new Inflater();
+ assertTrue(
+ "needsInput give the wrong boolean value as a result of no input buffer",
+ inflate.needsInput());
+
+ byte byteArray[] = {2, 3, 4, 't', 'y', 'u', 'e', 'w', 7, 6, 5, 9};
+ inflate.setInput(byteArray);
+ assertFalse(
+ "methodNeedsInput returned true when the input buffer is full",
+ inflate.needsInput());
+
+ inflate.reset();
+ byte byteArrayEmpty[] = new byte[0];
+ inflate.setInput(byteArrayEmpty);
+ assertTrue(
+ "needsInput give wrong boolean value as a result of an empty input buffer",
+ inflate.needsInput());
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#reset()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "reset",
+ args = {}
+ )
+ public void test_reset() {
+ // test method of java.util.zip.inflater.reset()
+ byte byteArray[] = {1, 3, 4, 7, 8, 'e', 'r', 't', 'y', '5'};
+ byte outPutInf[] = new byte[100];
+ int y = 0;
+ Inflater inflate = new Inflater();
+ try {
+ while (!(inflate.finished())) {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuff1);
+ }
+ y += inflate.inflate(outPutInf, y, outPutInf.length - y);
+ }
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ }
+ for (int i = 0; i < byteArray.length; i++) {
+ assertTrue(
+ "Final decompressed data does not equal the original data",
+ byteArray[i] == outPutInf[i]);
+ }
+ assertEquals(
+ "final decompressed data contained more bytes than original - reset",
+ 0, outPutInf[byteArray.length]);
+
+ // testing that resetting the inflater will also return the correct
+ // decompressed data
+
+ inflate.reset();
+ try {
+ while (!(inflate.finished())) {
+ if (inflate.needsInput()) {
+ inflate.setInput(outPutBuff1);
+ }
+ inflate.inflate(outPutInf);
+ }
+ } catch (DataFormatException e) {
+ fail("Invalid input to be decompressed");
+ }
+ for (int i = 0; i < byteArray.length; i++) {
+ assertTrue(
+ "Final decompressed data does not equal the original data",
+ byteArray[i] == outPutInf[i]);
+ }
+ assertEquals(
+ "final decompressed data contained more bytes than original - reset",
+ 0, outPutInf[byteArray.length]);
+
+ }
+
+
+ /**
+ * @tests java.util.zip.Inflater#setInput(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setInput",
+ args = {byte[].class}
+ )
+ public void test_setInput$B() {
+ // test method of java.util.zip.inflater.setInput(byte)
+ byte byteArray[] = {2, 3, 4, 't', 'y', 'u', 'e', 'w', 7, 6, 5, 9};
+ Inflater inflate = new Inflater();
+ inflate.setInput(byteArray);
+ assertTrue("setInputB did not deliver any byte to the input buffer",
+ inflate.getRemaining() != 0);
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#setInput(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setInput",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_setInput$BII() {
+ // test method of java.util.zip.inflater.setInput(byte,int,int)
+ byte byteArray[] = {2, 3, 4, 't', 'y', 'u', 'e', 'w', 7, 6, 5, 9};
+ int offSet = 6;
+ int length = 6;
+ Inflater inflate = new Inflater();
+ inflate.setInput(byteArray, offSet, length);
+ assertTrue(
+ "setInputBII did not deliver the right number of bytes to the input buffer",
+ inflate.getRemaining() == length);
+ // boundary check
+ inflate.reset();
+ int r = 0;
+ try {
+ inflate.setInput(byteArray, 100, 100);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ r = 1;
+ }
+ assertEquals("boundary check is not present for setInput", 1, r);
+ }
+
+ @Override
+ protected void setUp() {
+ try {
+ java.io.InputStream infile = Support_Resources
+ .getStream("hyts_compressD.txt");
+ BufferedInputStream inflatIP = new BufferedInputStream(infile);
+ inflatIP.read(outPutBuff1, 0, outPutBuff1.length);
+ inflatIP.close();
+
+ java.io.InputStream infile2 = Support_Resources
+ .getStream("hyts_compDiction.txt");
+ BufferedInputStream inflatIP2 = new BufferedInputStream(infile2);
+ inflatIP2.read(outPutDiction, 0, outPutDiction.length);
+ inflatIP2.close();
+
+ } catch (FileNotFoundException e) {
+ fail("input file to test InflaterInputStream constructor is not found");
+ } catch (ZipException e) {
+ fail("read() threw an zip exception while testing constructor");
+ } catch (IOException e) {
+ fail("read() threw an exception while testing constructor");
+ }
+ }
+
+ @Override
+ protected void tearDown() {
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#getBytesRead()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getBytesRead",
+ args = {}
+ )
+ public void test_getBytesRead() throws DataFormatException,
+ UnsupportedEncodingException {
+ // Regression test for HARMONY-158
+ Deflater def = new Deflater();
+ Inflater inf = new Inflater();
+ assertEquals(0, def.getTotalIn());
+ assertEquals(0, def.getTotalOut());
+ assertEquals(0, def.getBytesRead());
+ // Encode a String into bytes
+ String inputString = "blahblahblah??";
+ byte[] input = inputString.getBytes("UTF-8");
+
+ // Compress the bytes
+ byte[] output = new byte[100];
+ def.setInput(input);
+ def.finish();
+ def.deflate(output);
+ inf.setInput(output);
+ int compressedDataLength = inf.inflate(input);
+ assertEquals(16, inf.getTotalIn());
+ assertEquals(compressedDataLength, inf.getTotalOut());
+ assertEquals(16, inf.getBytesRead());
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#getBytesRead()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getBytesWritten",
+ args = {}
+ )
+ public void test_getBytesWritten() throws DataFormatException,
+ UnsupportedEncodingException {
+ // Regression test for HARMONY-158
+ Deflater def = new Deflater();
+ Inflater inf = new Inflater();
+ assertEquals(0, def.getTotalIn());
+ assertEquals(0, def.getTotalOut());
+ assertEquals(0, def.getBytesWritten());
+ // Encode a String into bytes
+ String inputString = "blahblahblah??";
+ byte[] input = inputString.getBytes("UTF-8");
+
+ // Compress the bytes
+ byte[] output = new byte[100];
+ def.setInput(input);
+ def.finish();
+ def.deflate(output);
+ inf.setInput(output);
+ int compressedDataLength = inf.inflate(input);
+ assertEquals(16, inf.getTotalIn());
+ assertEquals(compressedDataLength, inf.getTotalOut());
+ assertEquals(14, inf.getBytesWritten());
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#inflate(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "Regression test",
+ method = "inflate",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void testInflate() throws Exception {
+ // Regression for HARMONY-81
+ Inflater inf = new Inflater();
+ int res = inf.inflate(new byte[0], 0, 0);
+
+ assertEquals(0, res);
+
+ // Regression for HARMONY-2508
+ Inflater inflater = new Inflater();
+ byte[] b = new byte[1024];
+ assertEquals(0, inflater.inflate(b));
+ inflater.end();
+
+ // Regression for HARMONY-2510
+ inflater = new Inflater();
+ byte[] input = new byte[] {-1};
+ inflater.setInput(input);
+ try {
+ inflater.inflate(b);
+ fail("should throw DataFormateException");
+ } catch (DataFormatException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.Deflater#inflate(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Can not be checked. Should be tested in DX test package.",
+ method = "finalize",
+ args = {}
+ )
+ public void testFinalize() throws Exception {
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#setDictionary(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Checks setDictionary. Can be splitted for 2 separate tests for Deflater & Inflater. Can be used as a base for setDictionary with additional params.",
+ method = "setDictionary",
+ args = {byte[].class}
+ )
+ public void testsetDictionary$B() throws Exception {
+ int i = 0;
+ String inputString = "blah string contains blahblahblahblah and blah";
+ String dictionary1 = "blah";
+ String dictionary2 = "1234";
+
+ byte[] outputNo = new byte[100];
+ byte[] output1 = new byte[100];
+ byte[] output2 = new byte[100];
+ Deflater defDictNo = new Deflater(9);
+ Deflater defDict1 = new Deflater(9);
+ Deflater defDict2 = new Deflater(9);
+
+ defDict1.setDictionary(dictionary1.getBytes());
+ defDict2.setDictionary(dictionary2.getBytes());
+
+ defDictNo.setInput(inputString.getBytes());
+ defDict1.setInput(inputString.getBytes());
+ defDict2.setInput(inputString.getBytes());
+
+ defDictNo.finish();
+ defDict1.finish();
+ defDict2.finish();
+
+ int dataLenNo = defDictNo.deflate(outputNo);
+ int dataLen1 = defDict1.deflate(output1);
+ int dataLen2 = defDict2.deflate(output2);
+
+ boolean passNo1 = false;
+ boolean passNo2 = false;
+ boolean pass12 = false;
+
+ for (i = 0; i < (dataLenNo < dataLen1 ? dataLenNo : dataLen1); i++) {
+ if (outputNo[i] != output1[i]) {
+ passNo1 = true;
+ break;
+ }
+ }
+ for (i = 0; i < (dataLenNo < dataLen1 ? dataLenNo : dataLen2); i++) {
+ if (outputNo[i] != output2[i]) {
+ passNo2 = true;
+ break;
+ }
+ }
+ for (i = 0; i < (dataLen1 < dataLen2 ? dataLen1 : dataLen2); i++) {
+ if (output1[i] != output2[i]) {
+ pass12 = true;
+ break;
+ }
+ }
+
+ assertTrue(
+ "Compressed data the same for stream with dictionary and without it.",
+ passNo1);
+ assertTrue(
+ "Compressed data the same for stream with dictionary and without it.",
+ passNo2);
+ assertTrue(
+ "Compressed data the same for stream with different dictionaries.",
+ pass12);
+
+ Inflater inflNo = new Inflater();
+ Inflater infl1 = new Inflater();
+ Inflater infl2 = new Inflater();
+
+ byte[] result = new byte[100];
+ int decLen;
+
+ inflNo.setInput(outputNo, 0, dataLenNo);
+ decLen = inflNo.inflate(result);
+
+ assertFalse(inflNo.needsDictionary());
+ inflNo.end();
+ assertEquals(inputString, new String(result, 0, decLen));
+
+ infl1.setInput(output1, 0, dataLen1);
+ decLen = infl1.inflate(result);
+
+ assertTrue(infl1.needsDictionary());
+ infl1.setDictionary(dictionary1.getBytes());
+ decLen = infl1.inflate(result);
+ infl1.end();
+ assertEquals(inputString, new String(result, 0, decLen));
+
+ infl2.setInput(output2, 0, dataLen2);
+ decLen = infl2.inflate(result);
+
+ assertTrue(infl2.needsDictionary());
+ infl2.setDictionary(dictionary2.getBytes());
+ decLen = infl2.inflate(result);
+ infl2.end();
+ assertEquals(inputString, new String(result, 0, decLen));
+
+
+ inflNo = new Inflater();
+ infl1 = new Inflater();
+ inflNo.setInput(outputNo, 0, dataLenNo);
+ try {
+ infl1.setDictionary(dictionary1.getBytes());
+ fail("IllegalArgumentException expected.");
+ } catch (IllegalArgumentException ee) {
+ // expected.
+ }
+ inflNo.end();
+
+ infl1.setInput(output1, 0, dataLen1);
+ decLen = infl1.inflate(result);
+
+ assertTrue(infl1.needsDictionary());
+ try {
+ infl1.setDictionary(dictionary2.getBytes());
+ fail("IllegalArgumentException expected.");
+ } catch (IllegalArgumentException ee) {
+ // expected.
+ }
+ infl1.end();
+ }
+
+ /**
+ * @tests java.util.zip.Inflater#setDictionary(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Checks setDictionary. Can be splitted for 2 separate tests for Deflater & Inflater. Can be used as a base for setDictionary with additional params.",
+ method = "setDictionary",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void testsetDictionary$BII() throws Exception {
+ int i = 0;
+ String inputString = "blah string contains blahblahblahblah and blah";
+ String dictionary1 = "blah";
+ String dictionary2 = "blahblahblah";
+
+ byte[] output1 = new byte[100];
+ byte[] output2 = new byte[100];
+ byte[] output3 = new byte[100];
+
+ Deflater defDict1 = new Deflater(9);
+ Deflater defDict2 = new Deflater(9);
+ Deflater defDict3 = new Deflater(9);
+
+ defDict1.setDictionary(dictionary1.getBytes());
+ defDict2.setDictionary(dictionary2.getBytes());
+ defDict3.setDictionary(dictionary2.getBytes(), 4, 4);
+
+ defDict1.setInput(inputString.getBytes());
+ defDict2.setInput(inputString.getBytes());
+ defDict3.setInput(inputString.getBytes());
+
+ defDict1.finish();
+ defDict2.finish();
+ defDict3.finish();
+
+ int dataLen1 = defDict1.deflate(output1);
+ int dataLen2 = defDict2.deflate(output2);
+ int dataLen3 = defDict3.deflate(output3);
+
+ boolean pass12 = false;
+ boolean pass23 = false;
+ boolean pass13 = true;
+
+ for (i = 0; i < (dataLen1 < dataLen2 ? dataLen1 : dataLen2); i++) {
+ if (output1[i] != output2[i]) {
+ pass12 = true;
+ break;
+ }
+ }
+ for (i = 0; i < (dataLen2 < dataLen3 ? dataLen2 : dataLen3); i++) {
+ if (output2[i] != output3[i]) {
+ pass23 = true;
+ break;
+ }
+ }
+ for (i = 0; i < (dataLen1 < dataLen3 ? dataLen1 : dataLen3); i++) {
+ if (output1[i] != output3[i]) {
+ pass13 = false;
+ break;
+ }
+ }
+
+ assertTrue(
+ "Compressed data the same for stream with different dictionaries.",
+ pass12);
+ assertTrue(
+ "Compressed data the same for stream with different dictionaries.",
+ pass23);
+ assertTrue(
+ "Compressed data the differs for stream with the same dictionaries.",
+ pass13);
+
+ Inflater infl1 = new Inflater();
+ Inflater infl2 = new Inflater();
+ Inflater infl3 = new Inflater();
+
+ byte[] result = new byte[100];
+ int decLen;
+
+ infl1.setInput(output1, 0, dataLen1);
+ decLen = infl1.inflate(result);
+
+ assertTrue(infl1.needsDictionary());
+ infl1.setDictionary(dictionary2.getBytes(), 4, 4);
+ decLen = infl1.inflate(result);
+ infl1.end();
+ assertEquals(inputString, new String(result, 0, decLen));
+
+ infl2.setInput(output2, 0, dataLen2);
+ decLen = infl2.inflate(result);
+
+ assertTrue(infl2.needsDictionary());
+ try {
+ infl2.setDictionary(dictionary1.getBytes());
+ fail("IllegalArgumentException expected.");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+ infl2.end();
+
+ infl3.setInput(output3, 0, dataLen3);
+ decLen = infl3.inflate(result);
+
+ assertTrue(infl3.needsDictionary());
+ infl3.setDictionary(dictionary1.getBytes());
+ decLen = infl3.inflate(result);
+ infl3.end();
+ assertEquals(inputString, new String(result, 0, decLen));
+
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipEntryTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipEntryTest.java
new file mode 100644
index 0000000..f8862d4
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipEntryTest.java
@@ -0,0 +1,646 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import tests.support.resource.Support_Resources;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.TimeZone;
+import java.util.zip.ZipEntry;
+
+@TestTargetClass(ZipEntry.class)
+public class ZipEntryTest extends junit.framework.TestCase {
+
+ // BEGIN android-added
+ public byte[] getAllBytesFromStream(InputStream is) throws IOException {
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ byte[] buf = new byte[666];
+ int iRead;
+ int off;
+ while (is.available() > 0) {
+ iRead = is.read(buf, 0, buf.length);
+ if (iRead > 0) bs.write(buf, 0, iRead);
+ }
+ return bs.toByteArray();
+ }
+
+ // END android-added
+
+ // zip file hyts_ZipFile.zip must be included as a resource
+ java.util.zip.ZipEntry zentry;
+
+ java.util.zip.ZipFile zfile;
+
+ private static final String platformId = System.getProperty(
+ "com.ibm.oti.configuration", "JDK")
+ + System.getProperty("java.vm.version");
+
+ static final String tempFileName = platformId + "zfzezi.zip";
+
+ long orgSize;
+
+ long orgCompressedSize;
+
+ long orgCrc;
+
+ long orgTime;
+
+ String orgComment;
+
+ /**
+ * @tests java.util.zip.ZipEntry#ZipEntry(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "ZipEntry",
+ args = {java.lang.String.class}
+ )
+ public void test_ConstructorLjava_lang_String() {
+ // Test for method java.util.zip.ZipEntry(java.lang.String)
+ zentry = zfile.getEntry("File3.txt");
+ assertNotNull("Failed to create ZipEntry", zentry);
+ try {
+ zentry = zfile.getEntry(null);
+ fail("NullPointerException not thrown");
+ } catch (NullPointerException e) {
+ }
+ StringBuffer s = new StringBuffer();
+ for (int i = 0; i < 65535; i++) {
+ s.append('a');
+ }
+ try {
+ zentry = new ZipEntry(s.toString());
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException During Test.");
+ }
+ try {
+ s.append('a');
+ zentry = new ZipEntry(s.toString());
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ String n = null;
+ zentry = new ZipEntry(n);
+ fail("NullPointerException not thrown");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#getComment()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getComment",
+ args = {}
+ )
+ public void test_getComment() {
+ // Test for method java.lang.String java.util.zip.ZipEntry.getComment()
+ ZipEntry zipEntry = new ZipEntry("zippy.zip");
+ assertNull("Incorrect Comment Returned.", zipEntry.getComment());
+ zipEntry.setComment("This Is A Comment");
+ assertEquals("Incorrect Comment Returned.", "This Is A Comment",
+ zipEntry.getComment());
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#getCompressedSize()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getCompressedSize",
+ args = {}
+ )
+ public void test_getCompressedSize() {
+ // Test for method long java.util.zip.ZipEntry.getCompressedSize()
+ assertTrue("Incorrect compressed size returned", zentry
+ .getCompressedSize() == orgCompressedSize);
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#getCrc()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getCrc",
+ args = {}
+ )
+ public void test_getCrc() {
+ // Test for method long java.util.zip.ZipEntry.getCrc()
+ assertTrue("Failed to get Crc", zentry.getCrc() == orgCrc);
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#getExtra()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getExtra",
+ args = {}
+ )
+ public void test_getExtra() {
+ // Test for method byte [] java.util.zip.ZipEntry.getExtra()
+ assertNull("Incorrect extra information returned", zentry.getExtra());
+ byte[] ba = {'T', 'E', 'S', 'T'};
+ zentry = new ZipEntry("test.tst");
+ zentry.setExtra(ba);
+ assertTrue("Incorrect Extra Information Returned.",
+ zentry.getExtra() == ba);
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#getMethod()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getMethod",
+ args = {}
+ )
+ public void test_getMethod() {
+ // Test for method int java.util.zip.ZipEntry.getMethod()
+ zentry = zfile.getEntry("File1.txt");
+ assertTrue("Incorrect compression method returned",
+ zentry.getMethod() == java.util.zip.ZipEntry.STORED);
+ zentry = zfile.getEntry("File3.txt");
+ assertTrue("Incorrect compression method returned",
+ zentry.getMethod() == java.util.zip.ZipEntry.DEFLATED);
+ zentry = new ZipEntry("test.tst");
+ assertEquals("Incorrect Method Returned.", -1, zentry.getMethod());
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#getName()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getName",
+ args = {}
+ )
+ public void test_getName() {
+ // Test for method java.lang.String java.util.zip.ZipEntry.getName()
+ assertEquals(
+ "Incorrect name returned - Note return result somewhat ambiguous in spec",
+ "File1.txt", zentry.getName());
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#getSize()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getSize",
+ args = {}
+ )
+ public void test_getSize() {
+ // Test for method long java.util.zip.ZipEntry.getSize()
+ assertTrue("Incorrect size returned", zentry.getSize() == orgSize);
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#getTime()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getTime",
+ args = {}
+ )
+ public void test_getTime() {
+ // Test for method long java.util.zip.ZipEntry.getTime()
+ assertTrue("Failed to get time", zentry.getTime() == orgTime);
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#isDirectory()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "isDirectory",
+ args = {}
+ )
+ public void test_isDirectory() {
+ // Test for method boolean java.util.zip.ZipEntry.isDirectory()
+ assertTrue("Entry should not answer true to isDirectory", !zentry
+ .isDirectory());
+ zentry = new ZipEntry("Directory/");
+ assertTrue("Entry should answer true to isDirectory", zentry
+ .isDirectory());
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#setComment(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setComment",
+ args = {java.lang.String.class}
+ )
+ public void test_setCommentLjava_lang_String() {
+ // Test for method void
+ // java.util.zip.ZipEntry.setComment(java.lang.String)
+ zentry = zfile.getEntry("File1.txt");
+ zentry.setComment("Set comment using api");
+ assertEquals("Comment not correctly set", "Set comment using api",
+ zentry.getComment());
+ String n = null;
+ zentry.setComment(n);
+ assertNull("Comment not correctly set", zentry.getComment());
+ StringBuffer s = new StringBuffer();
+ for (int i = 0; i < 0xFFFF; i++) {
+ s.append('a');
+ }
+ try {
+ zentry.setComment(s.toString());
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException During Test.");
+ }
+ try {
+ s.append('a');
+ zentry.setComment(s.toString());
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#setCompressedSize(long)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setCompressedSize",
+ args = {long.class}
+ )
+ public void test_setCompressedSizeJ() {
+ // Test for method void java.util.zip.ZipEntry.setCompressedSize(long)
+ zentry.setCompressedSize(orgCompressedSize + 10);
+ assertTrue("Set compressed size failed",
+ zentry.getCompressedSize() == (orgCompressedSize + 10));
+ zentry.setCompressedSize(0);
+ assertEquals("Set compressed size failed", 0, zentry
+ .getCompressedSize());
+ zentry.setCompressedSize(-25);
+ assertEquals("Set compressed size failed", -25, zentry
+ .getCompressedSize());
+ zentry.setCompressedSize(4294967296l);
+ assertTrue("Set compressed size failed",
+ zentry.getCompressedSize() == 4294967296l);
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#setCrc(long)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setCrc",
+ args = {long.class}
+ )
+ public void test_setCrcJ() {
+ // Test for method void java.util.zip.ZipEntry.setCrc(long)
+ zentry.setCrc(orgCrc + 100);
+ assertTrue("Failed to set Crc", zentry.getCrc() == (orgCrc + 100));
+ zentry.setCrc(0);
+ assertEquals("Failed to set Crc", 0, zentry.getCrc());
+ try {
+ zentry.setCrc(-25);
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ zentry.setCrc(4294967295l);
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException during test");
+ }
+ try {
+ zentry.setCrc(4294967296l);
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#setExtra(byte[])
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setExtra",
+ args = {byte[].class}
+ )
+ public void test_setExtra$B() {
+ // Test for method void java.util.zip.ZipEntry.setExtra(byte [])
+ zentry = zfile.getEntry("File1.txt");
+ zentry.setExtra("Test setting extra information".getBytes());
+ assertEquals("Extra information not written properly",
+ "Test setting extra information", new String(zentry.getExtra(),
+ 0, zentry.getExtra().length));
+ zentry = new ZipEntry("test.tst");
+ byte[] ba = new byte[0xFFFF];
+ try {
+ zentry.setExtra(ba);
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException during test");
+ }
+ try {
+ ba = new byte[0xFFFF + 1];
+ zentry.setExtra(ba);
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ }
+
+ // One constructor
+ ZipEntry zeInput = new ZipEntry("InputZIP");
+ byte[] extraB = {'a', 'b', 'd', 'e'};
+ zeInput.setExtra(extraB);
+ assertEquals(extraB, zeInput.getExtra());
+ assertEquals(extraB[3], zeInput.getExtra()[3]);
+ assertEquals(extraB.length, zeInput.getExtra().length);
+
+ // test another constructor
+ ZipEntry zeOutput = new ZipEntry(zeInput);
+ assertEquals(zeInput.getExtra()[3], zeOutput.getExtra()[3]);
+ assertEquals(zeInput.getExtra().length, zeOutput.getExtra().length);
+ assertEquals(extraB[3], zeOutput.getExtra()[3]);
+ assertEquals(extraB.length, zeOutput.getExtra().length);
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#setMethod(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setMethod",
+ args = {int.class}
+ )
+ public void test_setMethodI() {
+ // Test for method void java.util.zip.ZipEntry.setMethod(int)
+ zentry = zfile.getEntry("File3.txt");
+ zentry.setMethod(ZipEntry.STORED);
+ assertTrue("Failed to set compression method",
+ zentry.getMethod() == ZipEntry.STORED);
+ zentry.setMethod(ZipEntry.DEFLATED);
+ assertTrue("Failed to set compression method",
+ zentry.getMethod() == ZipEntry.DEFLATED);
+ try {
+ int error = 1;
+ zentry = new ZipEntry("test.tst");
+ zentry.setMethod(error);
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#setSize(long)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setSize",
+ args = {long.class}
+ )
+ public void test_setSizeJ() {
+ // Test for method void java.util.zip.ZipEntry.setSize(long)
+ zentry.setSize(orgSize + 10);
+ assertTrue("Set size failed", zentry.getSize() == (orgSize + 10));
+ zentry.setSize(0);
+ assertEquals("Set size failed", 0, zentry.getSize());
+ try {
+ zentry.setSize(-25);
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ zentry.setCrc(4294967295l);
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException during test");
+ }
+ try {
+ zentry.setCrc(4294967296l);
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#setTime(long)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setTime",
+ args = {long.class}
+ )
+ public void test_setTimeJ() {
+ // Test for method void java.util.zip.ZipEntry.setTime(long)
+ zentry.setTime(orgTime + 10000);
+ assertTrue("Test 1: Failed to set time: " + zentry.getTime(), zentry
+ .getTime() == (orgTime + 10000));
+ zentry.setTime(orgTime - 10000);
+ assertTrue("Test 2: Failed to set time: " + zentry.getTime(), zentry
+ .getTime() == (orgTime - 10000));
+ TimeZone zone = TimeZone.getDefault();
+ try {
+ TimeZone.setDefault(TimeZone.getTimeZone("EST"));
+ zentry.setTime(0);
+ assertTrue("Test 3: Failed to set time: " + zentry.getTime(),
+ zentry.getTime() == 315550800000L);
+ TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
+ assertTrue("Test 3a: Failed to set time: " + zentry.getTime(),
+ zentry.getTime() == 315532800000L);
+ zentry.setTime(0);
+ TimeZone.setDefault(TimeZone.getTimeZone("EST"));
+ assertTrue("Test 3b: Failed to set time: " + zentry.getTime(),
+ zentry.getTime() == 315550800000L);
+
+ zentry.setTime(-25);
+ assertTrue("Test 4: Failed to set time: " + zentry.getTime(),
+ zentry.getTime() == 315550800000L);
+ zentry.setTime(4354837200000L);
+ assertTrue("Test 5: Failed to set time: " + zentry.getTime(),
+ zentry.getTime() == 315550800000L);
+ } finally {
+ TimeZone.setDefault(zone);
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#toString()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "toString",
+ args = {}
+ )
+ public void test_toString() {
+ // Test for method java.lang.String java.util.zip.ZipEntry.toString()
+ assertTrue("Returned incorrect entry name", zentry.toString().indexOf(
+ "File1.txt") >= 0);
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#ZipEntry(java.util.zip.ZipEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "ZipEntry",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_ConstructorLjava_util_zip_ZipEntry() {
+ // Test for method java.util.zip.ZipEntry(util.zip.ZipEntry)
+ zentry.setSize(2);
+ zentry.setCompressedSize(4);
+ zentry.setComment("Testing");
+ ZipEntry zentry2 = new ZipEntry(zentry);
+ assertEquals("ZipEntry Created With Incorrect Size.", 2, zentry2
+ .getSize());
+ assertEquals("ZipEntry Created With Incorrect Compressed Size.", 4,
+ zentry2.getCompressedSize());
+ assertEquals("ZipEntry Created With Incorrect Comment.", "Testing",
+ zentry2.getComment());
+ assertTrue("ZipEntry Created With Incorrect Crc.",
+ zentry2.getCrc() == orgCrc);
+ assertTrue("ZipEntry Created With Incorrect Time.",
+ zentry2.getTime() == orgTime);
+ }
+
+ /**
+ * @tests java.util.zip.ZipEntry#clone()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clone",
+ args = {}
+ )
+ public void test_clone() {
+ // Test for method java.util.zip.ZipEntry.clone()
+ Object obj = zentry.clone();
+ assertTrue("toString()", obj.toString().equals(zentry.toString()));
+ assertTrue("hashCode()", obj.hashCode() == zentry.hashCode());
+
+ // One constructor
+ ZipEntry zeInput = new ZipEntry("InputZIP");
+ byte[] extraB = {'a', 'b', 'd', 'e'};
+ zeInput.setExtra(extraB);
+ assertEquals(extraB, zeInput.getExtra());
+ assertEquals(extraB[3], zeInput.getExtra()[3]);
+ assertEquals(extraB.length, zeInput.getExtra().length);
+
+ // test Clone()
+ ZipEntry zeOutput = (ZipEntry) zeInput.clone();
+ assertEquals(zeInput.getExtra()[3], zeOutput.getExtra()[3]);
+ assertEquals(zeInput.getExtra().length, zeOutput.getExtra().length);
+ assertEquals(extraB[3], zeOutput.getExtra()[3]);
+ assertEquals(extraB.length, zeOutput.getExtra().length);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "hashCode",
+ args = {}
+ )
+ public void test_hashCode() {
+ try {
+ zentry.hashCode();
+ } catch (Exception ee) {
+ fail("Unexpected exception " + ee);
+ }
+ }
+
+ /**
+ * Sets up the fixture, for example, open a network connection. This method
+ * is called before a test is executed.
+ */
+
+ @Override
+ protected void setUp() {
+ java.io.File f = null;
+ try {
+ // BEGIN android-changed
+ // Create a local copy of the file since some tests want to alter
+ // information.
+ f = new java.io.File(tempFileName);
+ // Create absolute filename as ZipFile does not resolve using
+ // user.dir
+ f = new java.io.File(f.getAbsolutePath());
+ f.delete();
+ java.io.InputStream is = Support_Resources
+ .getStream("hyts_ZipFile.zip");
+ java.io.FileOutputStream fos = new java.io.FileOutputStream(f);
+ byte[] rbuf = getAllBytesFromStream(is);
+ // END android-changed
+ fos.write(rbuf, 0, rbuf.length);
+ is.close();
+ fos.close();
+ zfile = new java.util.zip.ZipFile(f);
+ zentry = zfile.getEntry("File1.txt");
+ orgSize = zentry.getSize();
+ orgCompressedSize = zentry.getCompressedSize();
+ orgCrc = zentry.getCrc();
+ orgTime = zentry.getTime();
+ orgComment = zentry.getComment();
+ } catch (Exception e) {
+ System.out.println("Exception during ZipFile setup <"
+ + f.getAbsolutePath() + ">: ");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Tears down the fixture, for example, close a network connection. This
+ * method is called after a test is executed.
+ */
+
+ @Override
+ protected void tearDown() {
+ try {
+ if (zfile != null) {
+ zfile.close();
+ }
+ java.io.File f = new java.io.File(tempFileName);
+ f.delete();
+ } catch (java.io.IOException e) {
+ System.out.println("Exception during tearDown");
+ }
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipExceptionTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipExceptionTest.java
new file mode 100644
index 0000000..eb04777
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipExceptionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargetClass;
+
+import junit.framework.TestCase;
+
+import java.util.zip.ZipException;
+
+@TestTargetClass(ZipException.class)
+public class ZipExceptionTest extends TestCase {
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "ZipException",
+ args = {}
+ )
+ public void testZipException() {
+ ZipException zz = new ZipException();
+ assertEquals(zz.getMessage(), null);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "ZipException",
+ args = {java.lang.String.class}
+ )
+ public void testZipExceptionLjava_lang_String() {
+ ZipException zz = new ZipException("Test");
+ assertEquals(zz.getMessage(), "Test");
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
new file mode 100644
index 0000000..3fe23a7
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
@@ -0,0 +1,515 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.AndroidOnly;
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import tests.support.Support_PlatformFile;
+import tests.support.resource.Support_Resources;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Permission;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+@TestTargetClass(ZipFile.class)
+public class ZipFileTest extends junit.framework.TestCase {
+
+ // BEGIN android-added
+ public byte[] getAllBytesFromStream(InputStream is) throws IOException {
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ byte[] buf = new byte[666];
+ int iRead;
+ int off;
+ while (is.available() > 0) {
+ iRead = is.read(buf, 0, buf.length);
+ if (iRead > 0) bs.write(buf, 0, iRead);
+ }
+ return bs.toByteArray();
+ }
+
+ // END android-added
+
+ // the file hyts_zipFile.zip in setup must be included as a resource
+ private String tempFileName;
+
+ private ZipFile zfile;
+
+ // custom security manager
+ SecurityManager sm = new SecurityManager() {
+ final String forbidenPermissionAction = "read";
+
+
+
+ public void checkPermission(Permission perm) {
+ if (perm.getActions().equals(forbidenPermissionAction)) {
+ throw new SecurityException();
+ }
+ }
+ };
+
+ /**
+ * @tests java.util.zip.ZipFile#ZipFile(java.io.File)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "setUp procedure checks this type of constructor.",
+ method = "ZipFile",
+ args = {java.io.File.class}
+ )
+ public void test_ConstructorLjava_io_File() {
+ // Test for method java.util.zip.ZipFile(java.io.File)
+ assertTrue("Used to test", true);
+ }
+
+ /**
+ * @tests java.util.zip.ZipFile#ZipFile(java.io.File, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "ZipFile",
+ args = {java.io.File.class, int.class}
+ )
+ public void test_ConstructorLjava_io_FileI() throws IOException {
+ zfile.close(); // about to reopen the same temp file
+ File file = new File(tempFileName);
+ ZipFile zip = new ZipFile(file, ZipFile.OPEN_DELETE | ZipFile.OPEN_READ);
+ zip.close();
+ assertTrue("Zip should not exist", !file.exists());
+ file = new File(tempFileName);
+ file.delete();
+ try {
+ zip = new ZipFile(file, ZipFile.OPEN_READ);
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ // IOException can not be checked throws ZipException in case of IO
+ // problems.
+ SecurityManager oldSm = System.getSecurityManager();
+ System.setSecurityManager(sm);
+ try {
+ file = new File(tempFileName);
+ zip = new ZipFile(file, ZipFile.OPEN_READ);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ System.setSecurityManager(oldSm);
+ }
+ file = new File(tempFileName);
+ try {
+ zip = new ZipFile(file, -1);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @throws IOException
+ * @tests java.util.zip.ZipFile#ZipFile(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test contains empty brackets.",
+ method = "ZipFile",
+ args = {java.lang.String.class}
+ )
+ public void test_ConstructorLjava_lang_String() throws IOException {
+ String oldUserDir = System.getProperty("user.dir");
+ System.setProperty("user.dir", System.getProperty("java.io.tmpdir"));
+
+ zfile.close(); // about to reopen the same temp file
+ ZipFile zip = new ZipFile(tempFileName);
+ zip.close();
+ File file = File.createTempFile("zip", "tmp");
+ try {
+ zip = new ZipFile(file.getName());
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+ file.delete();
+ // IOException can not be checked throws ZipException in case of IO
+ // problems.
+ SecurityManager oldSm = System.getSecurityManager();
+ System.setSecurityManager(sm);
+ try {
+ zip = new ZipFile(tempFileName);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ System.setSecurityManager(oldSm);
+ System.setProperty("user.dir", oldUserDir);
+ }
+ }
+
+ protected ZipEntry test_finalize1(ZipFile zip) {
+ return zip.getEntry("File1.txt");
+ }
+
+ protected ZipFile test_finalize2(File file) throws IOException {
+ return new ZipFile(file);
+ }
+
+ /**
+ * @tests java.util.zip.ZipFile#finalize()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "finalize",
+ args = {}
+ )
+ public void test_finalize() throws IOException {
+ InputStream in = Support_Resources.getStream("hyts_ZipFile.zip");
+ File file = Support_Resources.createTempFile(".jar");
+ OutputStream out = new FileOutputStream(file);
+ int result;
+ byte[] buf = new byte[4096];
+ while ((result = in.read(buf)) != -1) {
+ out.write(buf, 0, result);
+ }
+ in.close();
+ out.close();
+ /*
+ * ZipFile zip = new ZipFile(file); ZipEntry entry1 =
+ * zip.getEntry("File1.txt"); assertNotNull("Did not find entry",
+ * entry1); entry1 = null; zip = null;
+ */
+
+ assertNotNull("Did not find entry",
+ test_finalize1(test_finalize2(file)));
+ System.gc();
+ System.gc();
+ System.runFinalization();
+ file.delete();
+ assertTrue("Zip should not exist", !file.exists());
+ }
+
+ /**
+ * @throws IOException
+ * @tests java.util.zip.ZipFile#close()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "close",
+ args = {}
+ )
+ public void test_close() throws IOException {
+ // Test for method void java.util.zip.ZipFile.close()
+ File fl = new File(tempFileName);
+ ZipFile zf = new ZipFile(fl);
+ InputStream is1 = zf.getInputStream(zf.getEntry("File1.txt"));
+ InputStream is2 = zf.getInputStream(zf.getEntry("File2.txt"));
+
+ is1.read();
+ is2.read();
+
+ zf.close();
+
+ try {
+ is1.read();
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+
+ try {
+ is2.read();
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipFile#entries()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "entries",
+ args = {}
+ )
+ public void test_entries() {
+ // Test for method java.util.Enumeration java.util.zip.ZipFile.entries()
+ Enumeration<? extends ZipEntry> enumer = zfile.entries();
+ int c = 0;
+ while (enumer.hasMoreElements()) {
+ ++c;
+ enumer.nextElement();
+ }
+ assertTrue("Incorrect number of entries returned: " + c, c == 6);
+
+ try {
+ Enumeration<? extends ZipEntry> enumeration = zfile.entries();
+ zfile.close();
+ zfile = null;
+ boolean pass = false;
+ try {
+ enumeration.hasMoreElements();
+ } catch (IllegalStateException e) {
+ pass = true;
+ }
+ assertTrue("did not detect closed jar file", pass);
+ } catch (Exception e) {
+ fail("Exception during entries test: " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipFile#getEntry(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "getEntry",
+ args = {java.lang.String.class}
+ )
+ public void test_getEntryLjava_lang_String() throws IOException {
+ // Test for method java.util.zip.ZipEntry
+ // java.util.zip.ZipFile.getEntry(java.lang.String)
+ java.util.zip.ZipEntry zentry = zfile.getEntry("File1.txt");
+ assertNotNull("Could not obtain ZipEntry", zentry);
+ int r;
+ InputStream in;
+
+ zentry = zfile.getEntry("testdir1/File1.txt");
+ assertNotNull("Could not obtain ZipEntry: testdir1/File1.txt", zentry);
+ zentry = zfile.getEntry("testdir1/");
+ assertNotNull("Could not obtain ZipEntry: testdir1/", zentry);
+ in = zfile.getInputStream(zentry);
+ assertNotNull("testdir1/ should not have null input stream", in);
+ r = in.read();
+ in.close();
+ assertEquals("testdir1/ should not contain data", -1, r);
+
+ zentry = zfile.getEntry("testdir1/testdir1");
+ assertNotNull("Could not obtain ZipEntry: testdir1/testdir1", zentry);
+ in = zfile.getInputStream(zentry);
+ byte[] buf = new byte[256];
+ r = in.read(buf);
+ in.close();
+ assertEquals("incorrect contents", "This is also text", new String(buf,
+ 0, r));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "Strange test that succeeds in Android but not against RI.",
+ method = "getEntry",
+ args = {java.lang.String.class}
+ )
+ @AndroidOnly("God knows why!")
+ public void test_getEntryLjava_lang_String_AndroidOnly() throws IOException {
+ java.util.zip.ZipEntry zentry = zfile.getEntry("File1.txt");
+ assertNotNull("Could not obtain ZipEntry", zentry);
+ int r;
+ InputStream in;
+
+ zentry = zfile.getEntry("testdir1");
+ assertNotNull("Could not obtain ZipEntry: testdir1", zentry);
+ in = zfile.getInputStream(zentry);
+ assertNotNull("testdir1 should not have null input stream", in);
+ r = in.read();
+ in.close();
+ assertEquals("testdir1 should not contain data", -1, r);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "IllegalStateException checking.",
+ method = "getEntry",
+ args = {java.lang.String.class}
+ )
+ @KnownFailure("Android does not throw IllegalStateException when using getEntry() after close().")
+ public void test_getEntryLjava_lang_String_Ex() throws IOException {
+ java.util.zip.ZipEntry zentry = zfile.getEntry("File1.txt");
+ assertNotNull("Could not obtain ZipEntry", zentry);
+ int r;
+ InputStream in;
+
+ zfile.close();
+ try {
+ zentry = zfile.getEntry("File2.txt");
+ fail("IllegalStateException expected"); // Android fails here!
+ } catch (IllegalStateException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @throws IOException
+ * @tests java.util.zip.ZipFile#getInputStream(java.util.zip.ZipEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_getInputStreamLjava_util_zip_ZipEntry() throws IOException {
+ // Test for method java.io.InputStream
+ // java.util.zip.ZipFile.getInputStream(java.util.zip.ZipEntry)
+ ZipEntry zentry = null;
+ InputStream is = null;
+ try {
+ zentry = zfile.getEntry("File1.txt");
+ is = zfile.getInputStream(zentry);
+ byte[] rbuf = new byte[1000];
+ int r;
+ is.read(rbuf, 0, r = (int) zentry.getSize());
+ assertEquals("getInputStream read incorrect data", "This is text",
+ new String(rbuf, 0, r));
+ } catch (java.io.IOException e) {
+ fail("IOException during getInputStream");
+ } finally {
+ try {
+ is.close();
+ } catch (java.io.IOException e) {
+ fail("Failed to close input stream");
+ }
+ }
+
+ zentry = zfile.getEntry("File2.txt");
+ zfile.close();
+ try {
+ is = zfile.getInputStream(zentry);
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException ee) {
+ // expected
+ }
+
+ // ZipException can not be checked. Stream object returned or null.
+ }
+
+ /**
+ * @tests java.util.zip.ZipFile#getName()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getName",
+ args = {}
+ )
+ public void test_getName() {
+ // Test for method java.lang.String java.util.zip.ZipFile.getName()
+ assertTrue("Returned incorrect name: " + zfile.getName(), zfile
+ .getName().equals(tempFileName));
+ }
+
+ /**
+ * @throws IOException
+ * @tests java.util.zip.ZipFile#size()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "size",
+ args = {}
+ )
+ @KnownFailure("IllegalStateException not thrown when using ZipFile.size() after close().")
+ public void test_size() throws IOException {
+ assertEquals(6, zfile.size());
+ zfile.close();
+ try {
+ zfile.size();
+ fail("IllegalStateException expected"); // Android fails here!
+ } catch (IllegalStateException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * Sets up the fixture, for example, open a network connection. This method
+ * is called before a test is executed.
+ */
+ @Override
+ protected void setUp() {
+ try {
+ // BEGIN android-changed
+ // Create a local copy of the file since some tests want to alter
+ // information.
+ tempFileName = System.getProperty("java.io.tmpdir");
+ String separator = System.getProperty("file.separator");
+ if (tempFileName.charAt(tempFileName.length() - 1) == separator
+ .charAt(0)) {
+ tempFileName = Support_PlatformFile.getNewPlatformFile(
+ tempFileName, "gabba.zip");
+ } else {
+ tempFileName = Support_PlatformFile.getNewPlatformFile(
+ tempFileName + separator, "gabba.zip");
+ }
+
+ File f = new File(tempFileName);
+ f.delete();
+ InputStream is = Support_Resources.getStream("hyts_ZipFile.zip");
+ FileOutputStream fos = new FileOutputStream(f);
+ // END android-changed
+ byte[] rbuf = getAllBytesFromStream(is);
+ fos.write(rbuf, 0, rbuf.length);
+ is.close();
+ fos.close();
+ zfile = new ZipFile(f);
+ } catch (Exception e) {
+ System.out.println("Exception during ZipFile setup:");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Tears down the fixture, for example, close a network connection. This
+ * method is called after a test is executed.
+ */
+ @Override
+ protected void tearDown() {
+ try {
+ if (zfile != null) {
+ // Note zfile is a user-defined zip file used by other tests and
+ // should not be deleted
+ zfile.close();
+ tempFileName = System.getProperty("java.io.tmpdir");
+ String separator = System.getProperty("file.separator");
+ if (tempFileName.charAt(tempFileName.length() - 1) == separator
+ .charAt(0)) {
+ tempFileName = Support_PlatformFile.getNewPlatformFile(
+ tempFileName, "gabba.zip");
+ } else {
+ tempFileName = Support_PlatformFile.getNewPlatformFile(
+ tempFileName + separator, "gabba.zip");
+ }
+
+ File f = new File(tempFileName);
+ f.delete();
+ }
+ } catch (Exception e) {
+ }
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipInputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipInputStreamTest.java
new file mode 100644
index 0000000..bdab74a
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipInputStreamTest.java
@@ -0,0 +1,419 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+
+import junit.framework.TestCase;
+
+import tests.support.resource.Support_Resources;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+@TestTargetClass(ZipInputStream.class)
+public class ZipInputStreamTest extends TestCase {
+ // the file hyts_zipFile.zip used in setup needs to included as a resource
+ private ZipEntry zentry;
+
+ private ZipInputStream zis;
+
+ private byte[] zipBytes;
+
+ private byte[] dataBytes = "Some data in my file".getBytes();
+
+ @Override
+ protected void setUp() {
+ try {
+ InputStream is = Support_Resources.getStream("hyts_ZipFile.zip");
+ if (is == null) {
+ System.out.println("file hyts_ZipFile.zip can not be found");
+ }
+ zis = new ZipInputStream(is);
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ZipOutputStream zos = new ZipOutputStream(bos);
+ ZipEntry entry = new ZipEntry("myFile");
+ zos.putNextEntry(entry);
+ zos.write(dataBytes);
+ zos.closeEntry();
+ zos.close();
+ zipBytes = bos.toByteArray();
+ } catch (Exception e) {
+ System.out.println("Exception during ZipFile setup:");
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected void tearDown() {
+ if (zis != null) {
+ try {
+ zis.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipInputStream#ZipInputStream(java.io.InputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "ZipInputStream",
+ args = {java.io.InputStream.class}
+ )
+ public void test_ConstructorLjava_io_InputStream() throws Exception {
+ zentry = zis.getNextEntry();
+ zis.closeEntry();
+ }
+
+ /**
+ * @tests java.util.zip.ZipInputStream#close()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "close",
+ args = {}
+ )
+ public void test_close() {
+ try {
+ zis.close();
+ byte[] rbuf = new byte[10];
+ zis.read(rbuf, 0, 1);
+ } catch (IOException e) {
+ return;
+ }
+ fail("Read data after stream was closed");
+ }
+
+ /**
+ * @tests java.util.zip.ZipInputStream#close()
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "Checks calling method two times",
+ method = "close",
+ args = {}
+ )
+ public void test_close2() throws Exception {
+ // Regression for HARMONY-1101
+ zis.close();
+ // another call to close should NOT cause an exception
+ zis.close();
+ }
+
+ /**
+ * @tests java.util.zip.ZipInputStream#closeEntry()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "closeEntry",
+ args = {}
+ )
+ public void test_closeEntry() throws Exception {
+ zentry = zis.getNextEntry();
+ zis.closeEntry();
+ zentry = zis.getNextEntry();
+ zis.close();
+ try {
+ zis.closeEntry();
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ FileInputStream fis = new FileInputStream(new File(resources,
+ "Broken_manifest.jar"));
+
+ ZipInputStream zis1 = new ZipInputStream(fis);
+
+ try {
+ for (int i = 0; i < 6; i++) {
+ zis1.getNextEntry();
+ zis1.closeEntry();
+ }
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "close",
+ args = {}
+ )
+ @KnownFailure("The behaviour is different from RI, but not neccessarily wrong.")
+ public void test_closeAfterException() throws Exception {
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ FileInputStream fis = new FileInputStream(new File(resources,
+ "Broken_manifest.jar"));
+
+ ZipInputStream zis1 = new ZipInputStream(fis);
+
+ try {
+ for (int i = 0; i < 6; i++) {
+ zis1.getNextEntry();
+ }
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+
+ zis1.close(); // Android throws exception here, but RI only when getNextEntry/read/skip are called.
+ try {
+ zis1.getNextEntry();
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipInputStream#getNextEntry()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getNextEntry",
+ args = {}
+ )
+ public void test_getNextEntry() throws Exception {
+ assertNotNull("getNextEntry failed", zis.getNextEntry());
+
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ FileInputStream fis = new FileInputStream(new File(resources,
+ "Broken_manifest.jar"));
+
+ ZipInputStream zis1 = new ZipInputStream(fis);
+
+ try {
+ for (int i = 0; i < 6; i++) {
+ zis1.getNextEntry();
+ }
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+
+ try {
+ zis1.close(); // Android throws exception here, already!
+ zis1.getNextEntry(); // But RI here, only!
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipInputStream#read(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "read",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_read$BII() throws Exception {
+ zentry = zis.getNextEntry();
+ byte[] rbuf = new byte[(int) zentry.getSize()];
+ int r = zis.read(rbuf, 0, rbuf.length);
+ new String(rbuf, 0, r);
+ assertEquals("Failed to read entry", 12, r);
+
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ FileInputStream fis = new FileInputStream(new File(resources,
+ "Broken_manifest.jar"));
+
+ ZipInputStream zis1 = new ZipInputStream(fis);
+
+ zis1.getNextEntry();
+ zis1.getNextEntry();
+
+ rbuf = new byte[100];
+
+ try {
+ zis1.read(rbuf, 10, 90);
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+
+ try {
+ zis1.close(); // Android throws exception here, already!
+ zis1.read(rbuf, 10, 90); // But RI here, only!
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipInputStream#skip(long)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "skip",
+ args = {long.class}
+ )
+ public void test_skipJ() throws Exception {
+ zentry = zis.getNextEntry();
+ byte[] rbuf = new byte[(int) zentry.getSize()];
+ zis.skip(2);
+ int r = zis.read(rbuf, 0, rbuf.length);
+ assertEquals("Failed to skip data", 10, r);
+
+ zentry = zis.getNextEntry();
+ zentry = zis.getNextEntry();
+ long s = zis.skip(1025);
+ assertTrue("invalid skip: " + s, s == 1025);
+
+ ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(
+ zipBytes));
+ zis.getNextEntry();
+ long skipLen = dataBytes.length / 2;
+ assertEquals("Assert 0: failed valid skip", skipLen, zis.skip(skipLen));
+ zis.skip(dataBytes.length);
+ assertEquals("Assert 1: performed invalid skip", 0, zis.skip(1));
+ assertEquals("Assert 2: failed zero len skip", 0, zis.skip(0));
+ try {
+ zis.skip(-1);
+ fail("Assert 3: Expected Illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ FileInputStream fis = new FileInputStream(new File(resources,
+ "Broken_manifest.jar"));
+
+ ZipInputStream zis1 = new ZipInputStream(fis);
+
+ zis1.getNextEntry();
+ zis1.getNextEntry();
+
+ try {
+ zis1.skip(10);
+ fail("ZipException expected");
+ } catch (ZipException ee) {
+ // expected
+ }
+
+ try {
+ zis1.close(); // Android throws exception here, already!
+ zis1.skip(10); // But RI here, only!
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "available",
+ args = {}
+ )
+ @KnownFailure("Needs investigation!!!")
+ public void test_available() throws Exception {
+
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ File fl = new File(resources, "Broken_manifest.jar");
+ FileInputStream fis = new FileInputStream(fl);
+
+ ZipInputStream zis1 = new ZipInputStream(fis);
+ int i = 0;
+System.out.println(fl.length());
+ for (i = 0; i < fl.length(); i++) {
+//System.out.println(i);
+ zis1.skip(1);
+//System.out.println("Skipped 1");
+int avail = zis1.available();
+//System.out.println(avail);
+ if (zis1.available() == 0) break; // RI breaks at i = 0 already; Android loops till the end!
+//System.out.println("Looping...");
+ }
+ if (i == fl.length()) {
+ fail("ZipInputStream.available or ZipInputStream.skip does not working properly");
+ }
+ assertTrue(zis1.available() == 0);
+ zis1.skip(1);
+ assertFalse(zis.available() == 0);
+ zis1.close();
+ try {
+ zis1.available();
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ class Mock_ZipInputStream extends ZipInputStream {
+ boolean createFlag = false;
+
+ public Mock_ZipInputStream(InputStream arg0) {
+ super(arg0);
+ }
+
+ boolean getCreateFlag() {
+ return createFlag;
+ }
+
+ protected ZipEntry createZipEntry(String name) {
+ createFlag = true;
+ return super.createZipEntry(name);
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "createZipEntry",
+ args = {java.lang.String.class}
+ )
+ public void test_createZipEntryLjava_lang_String() throws Exception {
+
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
+ File fl = new File(resources, "Broken_manifest.jar");
+ FileInputStream fis = new FileInputStream(fl);
+
+ Mock_ZipInputStream zis1 = new Mock_ZipInputStream(fis);
+ assertFalse(zis1.getCreateFlag());
+ zis1.getNextEntry();
+ assertTrue(zis1.getCreateFlag());
+ }
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
new file mode 100644
index 0000000..9a5f63a
--- /dev/null
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
@@ -0,0 +1,371 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.tests.java.util.zip;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+@TestTargetClass(ZipOutputStream.class)
+public class ZipOutputStreamTest extends junit.framework.TestCase {
+
+ ZipOutputStream zos;
+
+ ByteArrayOutputStream bos;
+
+ ZipInputStream zis;
+
+ static final String data = "HelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorld";
+
+ /**
+ * @tests java.util.zip.ZipOutputStream#close()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Can not check IOException.",
+ method = "close",
+ args = {}
+ )
+ public void test_close() throws Exception {
+ try {
+ zos.close();
+ fail("Close on empty stream failed to throw exception");
+ } catch (ZipException e) {
+ // expected
+ }
+
+ zos = new ZipOutputStream(bos);
+ zos.putNextEntry(new ZipEntry("XX"));
+ zos.closeEntry();
+ zos.close();
+
+ // Regression for HARMONY-97
+ ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());
+ zos.putNextEntry(new ZipEntry("myFile"));
+ zos.close();
+ zos.close(); // Should be a no-op
+ }
+
+ /**
+ * @tests java.util.zip.ZipOutputStream#closeEntry()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "ZipException can not be checked.",
+ method = "closeEntry",
+ args = {}
+ )
+ public void test_closeEntry() throws IOException {
+ ZipEntry ze = new ZipEntry("testEntry");
+ ze.setTime(System.currentTimeMillis());
+ zos.putNextEntry(ze);
+ zos.write("Hello World".getBytes());
+ zos.closeEntry();
+ assertTrue("closeEntry failed to update required fields",
+ ze.getSize() == 11 && ze.getCompressedSize() == 13);
+ ze = new ZipEntry("testEntry1");
+ zos.close();
+ try {
+ zos.closeEntry();
+ fail("IOException expected");
+ } catch (IOException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipOutputStream#finish()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "ZipException can not be checked.",
+ method = "finish",
+ args = {}
+ )
+ public void test_finish() throws Exception {
+ ZipEntry ze = new ZipEntry("test");
+ zos.putNextEntry(ze);
+ zos.write("Hello World".getBytes());
+ zos.finish();
+ assertEquals("Finish failed to closeCurrentEntry", 11, ze.getSize());
+
+ ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());
+ zos.putNextEntry(new ZipEntry("myFile"));
+ zos.finish();
+ zos.close();
+ try {
+ zos.finish();
+ fail("Assert 0: Expected IOException");
+ } catch (IOException e) {
+ // Expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipOutputStream#putNextEntry(java.util.zip.ZipEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "ZipException can not be checked.",
+ method = "putNextEntry",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_putNextEntryLjava_util_zip_ZipEntry() throws IOException {
+ ZipEntry ze = new ZipEntry("testEntry");
+ ze.setTime(System.currentTimeMillis());
+ zos.putNextEntry(ze);
+ zos.write("Hello World".getBytes());
+ zos.closeEntry();
+ zos.close();
+ zis = new ZipInputStream(new ByteArrayInputStream(bos.toByteArray()));
+ ZipEntry ze2 = zis.getNextEntry();
+ zis.closeEntry();
+ assertTrue("Failed to write correct entry", ze.getName().equals(
+ ze2.getName())
+ && ze.getCrc() == ze2.getCrc());
+ try {
+ zos.putNextEntry(ze);
+ fail("Entry with incorrect setting failed to throw exception");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipOutputStream#setComment(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setComment",
+ args = {java.lang.String.class}
+ )
+ public void test_setCommentLjava_lang_String() {
+ // There is no way to get the comment back, so no way to determine if
+ // the comment is set correct
+ try {
+ zos.setComment("test setComment");
+ } catch (Exception e) {
+ fail("Trying to set comment failed");
+ }
+ try {
+ zos.setComment(new String(new byte[0xFFFF + 1]));
+ fail("Comment over 0xFFFF in length should throw exception");
+ } catch (IllegalArgumentException e) {
+ // Passed
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipOutputStream#setLevel(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setLevel",
+ args = {int.class}
+ )
+ public void test_setLevelI() throws IOException {
+ ZipEntry ze = new ZipEntry("test");
+ zos.putNextEntry(ze);
+ zos.write(data.getBytes());
+ zos.closeEntry();
+ long csize = ze.getCompressedSize();
+ zos.setLevel(9); // Max Compression
+ zos.putNextEntry(ze = new ZipEntry("test2"));
+ zos.write(data.getBytes());
+ zos.closeEntry();
+ assertTrue("setLevel failed", csize <= ze.getCompressedSize());
+ try {
+ zos.setLevel(-9); // Max Compression
+ fail("IllegalArgumentException ecpected.");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipOutputStream#setMethod(int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "setMethod",
+ args = {int.class}
+ )
+ public void test_setMethodI() throws IOException {
+ ZipEntry ze = new ZipEntry("test");
+ zos.setMethod(ZipOutputStream.STORED);
+ CRC32 tempCrc = new CRC32();
+ tempCrc.update(data.getBytes());
+ ze.setCrc(tempCrc.getValue());
+ ze.setSize(new String(data).length());
+ zos.putNextEntry(ze);
+ zos.write(data.getBytes());
+ zos.closeEntry();
+ long csize = ze.getCompressedSize();
+ zos.setMethod(ZipOutputStream.DEFLATED);
+ zos.putNextEntry(ze = new ZipEntry("test2"));
+ zos.write(data.getBytes());
+ zos.closeEntry();
+ assertTrue("setLevel failed", csize >= ze.getCompressedSize());
+ try {
+ zos.setMethod(-ZipOutputStream.DEFLATED);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException ee) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipOutputStream#write(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "write",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_write$BII() throws IOException {
+ ZipEntry ze = new ZipEntry("test");
+ zos.putNextEntry(ze);
+ zos.write(data.getBytes());
+ zos.closeEntry();
+ zos.close();
+ zos = null;
+ zis = new ZipInputStream(new ByteArrayInputStream(bos.toByteArray()));
+ zis.getNextEntry();
+ byte[] b = new byte[data.length()];
+ int r = 0;
+ int count = 0;
+ while (count != b.length && (r = zis.read(b, count, b.length)) != -1) {
+ count += r;
+ }
+ zis.closeEntry();
+ assertTrue("Write failed to write correct bytes", new String(b)
+ .equals(data));
+
+ File f = File.createTempFile("testZip", "tst");
+ f.deleteOnExit();
+ FileOutputStream stream = new FileOutputStream(f);
+ ZipOutputStream zip = new ZipOutputStream(stream);
+ zip.setMethod(ZipEntry.STORED);
+
+ try {
+ zip.putNextEntry(new ZipEntry("Second"));
+ fail("Not set an entry. Should have thrown ZipException.");
+ } catch (ZipException e) {
+ // expected -- We have not set an entry
+ }
+
+ try {
+ // We try to write data without entry
+ zip.write(new byte[2]);
+ fail("Writing data without an entry. Should have thrown IOException");
+ } catch (IOException e) {
+ // expected
+ }
+
+ try {
+ // Try to write without an entry and with nonsense offset and
+ // length
+ zip.write(new byte[2], 0, 12);
+ fail("Writing data without an entry. Should have thrown IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.util.zip.ZipOutputStream#write(byte[], int, int)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Regression",
+ method = "write",
+ args = {byte[].class, int.class, int.class}
+ )
+ public void test_write$BII_2() throws IOException {
+ // Regression for HARMONY-577
+ File f1 = File.createTempFile("testZip1", "tst");
+ f1.deleteOnExit();
+ FileOutputStream stream1 = new FileOutputStream(f1);
+ ZipOutputStream zip1 = new ZipOutputStream(stream1);
+ zip1.putNextEntry(new ZipEntry("one"));
+ zip1.setMethod(ZipOutputStream.STORED);
+ zip1.setMethod(ZipEntry.STORED);
+
+ zip1.write(new byte[2]);
+
+ try {
+ zip1.putNextEntry(new ZipEntry("Second"));
+ fail("ZipException expected");
+ } catch (ZipException e) {
+ // expected - We have not set an entry
+ }
+
+ try {
+ zip1.write(new byte[2]); // try to write data without entry
+ fail("expected IOE there");
+ } catch (IOException e2) {
+ // expected
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ zos = new ZipOutputStream(bos = new ByteArrayOutputStream());
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ if (zos != null) {
+ zos.close();
+ }
+ if (zis != null) {
+ zis.close();
+ }
+ } catch (Exception e) {
+ }
+ super.tearDown();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "See setUp procedure for more info.",
+ method = "ZipOutputStream",
+ args = {java.io.OutputStream.class}
+ )
+ public void test_ConstructorLjava_io_OutputStream() {
+ assertTrue(true);
+ }
+}
diff --git a/archive/src/test/java/tests/archive/AllTests.java b/archive/src/test/java/tests/archive/AllTests.java
new file mode 100644
index 0000000..a5c461c
--- /dev/null
+++ b/archive/src/test/java/tests/archive/AllTests.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.archive;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(AllTests.suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite = tests.TestSuiteFactory.createTestSuite("All Archive test suites");
+ // $JUnit-BEGIN$
+ suite.addTest(org.apache.harmony.archive.tests.java.util.jar.AllTests
+ .suite());
+ suite.addTest(org.apache.harmony.archive.tests.java.util.zip.AllTests
+ .suite());
+ // $JUnit-END$
+ return suite;
+ }
+}