Mega Code Archive

 
Categories / Java Tutorial / File
 

An InputStream class that terminates the stream when it encounters a particular byte sequence

/****************************************************************  * 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.                                           *  ****************************************************************/ import java.io.IOException; import java.io.InputStream; /**  * An InputStream class that terminates the stream when it encounters a  * particular byte sequence.  *  * @version 1.0.0, 24/04/1999  */ public class CharTerminatedInputStream     extends InputStream {     /**      * The wrapped input stream      */     private InputStream in;     /**      * The terminating character array      */     private int match[];     /**      * An array containing the last N characters read from the stream, where      * N is the length of the terminating character array      */     private int buffer[];     /**      * The number of bytes that have been read that have not been placed      * in the internal buffer.      */     private int pos = 0;     /**      * Whether the terminating sequence has been read from the stream      */     private boolean endFound = false;     /**      * A constructor for this object that takes a stream to be wrapped      * and a terminating character sequence.      *      * @param in the <code>InputStream</code> to be wrapped      * @param terminator the array of characters that will terminate the stream.      *      * @throws IllegalArgumentException if the terminator array is null or empty      */     public CharTerminatedInputStream(InputStream in, char[] terminator) {         if (terminator == null) {             throw new IllegalArgumentException("The terminating character array cannot be null.");         }         if (terminator.length == 0) {             throw new IllegalArgumentException("The terminating character array cannot be of zero length.");         }         match = new int[terminator.length];         buffer = new int[terminator.length];         for (int i = 0; i < terminator.length; i++) {             match[i] = (int)terminator[i];             buffer[i] = (int)terminator[i];         }         this.in = in;     }     /**      * Read a byte off this stream.      *      * @return the byte read off the stream      * @throws IOException if an IOException is encountered while reading off the stream      * @throws ProtocolException if the underlying stream returns -1 before the terminator is seen.      */     public int read() throws IOException {         if (endFound) {             //We've found the match to the terminator             return -1;         }         if (pos == 0) {             //We have no data... read in a record             int b = in.read();             if (b == -1) {                 //End of stream reached without seeing the terminator                 throw new java.net.ProtocolException("pre-mature end of data");             }             if (b != match[0]) {                 //this char is not the first char of the match                 return b;             }             //this is a match...put this in the first byte of the buffer,             // and fall through to matching logic             buffer[0] = b;             pos++;         } else {             if (buffer[0] != match[0]) {                 //Maybe from a previous scan, there is existing data,                 // and the first available char does not match the                 // beginning of the terminating string.                 return topChar();             }             //we have a match... fall through to matching logic.         }         //MATCHING LOGIC         //The first character is a match... scan for complete match,         // reading extra chars as needed, until complete match is found         for (int i = 0; i < match.length; i++) {             if (i >= pos) {                 int b = in.read();                 if (b == -1) {                     //end of stream found, so match cannot be fulfilled.                     // note we don't set endFound, because otherwise                     // remaining part of buffer won't be returned.                     return topChar();                 }                 //put the read char in the buffer                 buffer[pos] = b;                 pos++;             }             if (buffer[i] != match[i]) {                 //we did not find a match... return the top char                 return topChar();             }         }         //A complete match was made...         endFound = true;         return -1;     }     /**      * Private helper method to update the internal buffer of last read characters      *      * @return the byte that was previously at the front of the internal buffer      */     private int topChar() {         int b = buffer[0];         if (pos > 1) {             //copy down the buffer to keep the fresh data at top             System.arraycopy(buffer, 1, buffer, 0, pos - 1);         }         pos--;         return b;     } }