diff options
author | Elliott Hughes <enh@google.com> | 2010-04-07 18:27:01 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2010-04-08 11:53:06 -0700 |
commit | 60eb73fc9f0636c3d0bda5baba641a5f88f8476f (patch) | |
tree | 7e642b1535639521b13b7158d2f9d41b11896cc4 | |
parent | ac9ea76b7b57069f251907f76f5e1573d2da4cd6 (diff) | |
download | libcore-60eb73fc9f0636c3d0bda5baba641a5f88f8476f.zip libcore-60eb73fc9f0636c3d0bda5baba641a5f88f8476f.tar.gz libcore-60eb73fc9f0636c3d0bda5baba641a5f88f8476f.tar.bz2 |
Add Java 6's new java.util.zip API.
This passes all but four of the harmony tests. The others fail because our
Deflater works differently to theirs; we already fail the corresponding
Deflater test.
The only jtreg test for ZipError neither passes nor fails: it appears that
this can only be thrown on Windows.
Bug: 2497395
Change-Id: I79687495da42507dda692c890ec939bdbc9be2b3
11 files changed, 1258 insertions, 36 deletions
diff --git a/archive/src/main/java/java/util/zip/DeflaterInputStream.java b/archive/src/main/java/java/util/zip/DeflaterInputStream.java new file mode 100644 index 0000000..13d65e4 --- /dev/null +++ b/archive/src/main/java/java/util/zip/DeflaterInputStream.java @@ -0,0 +1,243 @@ +/* + * 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.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * An {@code InputStream} filter to compress data. Callers read + * compressed data in the "deflate" format from the uncompressed + * underlying stream. + * @since 1.6 + * @hide + */ +public class DeflaterInputStream extends FilterInputStream { + private static final int DEFAULT_BUFFER_SIZE = 1024; + + protected final Deflater deflater; + protected final byte[] buf; + + private boolean closed = false; + private boolean available = true; + + /** + * Constructs a {@code DeflaterInputStream} with a new {@code Deflater} and an + * implementation-defined default internal buffer size. {@code in} is a source of + * uncompressed data, and this stream will be a source of compressed data. + * + * @param in the source {@code InputStream} + */ + public DeflaterInputStream(InputStream in) { + this(in, new Deflater(), DEFAULT_BUFFER_SIZE); + } + + /** + * Constructs a {@code DeflaterInputStream} with the given {@code Deflater} and an + * implementation-defined default internal buffer size. {@code in} is a source of + * uncompressed data, and this stream will be a source of compressed data. + * + * @param in the source {@code InputStream} + * @param deflater the {@code Deflater} to be used for compression + */ + public DeflaterInputStream(InputStream in, Deflater deflater) { + this(in, deflater, DEFAULT_BUFFER_SIZE); + } + + /** + * Constructs a {@code DeflaterInputStream} with the given {@code Deflater} and + * given internal buffer size. {@code in} is a source of + * uncompressed data, and this stream will be a source of compressed data. + * + * @param in the source {@code InputStream} + * @param deflater the {@code Deflater} to be used for compression + * @param bufferSize the length in bytes of the internal buffer + */ + public DeflaterInputStream(InputStream in, Deflater deflater, int bufferSize) { + super(in); + if (in == null || deflater == null) { + throw new NullPointerException(); + } + if (bufferSize <= 0) { + throw new IllegalArgumentException(); + } + this.deflater = deflater; + this.buf = new byte[bufferSize]; + } + + /** + * Closes the underlying input stream and discards any remaining uncompressed + * data. + */ + @Override + public void close() throws IOException { + closed = true; + deflater.end(); + in.close(); + } + + /** + * Reads a byte from the compressed input stream. The result will be a byte of compressed + * data corresponding to an uncompressed byte or bytes read from the underlying stream. + * + * @return the byte or -1 if the end of the stream has been reached. + */ + @Override + public int read() throws IOException { + byte[] result = new byte[1]; + if (read(result, 0, 1) == -1) { + return -1; + } + return result[0] & 0xff; + } + + /** + * Reads compressed data into a byte buffer. The result will be bytes of compressed + * data corresponding to an uncompressed byte or bytes read from the underlying stream. + * + * @param b + * the byte buffer that compressed data will be read into. + * @param off + * the offset in the byte buffer where compressed data will start + * to be read into. + * @param len + * the length of the compressed data that is expected to read. + * @return the number of bytes read or -1 if the end of the compressed input + * stream has been reached. + */ + @Override + public int read(byte[] b, int off, int len) throws IOException { + checkClosed(); + if (b == null) { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + if (len == 0) { + return 0; + } + + if (!available) { + return -1; + } + + int count = 0; + while (count < len && !deflater.finished()) { + if (deflater.needsInput()) { + // read data from input stream + int byteCount = in.read(buf); + if (byteCount == -1) { + deflater.finish(); + } else { + deflater.setInput(buf, 0, byteCount); + } + } + int byteCount = deflater.deflate(buf, 0, Math.min(buf.length, len - count)); + if (byteCount == -1) { + break; + } + System.arraycopy(buf, 0, b, off + count, byteCount); + count += byteCount; + } + if (count == 0) { + count = -1; + available = false; + } + return count; + } + + /** + * {@inheritDoc} + * <p>Note: if {@code n > Integer.MAX_VALUE}, this stream will only attempt to + * skip {@code Integer.MAX_VALUE} bytes. + */ + @Override + public long skip(long n) throws IOException { + if (n < 0) { + throw new IllegalArgumentException(); + } + if (n > Integer.MAX_VALUE) { + n = Integer.MAX_VALUE; + } + checkClosed(); + + int remaining = (int) n; + byte[] tmp = new byte[Math.min(remaining, DEFAULT_BUFFER_SIZE)]; + while (remaining > 0) { + int count = read(tmp, 0, Math.min(remaining, tmp.length)); + if (count == -1) { + break; + } + remaining -= count; + } + return n - remaining; + } + + /** + * Returns 0 when when this stream has exhausted its input; and 1 otherwise. + * A result of 1 does not guarantee that further bytes can be returned, + * with or without blocking. + * + * <p>Although consistent with the RI, this behavior is inconsistent with + * {@link InputStream#available()}, and violates the <a + * href="http://en.wikipedia.org/wiki/Liskov_substitution_principle">Liskov + * Substitution Principle</a>. This method should not be used. + * + * @return 0 if no further bytes are available. Otherwise returns 1, + * which suggests (but does not guarantee) that additional bytes are + * available. + * @throws IOException if this stream is closed or an error occurs + */ + @Override + public int available() throws IOException { + checkClosed(); + return available ? 1 : 0; + } + + /** + * Returns false because {@code DeflaterInputStream} does not support + * {@code mark}/{@code reset}. + */ + @Override + public boolean markSupported() { + return false; + } + + /** + * This operation is not supported and does nothing. + */ + @Override + public void mark(int limit) { + } + + /** + * This operation is not supported and throws {@code IOException}. + */ + @Override + public void reset() throws IOException { + throw new IOException(); + } + + private void checkClosed() throws IOException { + if (closed) { + throw new IOException("Stream is closed"); + } + } +} diff --git a/archive/src/main/java/java/util/zip/GZIPInputStream.java b/archive/src/main/java/java/util/zip/GZIPInputStream.java index dd0da9b..d7f412e 100644 --- a/archive/src/main/java/java/util/zip/GZIPInputStream.java +++ b/archive/src/main/java/java/util/zip/GZIPInputStream.java @@ -159,7 +159,7 @@ public class GZIPInputStream extends InflaterInputStream { @Override public int read(byte[] buffer, int off, int nbytes) throws IOException { if (closed) { - throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$ + throw new IOException("Stream is closed"); } if (eos) { return -1; diff --git a/archive/src/main/java/java/util/zip/InflaterInputStream.java b/archive/src/main/java/java/util/zip/InflaterInputStream.java index 8cd8cf2..fcaf8c15 100644 --- a/archive/src/main/java/java/util/zip/InflaterInputStream.java +++ b/archive/src/main/java/java/util/zip/InflaterInputStream.java @@ -151,12 +151,8 @@ public class InflaterInputStream extends FilterInputStream { */ @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) { + checkClosed(); + if (buffer == null) { throw new NullPointerException(); } @@ -216,9 +212,7 @@ public class InflaterInputStream extends FilterInputStream { * if an {@code IOException} occurs. */ protected void fill() throws IOException { - if (closed) { - throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$ - } + checkClosed(); // BEGIN android-only if (nativeEndBufSize > 0) { ZipFile.RAFStream is = (ZipFile.RAFStream)in; @@ -283,10 +277,7 @@ public class InflaterInputStream extends FilterInputStream { */ @Override public int available() throws IOException { - if (closed) { - // archive.1E=Stream is closed - throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$ - } + checkClosed(); if (eof) { return 0; } @@ -345,4 +336,9 @@ public class InflaterInputStream extends FilterInputStream { return false; } + private void checkClosed() throws IOException { + if (closed) { + throw new IOException("Stream is closed"); + } + } } diff --git a/archive/src/main/java/java/util/zip/InflaterOutputStream.java b/archive/src/main/java/java/util/zip/InflaterOutputStream.java new file mode 100644 index 0000000..1329393 --- /dev/null +++ b/archive/src/main/java/java/util/zip/InflaterOutputStream.java @@ -0,0 +1,171 @@ +/* + * 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; + +/** + * An {@code OutputStream} filter to decompress data. Callers write + * compressed data in the "deflate" format, and uncompressed data is + * written to the underlying stream. + * @since 1.6 + * @hide + */ +public class InflaterOutputStream extends FilterOutputStream { + private static final int DEFAULT_BUFFER_SIZE = 1024; + + protected final Inflater inflater; + protected final byte[] buf; + + private boolean closed = false; + + /** + * Constructs an {@code InflaterOutputStream} with a new {@code Inflater} and an + * implementation-defined default internal buffer size. {@code out} is a destination + * for uncompressed data, and compressed data will be written to this stream. + * + * @param out the destination {@code OutputStream} + */ + public InflaterOutputStream(OutputStream out) { + this(out, new Inflater()); + } + + /** + * Constructs an {@code InflaterOutputStream} with the given {@code Inflater} and an + * implementation-defined default internal buffer size. {@code out} is a destination + * for uncompressed data, and compressed data will be written to this stream. + * + * @param out the destination {@code OutputStream} + * @param inflater the {@code Inflater} to be used for decompression + */ + public InflaterOutputStream(OutputStream out, Inflater inflater) { + this(out, inflater, DEFAULT_BUFFER_SIZE); + } + + /** + * Constructs an {@code InflaterOutputStream} with the given {@code Inflater} and + * given internal buffer size. {@code out} is a destination + * for uncompressed data, and compressed data will be written to this stream. + * + * @param out the destination {@code OutputStream} + * @param inflater the {@code Inflater} to be used for decompression + * @param bufferSize the length in bytes of the internal buffer + */ + public InflaterOutputStream(OutputStream out, Inflater inflater, int bufferSize) { + super(out); + if (out == null || inflater == null) { + throw new NullPointerException(); + } + if (bufferSize <= 0) { + throw new IllegalArgumentException(); + } + this.inflater = inflater; + this.buf = new byte[bufferSize]; + } + + /** + * Writes remaining data into the output stream and closes the underlying + * output stream. + */ + @Override + public void close() throws IOException { + if (!closed) { + finish(); + inflater.end(); + out.close(); + closed = true; + } + } + + @Override + public void flush() throws IOException { + finish(); + out.flush(); + } + + /** + * Finishes writing current uncompressed data into the InflaterOutputStream + * without closing it. + * + * @throws IOException if an I/O error occurs, or the stream has been closed + */ + public void finish() throws IOException { + checkClosed(); + write(); + } + + /** + * Writes a byte to the decompressing output stream. {@code b} should be a byte of + * compressed input. The corresponding uncompressed data will be written to the underlying + * stream. + * + * @param b the byte + * @throws IOException if an I/O error occurs, or the stream has been closed + * @throws ZipException if a zip exception occurs. + */ + @Override + public void write(int b) throws IOException, ZipException { + write(new byte[] { (byte) b }, 0, 1); + } + + /** + * Writes bytes to the decompressing output stream. {@code b} should be an array of + * compressed input. The corresponding uncompressed data will be written to the underlying + * stream. + * + * @param b the byte array + * @param off the start offset in the byte array + * @param len the number of the bytes to take from the byte array + * @throws IOException if an I/O error occurs, or the stream has been closed + * @throws ZipException if a zip exception occurs. + * @throws NullPointerException if {@code b == null}. + * @throws IndexOutOfBoundsException if {@code off < 0 || len < 0 || off + len > b.length} + */ + @Override + public void write(byte[] b, int off, int len) throws IOException, ZipException { + checkClosed(); + if (b == null) { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + + inflater.setInput(b, off, len); + write(); + } + + private void write() throws IOException, ZipException { + try { + int inflated; + while ((inflated = inflater.inflate(buf)) > 0) { + out.write(buf, 0, inflated); + } + } catch (DataFormatException e) { + throw new ZipException(); + } + } + + private void checkClosed() throws IOException { + if (closed) { + throw new IOException(); + } + } +} diff --git a/archive/src/main/java/java/util/zip/ZipError.java b/archive/src/main/java/java/util/zip/ZipError.java new file mode 100644 index 0000000..a244d80 --- /dev/null +++ b/archive/src/main/java/java/util/zip/ZipError.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; + +/** + * Thrown when an unrecoverable ZIP error has occurred. + * @since 1.6 + * @hide + */ +public class ZipError extends InternalError { + private static final long serialVersionUID = 853973422266861979L; + + /** + * Constructs a ZipError with the given detail message. + */ + public ZipError(String s) { + super(s); + } +} diff --git a/archive/src/main/java/java/util/zip/ZipFile.java b/archive/src/main/java/java/util/zip/ZipFile.java index 6513622..a2ca35a 100644 --- a/archive/src/main/java/java/util/zip/ZipFile.java +++ b/archive/src/main/java/java/util/zip/ZipFile.java @@ -181,7 +181,7 @@ public class ZipFile implements ZipConstants { private void checkNotClosed() { if (mRaf == null) { - throw new IllegalStateException("Zip File closed."); + throw new IllegalStateException("Zip file closed"); } } @@ -458,6 +458,12 @@ public class ZipFile implements ZipConstants { @Override public int available() throws IOException { + if (closed) { + // Our superclass will throw an exception, but there's a jtreg test that + // explicitly checks that the InputStream returned from ZipFile.getInputStream + // returns 0 even when closed. + return 0; + } return super.available() == 0 ? 0 : (int) (entry.getSize() - bytesRead); } } diff --git a/archive/src/main/java/java/util/zip/ZipInputStream.java b/archive/src/main/java/java/util/zip/ZipInputStream.java index 0d55a10..14141e9 100644 --- a/archive/src/main/java/java/util/zip/ZipInputStream.java +++ b/archive/src/main/java/java/util/zip/ZipInputStream.java @@ -103,15 +103,13 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants * if an {@code IOException} occurs. */ public void closeEntry() throws IOException { - if (closed) { - throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$ - } + checkClosed(); 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$ + if (temp != null && temp.containsKey("hidden")) { return; } } @@ -301,9 +299,7 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants */ @Override public int read(byte[] buffer, int start, int length) throws IOException { - if (closed) { - throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$ - } + checkClosed(); if (inf.finished() || currentEntry == null) { return -1; } @@ -385,9 +381,7 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants @Override public int available() throws IOException { - if (closed) { - throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$ - } + checkClosed(); // The InflaterInputStream contract says we must only return 0 or 1. return (currentEntry == null || inRead < currentEntry.size) ? 1 : 0; } @@ -415,4 +409,10 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants l |= ((long) (buffer[off + 3] & 0xFF)) << 24; return l; } + + private void checkClosed() throws IOException { + if (closed) { + throw new IOException("Stream is closed"); + } + } } diff --git a/archive/src/main/java/java/util/zip/ZipOutputStream.java b/archive/src/main/java/java/util/zip/ZipOutputStream.java index e53061a..3a9bd7e 100644 --- a/archive/src/main/java/java/util/zip/ZipOutputStream.java +++ b/archive/src/main/java/java/util/zip/ZipOutputStream.java @@ -109,9 +109,7 @@ public class ZipOutputStream extends DeflaterOutputStream implements * If an error occurs closing the entry. */ public void closeEntry() throws IOException { - if (cDir == null) { - throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$ - } + checkClosed(); if (currentEntry == null) { return; } @@ -196,8 +194,9 @@ public class ZipOutputStream extends DeflaterOutputStream implements */ @Override public void finish() throws IOException { + // TODO: is there a bug here? why not checkClosed? if (out == null) { - throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$ + throw new IOException("Stream is closed"); } if (cDir == null) { return; @@ -261,10 +260,7 @@ public class ZipOutputStream extends DeflaterOutputStream implements 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$ - } + checkClosed(); if (entries.contains(ze.name)) { /* [MSG "archive.29", "Entry already exists: {0}"] */ throw new ZipException(Messages.getString("archive.29", ze.name)); //$NON-NLS-1$ @@ -450,4 +446,10 @@ public class ZipOutputStream extends DeflaterOutputStream implements } return result; } + + private void checkClosed() throws IOException { + if (cDir == null) { + throw new IOException("Stream is closed"); + } + } } 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 index 562b396..bf27661 100644 --- 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 @@ -25,19 +25,19 @@ import junit.framework.TestSuite; */ public class AllTests { public static Test suite() { - TestSuite suite = new TestSuite( - "Suite org.apache.harmony.archive.tests.java.util.zip"); - // $JUnit-BEGIN$ + TestSuite suite = new TestSuite("Suite org.apache.harmony.archive.tests.java.util.zip"); suite.addTestSuite(Adler32Test.class); suite.addTestSuite(CheckedInputStreamTest.class); suite.addTestSuite(CheckedOutputStreamTest.class); suite.addTestSuite(CRC32Test.class); suite.addTestSuite(DataFormatExceptionTest.class); + suite.addTestSuite(DeflaterInputStreamTest.class); suite.addTestSuite(DeflaterOutputStreamTest.class); suite.addTestSuite(DeflaterTest.class); suite.addTestSuite(GZIPInputStreamTest.class); suite.addTestSuite(GZIPOutputStreamTest.class); suite.addTestSuite(InflaterInputStreamTest.class); + suite.addTestSuite(InflaterOutputStreamTest.class); suite.addTestSuite(InflaterTest.class); suite.addTestSuite(ZipEntryTest.class); suite.addTestSuite(ZipExceptionTest.class); diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterInputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterInputStreamTest.java new file mode 100644 index 0000000..9ed0f67 --- /dev/null +++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterInputStreamTest.java @@ -0,0 +1,378 @@ +/* + * 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 java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.Deflater; +import java.util.zip.DeflaterInputStream; + +import junit.framework.TestCase; + +public class DeflaterInputStreamTest extends TestCase { + + String testStr = "Hi,this is a test"; + + InputStream is; + + /** + * @tests DeflaterInputStream#available() + */ + public void testAvailable() throws IOException { + byte[] buf = new byte[1024]; + DeflaterInputStream dis = new DeflaterInputStream(is); + assertEquals(1, dis.available()); + assertEquals(120, dis.read()); + assertEquals(1, dis.available()); + assertEquals(22, dis.read(buf, 0, 1024)); + assertEquals(1, dis.available()); + assertEquals(-1, dis.read()); + assertEquals(0, dis.available()); + dis.close(); + try { + dis.available(); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + } + + /** + * @tests DeflaterInputStream#close() + */ + public void testClose() throws IOException { + byte[] buf = new byte[1024]; + DeflaterInputStream dis = new DeflaterInputStream(is); + assertEquals(1, dis.available()); + dis.close(); + try { + dis.available(); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + try { + dis.read(buf, 0, 1024); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + // can close after close + dis.close(); + } + + /** + * @tests DeflaterInputStream#mark() + */ + public void testMark() throws IOException { + // mark do nothing + DeflaterInputStream dis = new DeflaterInputStream(is); + dis.mark(-1); + dis.mark(0); + dis.mark(1); + dis.close(); + dis.mark(1); + } + + /** + * @tests DeflaterInputStream#markSupported() + */ + public void testMarkSupported() throws IOException { + DeflaterInputStream dis = new DeflaterInputStream(is); + assertFalse(dis.markSupported()); + dis.close(); + assertFalse(dis.markSupported()); + } + + /** + * @tests DeflaterInputStream#read() + */ + public void testRead() throws IOException { + DeflaterInputStream dis = new DeflaterInputStream(is); + assertEquals(1, dis.available()); + assertEquals(120, dis.read()); + assertEquals(1, dis.available()); + assertEquals(156, dis.read()); + assertEquals(1, dis.available()); + assertEquals(243, dis.read()); + assertEquals(1, dis.available()); + dis.close(); + try { + dis.read(); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + } + + /** + * @tests DeflaterInputStream#read(byte[],int,int) + */ + public void testReadByteArrayIntInt() throws IOException { + byte[] buf1 = new byte[256]; + byte[] buf2 = new byte[256]; + DeflaterInputStream dis = new DeflaterInputStream(is); + assertEquals(23, dis.read(buf1, 0, 256)); + dis = new DeflaterInputStream(is); + assertEquals(8, dis.read(buf2, 0, 256)); + is = new ByteArrayInputStream(testStr.getBytes("UTF-8")); + dis = new DeflaterInputStream(is); + assertEquals(1, dis.available()); + assertEquals(120, dis.read()); + assertEquals(1, dis.available()); + assertEquals(22, dis.read(buf2, 0, 256)); + assertEquals(1, dis.available()); + assertEquals(-1, dis.read()); + assertEquals(0, dis.available()); + try { + dis.read(buf1, 0, 512); + fail("should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // expected + } + try { + dis.read(null, 0, 0); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + dis.read(null, -1, 0); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + dis.read(null, -1, -1); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + dis.read(buf1, -1, -1); + fail("should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // expected + } + try { + dis.read(buf1, 0, -1); + fail("should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // expected + } + dis.close(); + try { + dis.read(buf1, 0, 512); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + try { + dis.read(buf1, 0, 1); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + try { + dis.read(null, 0, 0); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + try { + dis.read(null, -1, 0); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + try { + dis.read(null, -1, -1); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + try { + dis.read(buf1, -1, -1); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + try { + dis.read(buf1, 0, -1); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + } + + /** + * @tests DeflaterInputStream#reset() + */ + public void testReset() throws IOException { + DeflaterInputStream dis = new DeflaterInputStream(is); + try { + dis.reset(); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + dis.close(); + try { + dis.reset(); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + } + + /** + * @tests DeflaterInputStream#skip() + */ + public void testSkip() throws IOException { + byte[] buf = new byte[1024]; + DeflaterInputStream dis = new DeflaterInputStream(is); + assertEquals(1, dis.available()); + dis.skip(1); + assertEquals(1, dis.available()); + assertEquals(22, dis.read(buf, 0, 1024)); + assertEquals(1, dis.available()); + dis.skip(1); + assertEquals(0, dis.available()); + is = new ByteArrayInputStream(testStr.getBytes("UTF-8")); + dis = new DeflaterInputStream(is); + assertEquals(1, dis.available()); + dis.skip(56); + assertEquals(0, dis.available()); + assertEquals(-1, dis.read(buf, 0, 1024)); + try { + dis.skip(-1); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + assertEquals(0, dis.available()); + // can still skip + dis.skip(1); + dis.close(); + try { + dis.skip(1); + fail("should throw IOException"); + } catch (IOException e) { + // expected + } + try { + dis.skip(-1); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + is = new ByteArrayInputStream(testStr.getBytes("UTF-8")); + dis = new DeflaterInputStream(is); + assertEquals(23, dis.skip(Long.MAX_VALUE)); + assertEquals(0, dis.available()); + } + + /** + * @tests DeflaterInputStream#DeflaterInputStream(InputStream) + */ + public void testDeflaterInputStreamInputStream() { + // ok + new DeflaterInputStream(is); + // fail + try { + new DeflaterInputStream(null); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } + + /** + * @tests DeflaterInputStream#DeflaterInputStream(InputStream,Deflater) + */ + public void testDeflaterInputStreamInputStreamDeflater() { + // ok + new DeflaterInputStream(is, new Deflater()); + // fail + try { + new DeflaterInputStream(is, null); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + new DeflaterInputStream(null, new Deflater()); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } + + /** + * @tests DeflaterInputStream#DeflaterInputStream(InputStream,Deflater,int) + */ + public void testDeflaterInputStreamInputStreamDeflaterInt() { + // ok + new DeflaterInputStream(is, new Deflater(), 1024); + // fail + try { + new DeflaterInputStream(is, null, 1024); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + new DeflaterInputStream(null, new Deflater(), 1024); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + new DeflaterInputStream(is, new Deflater(), -1); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + try { + new DeflaterInputStream(null, new Deflater(), -1); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + new DeflaterInputStream(is, null, -1); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + is = new ByteArrayInputStream(testStr.getBytes("UTF-8")); + } + + @Override + protected void tearDown() throws Exception { + is.close(); + super.tearDown(); + } +} diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterOutputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterOutputStreamTest.java new file mode 100644 index 0000000..9627613 --- /dev/null +++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterOutputStreamTest.java @@ -0,0 +1,392 @@ +/* + * 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 java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; +import java.util.zip.InflaterOutputStream; +import java.util.zip.ZipException; + +import junit.framework.TestCase; + +public class InflaterOutputStreamTest extends TestCase { + + private ByteArrayOutputStream os = new ByteArrayOutputStream(); + + private byte[] compressedBytes = new byte[100]; + + private String testString = "Hello world"; + + /** + * @tests java.util.zip.InflaterOutputStream#InflaterOutputStream(java.io.OutputStream) + */ + public void test_ConstructorLjava_io_OutputStream() throws IOException { + new InflaterOutputStream(os); + + try { + new InflaterOutputStream(null); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } + + /** + * @tests java.util.zip.InflaterOutputStream#InflaterOutputStream(java.io.OutputStream,Inflater) + */ + public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_Inflater() { + new InflaterOutputStream(os, new Inflater()); + + try { + new InflaterOutputStream(null, new Inflater()); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + try { + new InflaterOutputStream(os, null); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } + + /** + * @tests java.util.zip.InflaterOutputStream#InflaterOutputStream(java.io.OutputStream,Inflater,int) + */ + public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_InflaterI() { + new InflaterOutputStream(os, new Inflater(), 20); + + try { + new InflaterOutputStream(null, null, 10); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + try { + new InflaterOutputStream(null, new Inflater(), -1); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + try { + new InflaterOutputStream(os, null, -1); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + try { + new InflaterOutputStream(null, null, -1); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + try { + new InflaterOutputStream(os, new Inflater(), 0); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + try { + new InflaterOutputStream(os, new Inflater(), -10000); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + } + + /** + * @tests java.util.zip.InflaterOutputStream#close() + */ + public void test_close() throws IOException { + InflaterOutputStream ios = new InflaterOutputStream(os); + ios.close(); + // multiple close + ios.close(); + } + + /** + * @tests java.util.zip.InflaterOutputStream#flush() + */ + public void test_flush() throws IOException { + InflaterOutputStream ios = new InflaterOutputStream(os); + ios.close(); + try { + ios.flush(); + fail("Should throw IOException"); + } catch (IOException e) { + // expected + } + + ios = new InflaterOutputStream(os); + ios.flush(); + ios.flush(); + } + + /** + * @tests java.util.zip.InflaterOutputStream#finish() + */ + public void test_finish() throws IOException { + InflaterOutputStream ios = new InflaterOutputStream(os); + ios.close(); + try { + ios.finish(); + fail("Should throw IOException"); + } catch (IOException e) { + // expected + } + + ios = new InflaterOutputStream(os); + ios.finish(); + ios.finish(); + ios.flush(); + ios.flush(); + ios.finish(); + + byte[] bytes1 = {10,20,30,40,50}; + Deflater defaultDeflater = new Deflater(Deflater.BEST_SPEED); + defaultDeflater.setInput(bytes1); + defaultDeflater.finish(); + int length1 = defaultDeflater.deflate(compressedBytes); + + byte[] bytes2 = {100,90,80,70,60}; + Deflater bestDeflater = new Deflater(Deflater.BEST_COMPRESSION ); + bestDeflater.setInput(bytes2); + bestDeflater.finish(); + int length2 = bestDeflater.deflate(compressedBytes,length1,compressedBytes.length-length1); + + ios = new InflaterOutputStream(os); + for (int i = 0; i < length1; i++) { + ios.write(compressedBytes[i]); + } + ios.finish(); + ios.close(); + + byte[] result = os.toByteArray(); + for(int i =0;i<bytes1.length; i++){ + assertEquals(bytes1[i],result[i]); + } + + ios = new InflaterOutputStream(os); + for (int i = length1; i < length2*2; i++) { + ios.write(compressedBytes[i]); + } + ios.finish(); + ios.close(); + + result = os.toByteArray(); + for(int i =0;i<bytes2.length; i++){ + assertEquals(bytes2[i],result[bytes1.length+i]); + } + + } + + /** + * @tests java.util.zip.InflaterOutputStream#write(int) + */ + public void test_write_I() throws IOException { + int length = compressToBytes(testString); + + // uncompress the data stored in the compressedBytes + InflaterOutputStream ios = new InflaterOutputStream(os); + for (int i = 0; i < length; i++) { + ios.write(compressedBytes[i]); + } + + String result = new String(os.toByteArray()); + assertEquals(testString, result); + } + + /** + * @tests java.util.zip.InflaterOutputStream#write(int) + */ + public void test_write_I_Illegal() throws IOException { + + // write after close + InflaterOutputStream ios = new InflaterOutputStream(os); + ios.close(); + try { + ios.write(-1); + fail("Should throw IOException"); + } catch (IOException e) { + // expected + } + } + + /** + * @tests java.util.zip.InflaterOutputStream#write(byte[],int,int) + */ + public void test_write_$BII() throws IOException { + int length = compressToBytes(testString); + + // uncompress the data stored in the compressedBytes + InflaterOutputStream ios = new InflaterOutputStream(os); + ios.write(compressedBytes, 0, length); + + String result = new String(os.toByteArray()); + assertEquals(testString, result); + } + + /** + * @tests java.util.zip.InflaterOutputStream#write(byte[],int,int) + */ + public void test_write_$BII_Illegal() throws IOException { + // write error compression (ZIP) format + InflaterOutputStream ios = new InflaterOutputStream(os); + byte[] bytes = { 0, 1, 2, 3 }; + try { + ios.write(bytes, 0, 4); + fail("Should throw ZipException"); + } catch (ZipException e) { + // expected + } + try { + ios.flush(); + fail("Should throw ZipException"); + } catch (ZipException e) { + // expected + } + + // write after close + ios = new InflaterOutputStream(os); + ios.close(); + try { + ios.write(bytes, 0, 4); + fail("Should throw IOException"); + } catch (IOException e) { + // expected + } + try { + ios.write(bytes, -1, 4); + fail("Should throw IOException"); + } catch (IOException e) { + // expected + } + try { + ios.write(bytes, -1, -4); + fail("Should throw IOException"); + } catch (IOException e) { + // expected + } + try { + ios.write(bytes, 0, 400); + fail("Should throw IOException"); + } catch (IOException e) { + // expected + } + try { + ios.write(null, -1, 4); + fail("Should throw IOException"); + } catch (IOException e) { + // expected + } + + ios = new InflaterOutputStream(os); + try { + ios.write(null, 0, 4); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + ios.write(null, -1, 4); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + ios.write(null, 0, -4); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + ios.write(null, 0, 1000); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + try { + ios.write(bytes, -1, 4); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // expected + } + try { + ios.write(bytes, 0, -4); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // expected + } + try { + ios.write(bytes, 0, 100); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // expected + } + try { + ios.write(bytes, -100, 100); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + ios = new InflaterOutputStream(os); + ios.finish(); + + try { + ios.write(bytes, -1,-100); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // expected + } + try { + ios.write(null, -1,-100); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + ios = new InflaterOutputStream(os); + ios.flush(); + try { + ios.write(bytes, 0, 4); + fail("Should throw ZipException"); + } catch (ZipException e) { + // expected + } + } + + // Compress the test string into compressedBytes + private int compressToBytes(String string) { + byte[] input = string.getBytes(); + Deflater deflater = new Deflater(); + deflater.setInput(input); + deflater.finish(); + return deflater.deflate(compressedBytes); + } + +} |