1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.net.io;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.PushbackInputStream;
  20. /***
  21. * This class wraps an input stream, replacing all occurrences
  22. * of <CR><LF> (carriage return followed by a linefeed),
  23. * which is the NETASCII standard for representing a newline, with the
  24. * local line separator representation. You would use this class to
  25. * implement ASCII file transfers requiring conversion from NETASCII.
  26. * <p>
  27. * <p>
  28. * @author Daniel F. Savarese
  29. ***/
  30. public final class FromNetASCIIInputStream extends PushbackInputStream
  31. {
  32. static final boolean _noConversionRequired;
  33. static final String _lineSeparator;
  34. static final byte[] _lineSeparatorBytes;
  35. static {
  36. _lineSeparator = System.getProperty("line.separator");
  37. _noConversionRequired = _lineSeparator.equals("\r\n");
  38. _lineSeparatorBytes = _lineSeparator.getBytes();
  39. }
  40. private int __length = 0;
  41. /***
  42. * Returns true if the NetASCII line separator differs from the system
  43. * line separator, false if they are the same. This method is useful
  44. * to determine whether or not you need to instantiate a
  45. * FromNetASCIIInputStream object.
  46. * <p>
  47. * @return True if the NETASCII line separator differs from the local
  48. * system line separator, false if they are the same.
  49. ***/
  50. public static final boolean isConversionRequired()
  51. {
  52. return !_noConversionRequired;
  53. }
  54. /***
  55. * Creates a FromNetASCIIInputStream instance that wraps an existing
  56. * InputStream.
  57. ***/
  58. public FromNetASCIIInputStream(InputStream input)
  59. {
  60. super(input, _lineSeparatorBytes.length + 1);
  61. }
  62. private int __read() throws IOException
  63. {
  64. int ch;
  65. ch = super.read();
  66. if (ch == '\r')
  67. {
  68. ch = super.read();
  69. if (ch == '\n')
  70. {
  71. unread(_lineSeparatorBytes);
  72. ch = super.read();
  73. // This is a kluge for read(byte[], ...) to read the right amount
  74. --__length;
  75. }
  76. else
  77. {
  78. if (ch != -1)
  79. unread(ch);
  80. return '\r';
  81. }
  82. }
  83. return ch;
  84. }
  85. /***
  86. * Reads and returns the next byte in the stream. If the end of the
  87. * message has been reached, returns -1. Note that a call to this method
  88. * may result in multiple reads from the underlying input stream in order
  89. * to convert NETASCII line separators to the local line separator format.
  90. * This is transparent to the programmer and is only mentioned for
  91. * completeness.
  92. * <p>
  93. * @return The next character in the stream. Returns -1 if the end of the
  94. * stream has been reached.
  95. * @exception IOException If an error occurs while reading the underlying
  96. * stream.
  97. ***/
  98. public int read() throws IOException
  99. {
  100. if (_noConversionRequired)
  101. return super.read();
  102. return __read();
  103. }
  104. /***
  105. * Reads the next number of bytes from the stream into an array and
  106. * returns the number of bytes read. Returns -1 if the end of the
  107. * stream has been reached.
  108. * <p>
  109. * @param buffer The byte array in which to store the data.
  110. * @return The number of bytes read. Returns -1 if the
  111. * end of the message has been reached.
  112. * @exception IOException If an error occurs in reading the underlying
  113. * stream.
  114. ***/
  115. public int read(byte buffer[]) throws IOException
  116. {
  117. return read(buffer, 0, buffer.length);
  118. }
  119. /***
  120. * Reads the next number of bytes from the stream into an array and returns
  121. * the number of bytes read. Returns -1 if the end of the
  122. * message has been reached. The characters are stored in the array
  123. * starting from the given offset and up to the length specified.
  124. * <p>
  125. * @param buffer The byte array in which to store the data.
  126. * @param offset The offset into the array at which to start storing data.
  127. * @param length The number of bytes to read.
  128. * @return The number of bytes read. Returns -1 if the
  129. * end of the stream has been reached.
  130. * @exception IOException If an error occurs while reading the underlying
  131. * stream.
  132. ***/
  133. public int read(byte buffer[], int offset, int length) throws IOException
  134. {
  135. int ch, off;
  136. if (length < 1)
  137. return 0;
  138. ch = available();
  139. __length = (length > ch ? ch : length);
  140. // If nothing is available, block to read only one character
  141. if (__length < 1)
  142. __length = 1;
  143. if (_noConversionRequired)
  144. return super.read(buffer, offset, __length);
  145. if ((ch = __read()) == -1)
  146. return -1;
  147. off = offset;
  148. do
  149. {
  150. buffer[offset++] = (byte)ch;
  151. }
  152. while (--__length > 0 && (ch = __read()) != -1);
  153. return (offset - off);
  154. }
  155. // PushbackInputStream in JDK 1.1.3 returns the wrong thing
  156. /***
  157. * Returns the number of bytes that can be read without blocking EXCEPT
  158. * when newline conversions have to be made somewhere within the
  159. * available block of bytes. In other words, you really should not
  160. * rely on the value returned by this method if you are trying to avoid
  161. * blocking.
  162. ***/
  163. public int available() throws IOException
  164. {
  165. return (buf.length - pos) + in.available();
  166. }
  167. }