1 package com.fasterxml.jackson.core.io; 2 3 import java.io.*; 4 5 /** 6 * Simple {@link InputStream} implementation that is used to "unwind" some 7 * data previously read from an input stream; so that as long as some of 8 * that data remains, it's returned; but as long as it's read, we'll 9 * just use data from the underlying original stream. 10 * This is similar to {@link java.io.PushbackInputStream}, but here there's 11 * only one implicit pushback, when instance is constructed. 12 */ 13 public final class MergedStream extends InputStream 14 { 15 final private IOContext _ctxt; 16 17 final private InputStream _in; 18 19 private byte[] _b; 20 21 private int _ptr; 22 23 final private int _end; 24 MergedStream(IOContext ctxt, InputStream in, byte[] buf, int start, int end)25 public MergedStream(IOContext ctxt, InputStream in, byte[] buf, int start, int end) { 26 _ctxt = ctxt; 27 _in = in; 28 _b = buf; 29 _ptr = start; 30 _end = end; 31 } 32 33 @Override available()34 public int available() throws IOException { 35 if (_b != null) { 36 return _end - _ptr; 37 } 38 return _in.available(); 39 } 40 close()41 @Override public void close() throws IOException { 42 _free(); 43 _in.close(); 44 } 45 mark(int readlimit)46 @Override public void mark(int readlimit) { 47 if (_b == null) { _in.mark(readlimit); } 48 } 49 markSupported()50 @Override public boolean markSupported() { 51 // Only supports marks past the initial rewindable section... 52 return (_b == null) && _in.markSupported(); 53 } 54 read()55 @Override public int read() throws IOException { 56 if (_b != null) { 57 int c = _b[_ptr++] & 0xFF; 58 if (_ptr >= _end) { 59 _free(); 60 } 61 return c; 62 } 63 return _in.read(); 64 } 65 read(byte[] b)66 @Override public int read(byte[] b) throws IOException { 67 return read(b, 0, b.length); 68 } 69 70 @Override read(byte[] b, int off, int len)71 public int read(byte[] b, int off, int len) throws IOException { 72 if (_b != null) { 73 int avail = _end - _ptr; 74 if (len > avail) { 75 len = avail; 76 } 77 System.arraycopy(_b, _ptr, b, off, len); 78 _ptr += len; 79 if (_ptr >= _end) { 80 _free(); 81 } 82 return len; 83 } 84 return _in.read(b, off, len); 85 } 86 87 @Override reset()88 public void reset() throws IOException { 89 if (_b == null) { _in.reset(); } 90 } 91 92 @Override skip(long n)93 public long skip(long n) throws IOException { 94 long count = 0L; 95 96 if (_b != null) { 97 int amount = _end - _ptr; 98 99 if (amount > n) { // all in pushed back segment? 100 _ptr += (int) n; 101 return n; 102 } 103 _free(); 104 count += amount; 105 n -= amount; 106 } 107 108 if (n > 0) { count += _in.skip(n); } 109 return count; 110 } 111 _free()112 private void _free() { 113 byte[] buf = _b; 114 if (buf != null) { 115 _b = null; 116 if (_ctxt != null) { 117 _ctxt.releaseReadIOBuffer(buf); 118 } 119 } 120 } 121 } 122