FromNetASCIIOutputStream.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.net.io;

  18. import java.io.FilterOutputStream;
  19. import java.io.IOException;
  20. import java.io.OutputStream;

  21. /**
  22.  * This class wraps an output stream, replacing all occurrences of <CR><LF> (carriage return followed by a linefeed), which is the NETASCII standard
  23.  * for representing a newline, with the local line separator representation. You would use this class to implement ASCII file transfers requiring conversion
  24.  * from NETASCII.
  25.  * <p>
  26.  * Because of the translation process, a call to <code>flush()</code> will not flush the last byte written if that byte was a carriage return. A call to
  27.  * {@link #close close() }, however, will flush the carriage return.
  28.  */

  29. public final class FromNetASCIIOutputStream extends FilterOutputStream {
  30.     private boolean lastWasCR;

  31.     /**
  32.      * Creates a FromNetASCIIOutputStream instance that wraps an existing OutputStream.
  33.      *
  34.      * @param output The OutputStream to wrap.
  35.      */
  36.     public FromNetASCIIOutputStream(final OutputStream output) {
  37.         super(output);
  38.         lastWasCR = false;
  39.     }

  40.     /**
  41.      * Closes the stream, writing all pending data.
  42.      *
  43.      * @throws IOException If an error occurs while closing the stream.
  44.      */
  45.     @Override
  46.     public synchronized void close() throws IOException {
  47.         if (FromNetASCIIInputStream._noConversionRequired) {
  48.             super.close();
  49.             return;
  50.         }

  51.         if (lastWasCR) {
  52.             out.write('\r');
  53.         }
  54.         super.close();
  55.     }

  56.     /**
  57.      * Writes a byte array to the stream.
  58.      *
  59.      * @param buffer The byte array to write.
  60.      * @throws IOException If an error occurs while writing to the underlying stream.
  61.      */
  62.     @Override
  63.     public synchronized void write(final byte buffer[]) throws IOException {
  64.         write(buffer, 0, buffer.length);
  65.     }

  66.     /**
  67.      * Writes a number of bytes from a byte array to the stream starting from a given offset.
  68.      *
  69.      * @param buffer The byte array to write.
  70.      * @param offset The offset into the array at which to start copying data.
  71.      * @param length The number of bytes to write.
  72.      * @throws IOException If an error occurs while writing to the underlying stream.
  73.      */
  74.     @Override
  75.     public synchronized void write(final byte buffer[], int offset, int length) throws IOException {
  76.         if (FromNetASCIIInputStream._noConversionRequired) {
  77.             // FilterOutputStream method is very slow.
  78.             // super.write(buffer, offset, length);
  79.             out.write(buffer, offset, length);
  80.             return;
  81.         }

  82.         while (length-- > 0) {
  83.             writeInt(buffer[offset++]);
  84.         }
  85.     }

  86.     /**
  87.      * Writes a byte to the stream. Note that a call to this method might not actually write a byte to the underlying stream until a subsequent character is
  88.      * written, from which it can be determined if a NETASCII line separator was encountered. This is transparent to the programmer and is only mentioned for
  89.      * completeness.
  90.      *
  91.      * @param ch The byte to write.
  92.      * @throws IOException If an error occurs while writing to the underlying stream.
  93.      */
  94.     @Override
  95.     public synchronized void write(final int ch) throws IOException {
  96.         if (FromNetASCIIInputStream._noConversionRequired) {
  97.             out.write(ch);
  98.             return;
  99.         }

  100.         writeInt(ch);
  101.     }

  102.     private void writeInt(final int ch) throws IOException {
  103.         switch (ch) {
  104.         case '\r':
  105.             lastWasCR = true;
  106.             // Don't write anything. We need to see if next one is linefeed
  107.             break;
  108.         case '\n':
  109.             if (lastWasCR) {
  110.                 out.write(FromNetASCIIInputStream._lineSeparatorBytes);
  111.                 lastWasCR = false;
  112.                 break;
  113.             }
  114.             out.write('\n');
  115.             break;
  116.         default:
  117.             if (lastWasCR) {
  118.                 out.write('\r');
  119.                 lastWasCR = false;
  120.             }
  121.             out.write(ch);
  122.             break;
  123.         }
  124.     }
  125. }