001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.io;
016    
017    import java.io.IOException;
018    import java.io.InputStream;
019    
020    /**
021     * Skip the specified offset until it fails three times. This is used to prevent
022     * reading an InputStream infinitely.
023     *
024     * @author Shuyang Zhou
025     */
026    public class LimitedInputStream extends InputStream {
027    
028            public LimitedInputStream(InputStream inputStream, long offset, long length)
029                    throws IOException {
030    
031                    if (offset < 0) {
032                            throw new IllegalArgumentException("Offset is less than 0");
033                    }
034    
035                    if (length < 0) {
036                            throw new IllegalArgumentException("Length is less than 0");
037                    }
038    
039                    _inputStream = inputStream;
040                    _length = length;
041    
042                    int count = 0;
043    
044                    while (offset > 0) {
045                            long skip = _inputStream.skip(offset);
046    
047                            if (skip == 0) {
048                                    if (++count >= _SKIP_RETRY_COUNT) {
049                                            throw new IOException(
050                                                    "Most likely reached the end of the input stream");
051                                    }
052                            }
053                            else {
054                                    count = 0;
055                            }
056    
057                            offset = offset - skip;
058                    }
059            }
060    
061            @Override
062            public int available() throws IOException {
063                    int available = _inputStream.available();
064    
065                    int allowed = (int)(_length - _read);
066    
067                    if (available > allowed) {
068                            return allowed;
069                    }
070                    else {
071                            return available;
072                    }
073            }
074    
075            @Override
076            public void close() throws IOException {
077                    _inputStream.close();
078            }
079    
080            @Override
081            public void mark(int readLimit) {
082            }
083    
084            @Override
085            public boolean markSupported() {
086                    return false;
087            }
088    
089            @Override
090            public int read() throws IOException {
091                    if (_read >= _length) {
092                            return -1;
093                    }
094    
095                    int read = _inputStream.read();
096    
097                    if (read >= 0) {
098                            _read++;
099                    }
100    
101                    return read;
102            }
103    
104            @Override
105            public int read(byte[] bytes) throws IOException {
106                    if (_read >= _length) {
107                            return -1;
108                    }
109    
110                    int read = 0;
111    
112                    if ((_read + bytes.length) > _length) {
113                            read = _inputStream.read(bytes, 0, (int)(_length - _read));
114                    }
115                    else {
116                            read = _inputStream.read(bytes);
117                    }
118    
119                    _read += read;
120    
121                    return read;
122            }
123    
124            @Override
125            public int read(byte[] bytes, int offset, int length)
126                    throws IOException {
127    
128                    if (_read >= _length) {
129                            return -1;
130                    }
131    
132                    int read = 0;
133    
134                    if ((_read + length) > _length) {
135                            read = _inputStream.read(bytes, 0, (int)(_length - _read));
136                    }
137                    else {
138                            read = _inputStream.read(bytes, offset, length);
139                    }
140    
141                    _read += read;
142    
143                    return read;
144            }
145    
146            @Override
147            public void reset() {
148            }
149    
150            @Override
151            public long skip(long skip) throws IOException {
152                    long allowed = _length - _read;
153    
154                    if (allowed < skip) {
155                            skip = allowed;
156                    }
157    
158                    skip = _inputStream.skip(skip);
159    
160                    _read += skip;
161    
162                    return skip;
163            }
164    
165            private static final int _SKIP_RETRY_COUNT = 3;
166    
167            private InputStream _inputStream;
168            private long _length;
169            private long _read;
170    
171    }