| package org.codehaus.jackson.io; |
| |
| import java.io.*; |
| |
| /** |
| * Simple {@link InputStream} implementation that is used to "unwind" some |
| * data previously read from an input stream; so that as long as some of |
| * that data remains, it's returned; but as long as it's read, we'll |
| * just use data from the underlying original stream. |
| * This is similar to {@link java.io.PushbackInputStream}, but here there's |
| * only one implicit pushback, when instance is constructed. |
| */ |
| public final class MergedStream |
| extends InputStream |
| { |
| final protected IOContext _context; |
| |
| final InputStream _in; |
| |
| byte[] _buffer; |
| |
| int _ptr; |
| |
| final int _end; |
| |
| public MergedStream(IOContext context, |
| InputStream in, byte[] buf, int start, int end) |
| { |
| _context = context; |
| _in = in; |
| _buffer = buf; |
| _ptr = start; |
| _end = end; |
| } |
| |
| @Override |
| public int available() throws IOException |
| { |
| if (_buffer != null) { |
| return _end - _ptr; |
| } |
| return _in.available(); |
| } |
| |
| @Override |
| public void close() throws IOException |
| { |
| freeMergedBuffer(); |
| _in.close(); |
| } |
| |
| @Override |
| public void mark(int readlimit) |
| { |
| if (_buffer == null) { |
| _in.mark(readlimit); |
| } |
| } |
| |
| @Override |
| public boolean markSupported() |
| { |
| // Only supports marks past the initial rewindable section... |
| return (_buffer == null) && _in.markSupported(); |
| } |
| |
| @Override |
| public int read() throws IOException |
| { |
| if (_buffer != null) { |
| int c = _buffer[_ptr++] & 0xFF; |
| if (_ptr >= _end) { |
| freeMergedBuffer(); |
| } |
| return c; |
| } |
| return _in.read(); |
| } |
| |
| @Override |
| public int read(byte[] b) throws IOException |
| { |
| return read(b, 0, b.length); |
| } |
| |
| @Override |
| public int read(byte[] b, int off, int len) throws IOException |
| { |
| if (_buffer != null) { |
| int avail = _end - _ptr; |
| if (len > avail) { |
| len = avail; |
| } |
| System.arraycopy(_buffer, _ptr, b, off, len); |
| _ptr += len; |
| if (_ptr >= _end) { |
| freeMergedBuffer(); |
| } |
| return len; |
| } |
| return _in.read(b, off, len); |
| } |
| |
| @Override |
| public void reset() throws IOException |
| { |
| if (_buffer == null) { |
| _in.reset(); |
| } |
| } |
| |
| @Override |
| public long skip(long n) throws IOException |
| { |
| long count = 0L; |
| |
| if (_buffer != null) { |
| int amount = _end - _ptr; |
| |
| if (amount > n) { // all in pushed back segment? |
| _ptr += (int) n; |
| return n; |
| } |
| freeMergedBuffer(); |
| count += amount; |
| n -= amount; |
| } |
| |
| if (n > 0) { |
| count += _in.skip(n); |
| } |
| return count; |
| } |
| |
| private void freeMergedBuffer() |
| { |
| byte[] buf = _buffer; |
| if (buf != null) { |
| _buffer = null; |
| if (_context != null) { |
| _context.releaseReadIOBuffer(buf); |
| } |
| } |
| } |
| } |