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