Frames | No Frames |
1: /* SequenceInputStream.java -- Reads multiple input streams in sequence 2: Copyright (C) 1998, 1999, 2001, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.io; 40: 41: import java.util.Enumeration; 42: 43: /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 44: * "The Java Language Specification", ISBN 0-201-63451-1 45: * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. 46: * Status: Believed complete and correct. 47: */ 48: 49: /** 50: * This class merges a sequence of multiple <code>InputStream</code>'s in 51: * order to form a single logical stream that can be read by applications 52: * that expect only one stream. 53: * <p> 54: * The streams passed to the constructor method are read in order until 55: * they return -1 to indicate they are at end of stream. When a stream 56: * reports end of stream, it is closed, then the next stream is read. 57: * When the last stream is closed, the next attempt to read from this 58: * stream will return a -1 to indicate it is at end of stream. 59: * <p> 60: * If this stream is closed prior to all subordinate streams being read 61: * to completion, all subordinate streams are closed. 62: * 63: * @author Aaron M. Renn (arenn@urbanophile.com) 64: * @author Warren Levy (warrenl@cygnus.com) 65: */ 66: public class SequenceInputStream extends InputStream 67: { 68: /** The handle for the current input stream. */ 69: private InputStream in; 70: 71: /** Secondary input stream; not used if constructed w/ enumeration. */ 72: private InputStream in2; 73: 74: /** 75: * The enumeration handle; not used if constructed w/ 2 explicit 76: * input streams. 77: */ 78: private Enumeration<? extends InputStream> e; 79: 80: /** 81: * This method creates a new <code>SequenceInputStream</code> that obtains 82: * its list of subordinate <code>InputStream</code>s from the specified 83: * <code>Enumeration</code> 84: * 85: * @param e An <code>Enumeration</code> that will return a list of 86: * <code>InputStream</code>s to read in sequence 87: */ 88: public SequenceInputStream(Enumeration<? extends InputStream> e) 89: { 90: this.e = e; 91: in = e.nextElement(); 92: in2 = null; 93: } 94: 95: /** 96: * This method creates a new <code>SequenceInputStream</code> that will read 97: * the two specified subordinate <code>InputStream</code>s in sequence. 98: * 99: * @param s1 The first <code>InputStream</code> to read 100: * @param s2 The second <code>InputStream</code> to read 101: */ 102: public SequenceInputStream(InputStream s1, InputStream s2) 103: { 104: in = s1; 105: in2 = s2; 106: } 107: 108: /** 109: * This method returns the number of bytes than can be read from the 110: * currently being read subordinate stream before that stream could 111: * block. Note that it is possible more bytes than this can actually 112: * be read without the stream blocking. If a 0 is returned, then the 113: * stream could block on the very next read. 114: * 115: * @return The number of bytes that can be read before blocking could occur 116: * 117: * @exception IOException If an error occurs 118: */ 119: public int available() throws IOException 120: { 121: if (in == null) 122: return 0; 123: 124: return in.available(); 125: } 126: 127: /** 128: * Closes this stream. This will cause any remaining unclosed subordinate 129: * <code>InputStream</code>'s to be closed as well. Subsequent attempts to 130: * read from this stream may cause an exception. 131: * 132: * @exception IOException If an error occurs 133: */ 134: public void close() throws IOException 135: { 136: while (in != null) 137: { 138: in.close(); 139: in = getNextStream (); 140: } 141: } 142: 143: /** 144: * This method reads an unsigned byte from the input stream and returns it 145: * as an int in the range of 0-255. This method also will return -1 if 146: * the end of the stream has been reached. This will only happen when 147: * all of the subordinate streams have been read. 148: * <p> 149: * This method will block until the byte can be read. 150: * 151: * @return The byte read, or -1 if end of stream 152: * 153: * @exception IOException If an error occurs 154: */ 155: public int read() throws IOException 156: { 157: int ch = -1; 158: 159: while (in != null && (ch = in.read()) < 0) 160: { 161: in.close(); 162: in = getNextStream(); 163: } 164: 165: return ch; 166: } 167: 168: /** 169: * This method reads bytes from a stream and stores them into a caller 170: * supplied buffer. It starts storing the data at index <code>offset</code> 171: * into the buffer and attempts to read <code>len</code> bytes. This method 172: * can return before reading the number of bytes requested. The actual number 173: * of bytes read is returned as an int. A -1 is returend to indicate the 174: * end of the stream. This will only happen when all of the subordinate 175: * streams have been read. 176: * <p> 177: * This method will block until at least one byte can be read. 178: * 179: * @param b The array into which bytes read should be stored 180: * @param off The offset into the array to start storing bytes 181: * @param len The requested number of bytes to read 182: * 183: * @return The actual number of bytes read, or -1 if end of stream 184: * 185: * @exception IOException If an error occurs 186: */ 187: public int read(byte[] b, int off, int len) throws IOException 188: { 189: int ch = -1; 190: 191: // The validity of the parameters will be checked by in.read so 192: // don't bother doing it here. 193: while (in != null && (ch = in.read(b, off, len)) < 0) 194: { 195: in.close(); 196: in = getNextStream(); 197: } 198: 199: return ch; 200: } 201: 202: /** 203: * This private method is used to get the next <code>InputStream</code> to 204: * read from. Returns null when no more streams are available. 205: */ 206: private InputStream getNextStream() 207: { 208: InputStream nextIn = null; 209: 210: if (e != null) 211: { 212: if (e.hasMoreElements()) 213: nextIn = e.nextElement(); 214: } 215: else if (in2 != null) 216: { 217: nextIn = in2; 218: in2 = null; 219: } 220: 221: return nextIn; 222: } 223: }