001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.net.io; 019 020import java.io.FilterInputStream; 021import java.io.IOException; 022import java.io.InputStream; 023 024import org.apache.commons.net.util.NetConstants; 025 026/** 027 * This class wraps an input stream, replacing all singly occurring <LF> (linefeed) characters with <CR><LF> (carriage return followed by 028 * linefeed), which is the NETASCII standard for representing a newline. You would use this class to implement ASCII file transfers requiring conversion to 029 * NETASCII. 030 * 031 * 032 */ 033 034public final class ToNetASCIIInputStream extends FilterInputStream { 035 private static final int NOTHING_SPECIAL = 0; 036 private static final int LAST_WAS_CR = 1; 037 private static final int LAST_WAS_NL = 2; 038 private int status; 039 040 /** 041 * Creates a ToNetASCIIInputStream instance that wraps an existing InputStream. 042 * 043 * @param input The InputStream to wrap. 044 */ 045 public ToNetASCIIInputStream(final InputStream input) { 046 super(input); 047 status = NOTHING_SPECIAL; 048 } 049 050 @Override 051 public int available() throws IOException { 052 final int result; 053 054 result = in.available(); 055 056 if (status == LAST_WAS_NL) { 057 return result + 1; 058 } 059 060 return result; 061 } 062 063 /** Returns false. Mark is not supported. */ 064 @Override 065 public boolean markSupported() { 066 return false; 067 } 068 069 /** 070 * Reads and returns the next byte in the stream. If the end of the message has been reached, returns -1. 071 * 072 * @return The next character in the stream. Returns -1 if the end of the stream has been reached. 073 * @throws IOException If an error occurs while reading the underlying stream. 074 */ 075 @Override 076 public int read() throws IOException { 077 final int ch; 078 079 if (status == LAST_WAS_NL) { 080 status = NOTHING_SPECIAL; 081 return '\n'; 082 } 083 084 ch = in.read(); 085 086 switch (ch) { 087 case '\r': 088 status = LAST_WAS_CR; 089 return '\r'; 090 case '\n': 091 if (status != LAST_WAS_CR) { 092 status = LAST_WAS_NL; 093 return '\r'; 094 } 095 //$FALL-THROUGH$ 096 default: 097 status = NOTHING_SPECIAL; 098 return ch; 099 } 100 // statement not reached 101 // return ch; 102 } 103 104 /** 105 * Reads the next number of bytes from the stream into an array and returns the number of bytes read. Returns -1 if the end of the stream has been reached. 106 * 107 * @param buffer The byte array in which to store the data. 108 * @return The number of bytes read. Returns -1 if the end of the message has been reached. 109 * @throws IOException If an error occurs in reading the underlying stream. 110 */ 111 @Override 112 public int read(final byte[] buffer) throws IOException { 113 return read(buffer, 0, buffer.length); 114 } 115 116 /** 117 * Reads the next number of bytes from the stream into an array and returns the number of bytes read. Returns -1 if the end of the message has been reached. 118 * The characters are stored in the array starting from the given offset and up to the length specified. 119 * 120 * @param buffer The byte array in which to store the data. 121 * @param offset The offset into the array at which to start storing data. 122 * @param length The number of bytes to read. 123 * @return The number of bytes read. Returns -1 if the end of the stream has been reached. 124 * @throws IOException If an error occurs while reading the underlying stream. 125 */ 126 @Override 127 public int read(final byte[] buffer, int offset, int length) throws IOException { 128 int ch; 129 final int off; 130 131 if (length < 1) { 132 return 0; 133 } 134 135 ch = available(); 136 137 if (length > ch) { 138 length = ch; 139 } 140 141 // If nothing is available, block to read only one character 142 if (length < 1) { 143 length = 1; 144 } 145 146 if ((ch = read()) == NetConstants.EOS) { 147 return NetConstants.EOS; 148 } 149 150 off = offset; 151 152 do { 153 buffer[offset++] = (byte) ch; 154 } while (--length > 0 && (ch = read()) != NetConstants.EOS); 155 156 return offset - off; 157 } 158}