1c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson/*
2c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson * Copyright (C) 2010 The Android Open Source Project
3c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson *
4c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson * you may not use this file except in compliance with the License.
6c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson * You may obtain a copy of the License at
7c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson *
8c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson *
10c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson * See the License for the specific language governing permissions and
14c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson * limitations under the License.
15c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson */
16c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson
176186821cb13f4ac7ff50950c813394367e021eaeJesse Wilsonpackage libcore.io;
18c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson
19bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughesimport java.io.ByteArrayOutputStream;
200eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughesimport java.io.EOFException;
21c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilsonimport java.io.IOException;
22c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilsonimport java.io.InputStream;
23086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilsonimport java.io.OutputStream;
24f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilsonimport java.io.Reader;
25f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilsonimport java.io.StringWriter;
26a1603838fe9e865575c87982e32c6343740e464cElliott Hughesimport java.util.Arrays;
273541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilsonimport java.util.concurrent.atomic.AtomicReference;
28c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson
29c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilsonpublic final class Streams {
303541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson    private static AtomicReference<byte[]> skipBuffer = new AtomicReference<byte[]>();
313541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson
32c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson    private Streams() {}
33c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson
340eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes    /**
35ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes     * Implements InputStream.read(int) in terms of InputStream.read(byte[], int, int).
36ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes     * InputStream assumes that you implement InputStream.read(int) and provides default
37ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes     * implementations of the others, but often the opposite is more efficient.
38ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes     */
39ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes    public static int readSingleByte(InputStream in) throws IOException {
40ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes        byte[] buffer = new byte[1];
41ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes        int result = in.read(buffer, 0, 1);
42ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes        return (result != -1) ? buffer[0] & 0xff : -1;
43ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes    }
44ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes
45ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes    /**
46ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes     * Implements OutputStream.write(int) in terms of OutputStream.write(byte[], int, int).
47ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes     * OutputStream assumes that you implement OutputStream.write(int) and provides default
48ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes     * implementations of the others, but often the opposite is more efficient.
49ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes     */
50ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes    public static void writeSingleByte(OutputStream out, int b) throws IOException {
51ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes        byte[] buffer = new byte[1];
52ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes        buffer[0] = (byte) (b & 0xff);
53ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes        out.write(buffer);
54ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes    }
55ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes
56ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes    /**
57f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes     * Fills 'dst' with bytes from 'in', throwing EOFException if insufficient bytes are available.
58f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes     */
59f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes    public static void readFully(InputStream in, byte[] dst) throws IOException {
60f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes        readFully(in, dst, 0, dst.length);
61f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes    }
62f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes
63f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes    /**
64f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes     * Reads exactly 'byteCount' bytes from 'in' (into 'dst' at offset 'offset'), and throws
65f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes     * EOFException if insufficient bytes are available.
66f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes     *
67f5309a39506c967feda8766feeba7f7271a458cbElliott Hughes     * Used to implement {@link java.io.DataInputStream#readFully(byte[], int, int)}.
680eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes     */
690eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes    public static void readFully(InputStream in, byte[] dst, int offset, int byteCount) throws IOException {
700eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes        if (byteCount == 0) {
710eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            return;
720eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes        }
730eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes        if (in == null) {
740eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            throw new NullPointerException("in == null");
750eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes        }
760eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes        if (dst == null) {
770eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            throw new NullPointerException("dst == null");
780eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes        }
79a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        Arrays.checkOffsetAndCount(dst.length, offset, byteCount);
800eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes        while (byteCount > 0) {
810eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            int bytesRead = in.read(dst, offset, byteCount);
820eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            if (bytesRead < 0) {
830eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes                throw new EOFException();
840eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            }
850eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            offset += bytesRead;
860eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            byteCount -= bytesRead;
870eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes        }
880eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes    }
890eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes
90bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes    /**
91f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson     * Returns a byte[] containing the remainder of 'in', closing it when done.
92bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes     */
93bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes    public static byte[] readFully(InputStream in) throws IOException {
94f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        try {
95df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson            return readFullyNoClose(in);
96f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        } finally {
97f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            in.close();
98f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        }
99f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson    }
100f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson
101f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson    /**
102df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson     * Returns a byte[] containing the remainder of 'in'.
103df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson     */
104df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson    public static byte[] readFullyNoClose(InputStream in) throws IOException {
105df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
106df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson        byte[] buffer = new byte[1024];
107df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson        int count;
108df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson        while ((count = in.read(buffer)) != -1) {
109df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson            bytes.write(buffer, 0, count);
110df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson        }
111df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson        return bytes.toByteArray();
112df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson    }
113df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson
114df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson    /**
115f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson     * Returns the remainder of 'reader' as a string, closing it when done.
116f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson     */
117f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson    public static String readFully(Reader reader) throws IOException {
118f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        try {
119f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            StringWriter writer = new StringWriter();
120f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            char[] buffer = new char[1024];
121f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            int count;
122f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            while ((count = reader.read(buffer)) != -1) {
123f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson                writer.write(buffer, 0, count);
124bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes            }
125f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            return writer.toString();
126f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        } finally {
127f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            reader.close();
128bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes        }
129bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes    }
130bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes
131c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson    public static void skipAll(InputStream in) throws IOException {
132c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson        do {
133c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson            in.skip(Long.MAX_VALUE);
134c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson        } while (in.read() != -1);
135c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson    }
1363541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson
1373541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson    /**
1383541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     * Call {@code in.read()} repeatedly until either the stream is exhausted or
1393541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     * {@code byteCount} bytes have been read.
1403541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     *
1413541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     * <p>This method reuses the skip buffer but is careful to never use it at
1423541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     * the same time that another stream is using it. Otherwise streams that use
1433541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     * the caller's buffer for consistency checks like CRC could be clobbered by
1443541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     * other threads. A thread-local buffer is also insufficient because some
1453541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     * streams may call other streams in their skip() method, also clobbering the
1463541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     * buffer.
1473541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson     */
1483541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson    public static long skipByReading(InputStream in, long byteCount) throws IOException {
1493541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        // acquire the shared skip buffer.
1503541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        byte[] buffer = skipBuffer.getAndSet(null);
1513541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        if (buffer == null) {
1523541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson            buffer = new byte[4096];
1533541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        }
1543541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson
1553541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        long skipped = 0;
1563541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        while (skipped < byteCount) {
1573541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson            int toRead = (int) Math.min(byteCount - skipped, buffer.length);
1583541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson            int read = in.read(buffer, 0, toRead);
1593541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson            if (read == -1) {
1603541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson                break;
1613541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson            }
1623541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson            skipped += read;
1633541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson            if (read < toRead) {
1643541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson                break;
1653541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson            }
1663541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        }
1673541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson
1683541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        // release the shared skip buffer.
1693541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        skipBuffer.set(buffer);
1703541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson
1713541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson        return skipped;
1723541c79d5058b86e742867b4ee5811a1de01de1fJesse Wilson    }
173086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson
174086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson    /**
175086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson     * Copies all of the bytes from {@code in} to {@code out}. Neither stream is closed.
176086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson     * Returns the total number of bytes transferred.
177086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson     */
178086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson    public static int copy(InputStream in, OutputStream out) throws IOException {
179086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson        int total = 0;
180086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson        byte[] buffer = new byte[8192];
181086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson        int c;
182086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson        while ((c = in.read(buffer)) != -1) {
183086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson            total += c;
184086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson            out.write(buffer, 0, c);
185086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson        }
186086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson        return total;
187086fd0244a54fa5ecf13ea66d49b22b36d7d456eJesse Wilson    }
188f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson
189f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson    /**
190f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson     * Returns the ASCII characters up to but not including the next "\r\n", or
191f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson     * "\n".
192f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson     *
193f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson     * @throws java.io.EOFException if the stream is exhausted before the next newline
194f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson     *     character.
195f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson     */
196f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson    public static String readAsciiLine(InputStream in) throws IOException {
197f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        // TODO: support UTF-8 here instead
198f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson
199f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        StringBuilder result = new StringBuilder(80);
200f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        while (true) {
201f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            int c = in.read();
202f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            if (c == -1) {
203f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson                throw new EOFException();
204f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            } else if (c == '\n') {
205f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson                break;
206f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            }
207f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson
208f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            result.append((char) c);
209f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        }
210f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        int length = result.length();
211f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        if (length > 0 && result.charAt(length - 1) == '\r') {
212f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson            result.setLength(length - 1);
213f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        }
214f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson        return result.toString();
215f589846f86761ffea3c06ab9d105d3f19328d121Jesse Wilson    }
216c0372d90016d241ac979faa6fa1731f30b6f2a03Jesse Wilson}
217