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 org.apache.james.mime4j.util.ByteArrayBuffer;
023    
024    import java.io.IOException;
025    import 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     */
032    public 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    }