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.FilterOutputStream;
021import java.io.IOException;
022import java.io.OutputStream;
023
024/**
025 * This class wraps an output stream, replacing all singly occurring
026 * <LF> (linefeed) characters with <CR><LF> (carriage return
027 * followed by linefeed), which is the NETASCII standard for representing
028 * a newline.
029 * You would use this class to implement ASCII file transfers requiring
030 * conversion to NETASCII.
031 *
032 *
033 */
034
035public final class ToNetASCIIOutputStream extends FilterOutputStream
036{
037    private boolean lastWasCR;
038
039    /**
040     * Creates a ToNetASCIIOutputStream instance that wraps an existing
041     * OutputStream.
042     *
043     * @param output  The OutputStream to wrap.
044     */
045    public ToNetASCIIOutputStream(final OutputStream output)
046    {
047        super(output);
048        lastWasCR = false;
049    }
050
051
052    /**
053     * Writes a byte to the stream.    Note that a call to this method
054     * may result in multiple writes to the underlying input stream in order
055     * to convert naked newlines to NETASCII line separators.
056     * This is transparent to the programmer and is only mentioned for
057     * completeness.
058     *
059     * @param ch The byte to write.
060     * @throws IOException If an error occurs while writing to the underlying
061     *            stream.
062     */
063    @Override
064    public synchronized void write(final int ch)
065    throws IOException
066    {
067        switch (ch)
068        {
069        case '\r':
070            lastWasCR = true;
071            out.write('\r');
072            return ;
073        case '\n':
074            if (!lastWasCR) {
075                out.write('\r');
076            }
077            //$FALL-THROUGH$
078        default:
079            lastWasCR = false;
080            out.write(ch);
081        }
082    }
083
084
085    /**
086     * Writes a byte array to the stream.
087     *
088     * @param buffer  The byte array to write.
089     * @throws IOException If an error occurs while writing to the underlying
090     *            stream.
091     */
092    @Override
093    public synchronized void write(final byte buffer[])
094    throws IOException
095    {
096        write(buffer, 0, buffer.length);
097    }
098
099
100    /**
101     * Writes a number of bytes from a byte array to the stream starting from
102     * a given offset.
103     *
104     * @param buffer  The byte array to write.
105     * @param offset  The offset into the array at which to start copying data.
106     * @param length  The number of bytes to write.
107     * @throws IOException If an error occurs while writing to the underlying
108     *            stream.
109     */
110    @Override
111    public synchronized void write(final byte buffer[], int offset, int length)
112    throws IOException
113    {
114        while (length-- > 0) {
115            write(buffer[offset++]);
116        }
117    }
118
119}