View Javadoc
1 package org.apache.commons.net.io; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Commons" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import java.io.IOException; 58 import java.io.PushbackReader; 59 import java.io.Reader; 60 61 /*** 62 * DotTerminatedMessageReader is a class used to read messages from a 63 * server that are terminated by a single dot followed by a 64 * <CR><LF> 65 * sequence and with double dots appearing at the begining of lines which 66 * do not signal end of message yet start with a dot. Various Internet 67 * protocols such as NNTP and POP3 produce messages of this type. 68 * <p> 69 * This class handles stripping of the duplicate period at the beginning 70 * of lines starting with a period, converts NETASCII newlines to the 71 * local line separator format, truncates the end of message indicator, 72 * and ensures you cannot read past the end of the message. 73 * @author <a href="mailto:savarese@apache.org">Daniel F. Savarese</a> 74 * @version $Id: DotTerminatedMessageReader.java,v 1.6 2003/01/26 04:33:32 brekke Exp $ 75 */ 76 public final class DotTerminatedMessageReader extends Reader 77 { 78 private static final String LS; 79 private static final char[] LS_CHARS; 80 81 static 82 { 83 LS = System.getProperty("line.separator"); 84 LS_CHARS = LS.toCharArray(); 85 } 86 87 private boolean atBeginning; 88 private boolean eof; 89 private int pos; 90 private char[] internalBuffer; 91 private PushbackReader internalReader; 92 93 /*** 94 * Creates a DotTerminatedMessageReader that wraps an existing Reader 95 * input source. 96 * @param reader The Reader input source containing the message. 97 */ 98 public DotTerminatedMessageReader(Reader reader) 99 { 100 super(reader); 101 internalBuffer = new char[LS_CHARS.length + 3]; 102 pos = internalBuffer.length; 103 // Assumes input is at start of message 104 atBeginning = true; 105 eof = false; 106 internalReader = new PushbackReader(reader); 107 } 108 109 /*** 110 * Reads and returns the next character in the message. If the end of the 111 * message has been reached, returns -1. Note that a call to this method 112 * may result in multiple reads from the underlying input stream to decode 113 * the message properly (removing doubled dots and so on). All of 114 * this is transparent to the programmer and is only mentioned for 115 * completeness. 116 * @return The next character in the message. Returns -1 if the end of the 117 * message has been reached. 118 * @exception IOException If an error occurs while reading the underlying 119 * stream. 120 */ 121 public int read() throws IOException 122 { 123 int ch; 124 125 synchronized (lock) 126 { 127 if (pos < internalBuffer.length) 128 { 129 return internalBuffer[pos++]; 130 } 131 132 if (eof) 133 { 134 return -1; 135 } 136 137 if ((ch = internalReader.read()) == -1) 138 { 139 eof = true; 140 return -1; 141 } 142 143 if (atBeginning) 144 { 145 atBeginning = false; 146 if (ch == '.') 147 { 148 ch = internalReader.read(); 149 150 if (ch != '.') 151 { 152 // read newline 153 eof = true; 154 internalReader.read(); 155 return -1; 156 } 157 else 158 { 159 return '.'; 160 } 161 } 162 } 163 164 if (ch == '\r') 165 { 166 ch = internalReader.read(); 167 168 if (ch == '\n') 169 { 170 ch = internalReader.read(); 171 172 if (ch == '.') 173 { 174 ch = internalReader.read(); 175 176 if (ch != '.') 177 { 178 // read newline and indicate end of file 179 internalReader.read(); 180 eof = true; 181 } 182 else 183 { 184 internalBuffer[--pos] = (char) ch; 185 } 186 } 187 else 188 { 189 internalReader.unread(ch); 190 } 191 192 pos -= LS_CHARS.length; 193 System.arraycopy(LS_CHARS, 0, internalBuffer, pos, 194 LS_CHARS.length); 195 ch = internalBuffer[pos++]; 196 } 197 else 198 { 199 internalBuffer[--pos] = (char) ch; 200 return '\r'; 201 } 202 } 203 204 return ch; 205 } 206 } 207 208 /*** 209 * Reads the next characters from the message into an array and 210 * returns the number of characters read. Returns -1 if the end of the 211 * message has been reached. 212 * @param buffer The character array in which to store the characters. 213 * @return The number of characters read. Returns -1 if the 214 * end of the message has been reached. 215 * @exception IOException If an error occurs in reading the underlying 216 * stream. 217 */ 218 public int read(char[] buffer) throws IOException 219 { 220 return read(buffer, 0, buffer.length); 221 } 222 223 /*** 224 * Reads the next characters from the message into an array and 225 * returns the number of characters read. Returns -1 if the end of the 226 * message has been reached. The characters are stored in the array 227 * starting from the given offset and up to the length specified. 228 * @param buffer The character array in which to store the characters. 229 * @param offset The offset into the array at which to start storing 230 * characters. 231 * @param length The number of characters to read. 232 * @return The number of characters read. Returns -1 if the 233 * end of the message has been reached. 234 * @exception IOException If an error occurs in reading the underlying 235 * stream. 236 */ 237 public int read(char[] buffer, int offset, int length) throws IOException 238 { 239 int ch, off; 240 synchronized (lock) 241 { 242 if (length < 1) 243 { 244 return 0; 245 } 246 if ((ch = read()) == -1) 247 { 248 return -1; 249 } 250 off = offset; 251 252 do 253 { 254 buffer[offset++] = (char) ch; 255 } 256 while (--length > 0 && (ch = read()) != -1); 257 258 return (offset - off); 259 } 260 } 261 262 /*** 263 * Determines if the message is ready to be read. 264 * @return True if the message is ready to be read, false if not. 265 * @exception IOException If an error occurs while checking the underlying 266 * stream. 267 */ 268 public boolean ready() throws IOException 269 { 270 synchronized (lock) 271 { 272 return (pos < internalBuffer.length || internalReader.ready()); 273 } 274 } 275 276 /*** 277 * Closes the message for reading. This doesn't actually close the 278 * underlying stream. The underlying stream may still be used for 279 * communicating with the server and therefore is not closed. 280 * <p> 281 * If the end of the message has not yet been reached, this method 282 * will read the remainder of the message until it reaches the end, 283 * so that the underlying stream may continue to be used properly 284 * for communicating with the server. If you do not fully read 285 * a message, you MUST close it, otherwise your program will likely 286 * hang or behave improperly. 287 * @exception IOException If an error occurs while reading the 288 * underlying stream. 289 */ 290 public void close() throws IOException 291 { 292 synchronized (lock) 293 { 294 if (internalReader == null) 295 { 296 return; 297 } 298 299 if (!eof) 300 { 301 while (read() != -1) 302 { 303 ; 304 } 305 } 306 eof = true; 307 atBeginning = false; 308 pos = internalBuffer.length; 309 internalReader = null; 310 } 311 } 312 }

This page was automatically generated by Maven