1 /*** 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that the following conditions are 4 * met : 5 * 6 * . Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * 9 * . Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * . The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $Id$ 29 */ 30 31 package palmed.edit.text; 32 33 import java.io.IOException; 34 import java.io.InputStream; 35 import java.io.OutputStream; 36 37 /*** 38 * This class wraps an InputStream in order to detect the line delimiter type. 39 * 40 * @author Mathieu Champlon 41 * @version $Revision$ $Date$ 42 */ 43 public final class LineDelimiterInspector extends InputStream 44 { 45 /*** 46 * The line feed delimiter. 47 */ 48 private static final String LF = "\n"; 49 /*** 50 * The carriage return delimiter. 51 */ 52 private static final String CR = "\r"; 53 /*** 54 * The carriage return/line feed delimiter. 55 */ 56 private static final String CR_LF = "\r\n"; 57 /*** 58 * The wrapped stream. 59 */ 60 private final InputStream stream_; 61 /*** 62 * The delimiter. 63 */ 64 private String delimiter_; 65 /*** 66 * Whether the previous read byte was a carriage return or not. 67 */ 68 private boolean wasCarriageReturn_; 69 /*** 70 * Whether to skip the rest of the stream or not. 71 */ 72 private boolean hasLineDelimiterBeenFound_; 73 74 /*** 75 * Create a line delimiter inspector. 76 * 77 * @param stream the stream to wrap 78 */ 79 public LineDelimiterInspector( final InputStream stream ) 80 { 81 if( stream == null ) 82 throw new IllegalArgumentException( "parameter 'stream' is null" ); 83 stream_ = stream; 84 delimiter_ = CR_LF; 85 wasCarriageReturn_ = false; 86 hasLineDelimiterBeenFound_ = false; 87 } 88 89 /*** 90 * Create a default line delimiter. 91 */ 92 public LineDelimiterInspector() 93 { 94 stream_ = null; 95 delimiter_ = CR_LF; 96 } 97 98 /*** 99 * {@inheritDoc} 100 */ 101 public int read() throws IOException 102 { 103 final int b = stream_.read(); 104 if( hasLineDelimiterBeenFound_ ) 105 return b; 106 return inspect( b ); 107 } 108 109 /*** 110 * {@inheritDoc} 111 */ 112 public int read( final byte[] b ) throws IOException 113 { 114 return read( b, 0, b.length ); 115 } 116 117 /*** 118 * {@inheritDoc} 119 */ 120 public int read( final byte[] b, final int off, final int len ) throws IOException 121 { 122 final int size = stream_.read( b, off, len ); 123 for( int i = off; i < size && !hasLineDelimiterBeenFound_; ++i ) 124 inspect( b[i] ); 125 return size; 126 } 127 128 private int inspect( final int b ) 129 { 130 if( b == '\r' ) 131 { 132 delimiter_ = CR; 133 wasCarriageReturn_ = true; 134 } 135 else 136 { 137 if( b == '\n' ) 138 { 139 if( wasCarriageReturn_ ) 140 delimiter_ = CR_LF; 141 else 142 delimiter_ = LF; 143 hasLineDelimiterBeenFound_ = true; 144 } 145 else if( wasCarriageReturn_ ) 146 hasLineDelimiterBeenFound_ = true; 147 } 148 return b; 149 } 150 151 /*** 152 * Write the delimiter to an output stream. 153 * 154 * @param stream the stream to write into 155 * @throws IOException an io exception occurs 156 */ 157 public void write( final OutputStream stream ) throws IOException 158 { 159 stream.write( delimiter_.getBytes() ); 160 } 161 162 /*** 163 * {@inheritDoc} 164 */ 165 public int available() throws IOException 166 { 167 return stream_.available(); 168 } 169 170 /*** 171 * {@inheritDoc} 172 */ 173 public void close() throws IOException 174 { 175 stream_.close(); 176 } 177 178 /*** 179 * {@inheritDoc} 180 */ 181 public void mark( final int readlimit ) 182 { 183 stream_.mark( readlimit ); 184 } 185 186 /*** 187 * {@inheritDoc} 188 */ 189 public boolean markSupported() 190 { 191 return stream_.markSupported(); 192 } 193 194 /*** 195 * {@inheritDoc} 196 */ 197 public void reset() throws IOException 198 { 199 stream_.reset(); 200 } 201 202 /*** 203 * {@inheritDoc} 204 */ 205 public long skip( final long n ) throws IOException 206 { 207 return stream_.skip( n ); 208 } 209 210 /*** 211 * {@inheritDoc} 212 */ 213 public String toString() 214 { 215 return delimiter_; 216 } 217 }