14ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira/****************************************************************
24ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * Licensed to the Apache Software Foundation (ASF) under one   *
34ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * or more contributor license agreements.  See the NOTICE file *
44ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * distributed with this work for additional information        *
54ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * regarding copyright ownership.  The ASF licenses this file   *
64ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * to you under the Apache License, Version 2.0 (the            *
74ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * "License"); you may not use this file except in compliance   *
84ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * with the License.  You may obtain a copy of the License at   *
94ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira *                                                              *
104ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira *   http://www.apache.org/licenses/LICENSE-2.0                 *
114ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira *                                                              *
124ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * Unless required by applicable law or agreed to in writing,   *
134ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * software distributed under the License is distributed on an  *
144ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
154ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * KIND, either express or implied.  See the License for the    *
164ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * specific language governing permissions and limitations      *
174ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * under the License.                                           *
184ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira ****************************************************************/
194ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
204ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereirapackage org.apache.james.mime4j;
214ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
224ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereiraimport java.io.IOException;
234ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereiraimport java.io.InputStream;
244ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereiraimport java.io.PushbackInputStream;
254ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
264ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira/**
274ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * InputStream which converts <code>\r</code>
284ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * bytes not followed by <code>\n</code> and <code>\n</code> not
294ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * preceded by <code>\r</code> to <code>\r\n</code>.
304ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira *
314ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira *
324ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira * @version $Id: EOLConvertingInputStream.java,v 1.4 2004/11/29 13:15:42 ntherning Exp $
334ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira */
344ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereirapublic class EOLConvertingInputStream extends InputStream {
354ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    /** Converts single '\r' to '\r\n' */
364ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    public static final int CONVERT_CR   = 1;
374ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    /** Converts single '\n' to '\r\n' */
384ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    public static final int CONVERT_LF   = 2;
394ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    /** Converts single '\r' and '\n' to '\r\n' */
404ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    public static final int CONVERT_BOTH = 3;
4196d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank
424ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    private PushbackInputStream in = null;
434ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    private int previous = 0;
444ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    private int flags = CONVERT_BOTH;
4596d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    private int size = 0;
4696d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    private int pos = 0;
4796d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    private int nextTenPctPos;
4896d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    private int tenPctSize;
4996d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    private Callback callback;
5096d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank
5196d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    public interface Callback {
5296d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        public void report(int bytesRead);
5396d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    }
5496d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank
554ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    /**
564ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * Creates a new <code>EOLConvertingInputStream</code>
574ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * instance converting bytes in the given <code>InputStream</code>.
584ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * The flag <code>CONVERT_BOTH</code> is the default.
594ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     *
604ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * @param in the <code>InputStream</code> to read from.
614ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     */
6296d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    public EOLConvertingInputStream(InputStream _in) {
6396d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        super();
6496d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        in = new PushbackInputStream(_in, 2);
654ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    }
6696d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank
674ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    /**
684ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * Creates a new <code>EOLConvertingInputStream</code>
694ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * instance converting bytes in the given <code>InputStream</code>.
704ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     *
7196d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank     * @param _in the <code>InputStream</code> to read from.
7296d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank     * @param _size the size of the input stream (need not be exact)
7396d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank     * @param _callback a callback reporting when each 10% of stream's size is reached
744ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     */
7596d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    public EOLConvertingInputStream(InputStream _in, int _size, Callback _callback) {
7696d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        this(_in);
7796d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        size = _size;
7896d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        tenPctSize = size / 10;
7996d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        nextTenPctPos = tenPctSize;
8096d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        callback = _callback;
814ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    }
824ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
834ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    /**
844ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * Closes the underlying stream.
854ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     *
864ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * @throws IOException on I/O errors.
874ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     */
884ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    public void close() throws IOException {
894ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira        in.close();
904ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    }
914ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
9296d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    private int readByte() throws IOException {
9396d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        int b = in.read();
9496d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        if (b != -1) {
9596d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank            if (callback != null && pos++ == nextTenPctPos) {
9696d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank                nextTenPctPos += tenPctSize;
9796d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank                if (callback != null) {
9896d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank                    callback.report(pos);
9996d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank                }
10096d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank            }
10196d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        }
10296d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        return b;
10396d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    }
10496d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank
10596d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    private void unreadByte(int c) throws IOException {
10696d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        in.unread(c);
10796d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        pos--;
10896d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank    }
10996d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank
1104ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    /**
1114ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     * @see java.io.InputStream#read()
1124ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira     */
1134ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    public int read() throws IOException {
11496d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank        int b = readByte();
1154ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
1164ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira        if (b == -1) {
11796d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank            pos = size;
1184ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira            return -1;
1194ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira        }
1204ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
1214ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira        if ((flags & CONVERT_CR) != 0 && b == '\r') {
12296d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank            int c = readByte();
1234ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira            if (c != -1) {
12496d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank                unreadByte(c);
1254ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira            }
1264ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira            if (c != '\n') {
12796d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank                unreadByte('\n');
1284ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira            }
1294ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira        } else if ((flags & CONVERT_LF) != 0 && b == '\n' && previous != '\r') {
1304ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira            b = '\r';
13196d998a038c3df43f8f2e94c570e70d9d24fbfbcMarc Blank            unreadByte('\n');
1324ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira        }
1334ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
1344ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira        previous = b;
1354ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
1364ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira        return b;
1374ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira    }
1384ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira
1394ebb916ddca5f59d4f854f104fca0de6e0dda706Mindy Pereira}
140