001 /****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one *
003 * or more contributor license agreements. See the NOTICE file *
004 * distributed with this work for additional information *
005 * regarding copyright ownership. The ASF licenses this file *
006 * to you under the Apache License, Version 2.0 (the *
007 * "License"); you may not use this file except in compliance *
008 * with the License. You may obtain a copy of the License at *
009 * *
010 * http://www.apache.org/licenses/LICENSE-2.0 *
011 * *
012 * Unless required by applicable law or agreed to in writing, *
013 * software distributed under the License is distributed on an *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015 * KIND, either express or implied. See the License for the *
016 * specific language governing permissions and limitations *
017 * under the License. *
018 ****************************************************************/
019
020 package org.apache.james.mime4j.io;
021
022 import java.io.IOException;
023 import java.io.InputStream;
024 import java.io.PushbackInputStream;
025
026 /**
027 * InputStream which converts <code>\r</code>
028 * bytes not followed by <code>\n</code> and <code>\n</code> not
029 * preceded by <code>\r</code> to <code>\r\n</code>.
030 */
031 public class EOLConvertingInputStream extends InputStream {
032 /** Converts single '\r' to '\r\n' */
033 public static final int CONVERT_CR = 1;
034 /** Converts single '\n' to '\r\n' */
035 public static final int CONVERT_LF = 2;
036 /** Converts single '\r' and '\n' to '\r\n' */
037 public static final int CONVERT_BOTH = 3;
038
039 private PushbackInputStream in = null;
040 private int previous = 0;
041 private int flags = CONVERT_BOTH;
042
043 /**
044 * Creates a new <code>EOLConvertingInputStream</code>
045 * instance converting bytes in the given <code>InputStream</code>.
046 * The flag <code>CONVERT_BOTH</code> is the default.
047 *
048 * @param in the <code>InputStream</code> to read from.
049 */
050 public EOLConvertingInputStream(InputStream in) {
051 this(in, CONVERT_BOTH);
052 }
053 /**
054 * Creates a new <code>EOLConvertingInputStream</code>
055 * instance converting bytes in the given <code>InputStream</code>.
056 *
057 * @param in the <code>InputStream</code> to read from.
058 * @param flags one of <code>CONVERT_CR</code>, <code>CONVERT_LF</code> or
059 * <code>CONVERT_BOTH</code>.
060 */
061 public EOLConvertingInputStream(InputStream in, int flags) {
062 super();
063
064 this.in = new PushbackInputStream(in, 2);
065 this.flags = flags;
066 }
067
068 /**
069 * Closes the underlying stream.
070 *
071 * @throws IOException on I/O errors.
072 */
073 @Override
074 public void close() throws IOException {
075 in.close();
076 }
077
078 /**
079 * @see java.io.InputStream#read()
080 */
081 @Override
082 public int read() throws IOException {
083 int b = in.read();
084
085 if (b == -1) {
086 return -1;
087 }
088
089 if ((flags & CONVERT_CR) != 0 && b == '\r') {
090 int c = in.read();
091 if (c != -1) {
092 in.unread(c);
093 }
094 if (c != '\n') {
095 in.unread('\n');
096 }
097 } else if ((flags & CONVERT_LF) != 0 && b == '\n' && previous != '\r') {
098 b = '\r';
099 in.unread('\n');
100 }
101
102 previous = b;
103
104 return b;
105 }
106
107 }