/* * 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 socket.io; import java.io.DataInputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * This input stream works in conjunction with the WrappedOutputStream * to introduce a protocol for reading arbitrary length data in a * uniform way. * <p> * <strong>Note:</strong> See the javadoc for WrappedOutputStream for * more information. * * @see WrappedOutputStream * * @author Andy Clark, IBM * * @version $Id: WrappedInputStream.java 699895 2008-09-28 21:21:24Z mrglavas $ */ public class WrappedInputStream extends FilterInputStream { // // Data // /** Bytes left on input stream for current packet. */ protected int fPacketCount; /** * Data input stream. This stream is used to input the block sizes * from the data stream that are written by the WrappedOutputStream. * <p> * <strong>Note:</strong> The data input stream is only used for * reading the byte count for performance reasons. We avoid the * method indirection for reading the byte data. */ protected DataInputStream fDataInputStream; /** To mark that the stream is "closed". */ protected boolean fClosed; // // Constructors // /** Constructs a wrapper for the given an input stream. */ public WrappedInputStream(InputStream stream) { super(stream); fDataInputStream = new DataInputStream(stream); } // <init>(InputStream) // // InputStream methods // /** Reads a single byte. */ public int read() throws IOException { // ignore, if already closed if (fClosed) { return -1; } // read packet header if (fPacketCount == 0) { fPacketCount = fDataInputStream.readInt() & 0x7FFFFFFF; if (fPacketCount == 0) { fClosed = true; return -1; } } // read a byte from the packet fPacketCount--; return super.in.read(); } // read():int /** * Reads a block of bytes and returns the total number of bytes read. */ public int read(byte[] b, int offset, int length) throws IOException { // ignore, if already closed if (fClosed) { return -1; } // read packet header if (fPacketCount == 0) { fPacketCount = fDataInputStream.readInt() & 0x7FFFFFFF; if (fPacketCount == 0) { fClosed = true; return -1; } } // read bytes from packet if (length > fPacketCount) { length = fPacketCount; } int count = super.in.read(b, offset, length); if (count == -1) { // NOTE: This condition should not happen. The end of // the stream should always be designated by a // byte count header of 0. -Ac fClosed = true; return -1; } fPacketCount -= count; // return total bytes read return count; } // read(byte[],int,int):int /** Skips the specified number of bytes from the input stream. */ public long skip(long n) throws IOException { if (!fClosed) { // NOTE: This should be rewritten to be more efficient. -Ac for (long i = 0; i < n; i++) { int b = read(); if (b == -1) { return i + 1; } } return n; } return 0; } // skip(long):long /** * Closes the input stream. This method will search for the end of * the wrapped input, positioning the stream at after the end packet. * <p> * <strong>Note:</strong> This method does not close the underlying * input stream. */ public void close() throws IOException { if (!fClosed) { fClosed = true; do { super.in.skip(fPacketCount); fPacketCount = fDataInputStream.readInt() & 0x7FFFFFFF; } while (fPacketCount > 0); } } // close() } // class WrappedInputStream