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 020package org.apache.james.mime4j.io; 021 022import java.io.IOException; 023import java.io.InputStream; 024import 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 */ 031public 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}