diff options
author | Android (Google) Code Review <android-gerrit@google.com> | 2009-12-14 14:35:24 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-12-14 14:35:24 -0800 |
commit | ee5af1749a3e4274baf177dc86d222c519086da9 (patch) | |
tree | 5c6ae61609d973098a4e14d237fe929309a05c7a /luni | |
parent | 97e18d454c30a7836315bfd40453eed826b2f4ec (diff) | |
parent | f7c6911047d63bc76292f55ce538da32818dd931 (diff) | |
download | libcore-ee5af1749a3e4274baf177dc86d222c519086da9.zip libcore-ee5af1749a3e4274baf177dc86d222c519086da9.tar.gz libcore-ee5af1749a3e4274baf177dc86d222c519086da9.tar.bz2 |
Merge change I1d96b51e
* changes:
Merge branch 'archive_888752' into archive_dalvik
Diffstat (limited to 'luni')
-rw-r--r-- | luni/src/main/java/org/apache/harmony/luni/InputStreamHelper.java | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/luni/src/main/java/org/apache/harmony/luni/InputStreamHelper.java b/luni/src/main/java/org/apache/harmony/luni/InputStreamHelper.java new file mode 100644 index 0000000..329b420 --- /dev/null +++ b/luni/src/main/java/org/apache/harmony/luni/InputStreamHelper.java @@ -0,0 +1,199 @@ +/* + * 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.luni.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * The class contains static {@link java.io.InputStream} utilities. + */ +public class InputStreamHelper { + + /** + * Provides access to a protected underlying buffer of + * <code>ByteArrayInputStream</code>. + */ + private static final Field BAIS_BUF; + + /** + * Provides access to a protected position in the underlying buffer of + * <code>ByteArrayInputStream</code>. + */ + private static final Field BAIS_POS; + + static { + final Field[] f = new Field[2]; + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + try { + f[0] = ByteArrayInputStream.class.getDeclaredField("buf"); //$NON-NLS-1$ + f[0].setAccessible(true); + f[1] = ByteArrayInputStream.class.getDeclaredField("pos"); //$NON-NLS-1$ + f[1].setAccessible(true); + } catch (NoSuchFieldException nsfe) { + throw new InternalError(nsfe.getLocalizedMessage()); + } + return null; + } + }); + BAIS_BUF = f[0]; + BAIS_POS = f[1]; + } + + /** + * The extension of <code>ByteArrayInputStream</code> which exposes an + * underlying buffer. + */ + static class ExposedByteArrayInputStream extends ByteArrayInputStream { + + /** + * @see java.io.ByteArrayInputStream(byte[]) + */ + public ExposedByteArrayInputStream(byte buf[]) { + super(buf); + } + + /** + * @see java.io.ByteArrayInputStream(byte[], int, int) + */ + public ExposedByteArrayInputStream(byte buf[], int offset, int length) { + super(buf, offset, length); + } + + /** + * Reads the whole stream and returns the stream snapshot. + */ + public synchronized byte[] expose() { + if (pos == 0 && count == buf.length) { + skip(count); + return buf; + } + + final int available = available(); + final byte[] buffer = new byte[available]; + System.arraycopy(buf, pos, buffer, 0, available); + skip(available); + return buffer; + } + } + + /** + * Reads all bytes from {@link java.io.ByteArrayInputStream} using its + * underlying buffer directly. + * + * @return an underlying buffer, if a current position is at the buffer + * beginning, and an end position is at the buffer end, or a copy of + * the underlying buffer part. + */ + private static byte[] expose(ByteArrayInputStream bais) { + byte[] buffer, buf; + int pos; + synchronized (bais) { + int available = bais.available(); + try { + buf = (byte[]) BAIS_BUF.get(bais); + pos = BAIS_POS.getInt(bais); + } catch (IllegalAccessException iae) { + throw new InternalError(iae.getLocalizedMessage()); + } + if (pos == 0 && available == buf.length) { + buffer = buf; + } else { + buffer = new byte[available]; + System.arraycopy(buf, pos, buffer, 0, available); + } + bais.skip(available); + } + return buffer; + } + + /** + * The utility method for reading the whole input stream into a snapshot + * buffer. To speed up the access it works with an underlying buffer for a + * given {@link java.io.ByteArrayInputStream}. + * + * @param is + * the stream to be read. + * @return the snapshot wrapping the buffer where the bytes are read to. + * @throws UnsupportedOperationException + * if the input stream data cannot be exposed + */ + public static byte[] expose(InputStream is) throws IOException, + UnsupportedOperationException { + if (is instanceof ExposedByteArrayInputStream) { + return ((ExposedByteArrayInputStream) is).expose(); + } + + if (is.getClass().equals(ByteArrayInputStream.class)) { + return expose((ByteArrayInputStream) is); + } + + // We don't know how to do this + throw new UnsupportedOperationException(); + } + + /** + * Reads all the bytes from the given input stream. + * + * Calls read multiple times on the given input stream until it receives an + * end of file marker. Returns the combined results as a byte array. Note + * that this method may block if the underlying stream read blocks. + * + * @param is + * the input stream to be read. + * @return the content of the stream as a byte array. + * @throws IOException + * if a read error occurs. + */ + public static byte[] readFullyAndClose(InputStream is) throws IOException { + + try { + // Initial read + byte[] buffer = new byte[1024]; + int count = is.read(buffer); + int nextByte = is.read(); + + // Did we get it all in one read? + if (nextByte == -1) { + byte[] dest = new byte[count]; + System.arraycopy(buffer, 0, dest, 0, count); + return dest; + } + + // Requires additional reads + ByteArrayOutputStream baos = new ByteArrayOutputStream(count * 2); + baos.write(buffer, 0, count); + baos.write(nextByte); + while (true) { + count = is.read(buffer); + if (count == -1) { + return baos.toByteArray(); + } + baos.write(buffer, 0, count); + } + } finally { + is.close(); + } + } +} |