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 org.apache.james.mime4j.util.ByteArrayBuffer;
023
024import java.io.IOException;
025import java.io.InputStream;
026
027/**
028 * <code>InputStream</code> used by the MIME parser to detect whether the
029 * underlying data stream was used (read from) and whether the end of the
030 * stream was reached.
031 */
032public class LineReaderInputStreamAdaptor extends LineReaderInputStream {
033
034    private final LineReaderInputStream bis;
035    private final int maxLineLen;
036
037    private boolean used = false;
038    private boolean eof = false;
039
040    public LineReaderInputStreamAdaptor(
041            final InputStream is,
042            int maxLineLen) {
043        super(is);
044        if (is instanceof LineReaderInputStream) {
045            this.bis = (LineReaderInputStream) is;
046        } else {
047            this.bis = null;
048        }
049        this.maxLineLen = maxLineLen;
050    }
051
052    public LineReaderInputStreamAdaptor(
053            final InputStream is) {
054        this(is, -1);
055    }
056
057    @Override
058    public int read() throws IOException {
059        int i = in.read();
060        this.eof = i == -1;
061        this.used = true;
062        return i;
063    }
064
065    @Override
066    public int read(byte[] b, int off, int len) throws IOException {
067        int i = in.read(b, off, len);
068        this.eof = i == -1;
069        this.used = true;
070        return i;
071    }
072
073    @Override
074    public int readLine(final ByteArrayBuffer dst)
075            throws MaxLineLimitException, IOException {
076        int i;
077        if (this.bis != null) {
078             i = this.bis.readLine(dst);
079        } else {
080             i = doReadLine(dst);
081        }
082        this.eof = i == -1;
083        this.used = true;
084        return i;
085    }
086
087    private int doReadLine(final ByteArrayBuffer dst)
088            throws MaxLineLimitException, IOException {
089        int total = 0;
090        int ch;
091        while ((ch = in.read()) != -1) {
092            dst.append(ch);
093            total++;
094            if (this.maxLineLen > 0 && dst.length() >= this.maxLineLen) {
095                throw new MaxLineLimitException("Maximum line length limit exceeded");
096            }
097            if (ch == '\n') {
098                break;
099            }
100        }
101        if (total == 0 && ch == -1) {
102            return -1;
103        } else {
104            return total;
105        }
106    }
107
108    public boolean eof() {
109        return this.eof;
110    }
111
112    public boolean isUsed() {
113        return this.used;
114    }
115
116    @Override
117    public String toString() {
118        return "[LineReaderInputStreamAdaptor: " + bis + "]";
119    }
120
121    @Override
122    public boolean unread(ByteArrayBuffer buf) {
123        if (bis != null) {
124            return bis.unread(buf);
125        } else {
126            return false;
127        }
128    }
129
130    @Override
131    public long skip(long count) throws IOException {
132        if (count <= 0) {
133            return 0; // So specified by InputStream.skip(long).
134        }
135        final int bufferSize = count > 8192 ? 8192 : (int) count;
136        final byte[] buffer = new byte[bufferSize];
137        long result = 0;
138        while (count > 0) {
139            int res = read(buffer);
140            if (res == -1) {
141                break;
142            }
143            result += res;
144            count -= res;
145        }
146        return result;
147    }
148}