Java tutorial
package org.apache.http.impl.io; import android.support.v4.view.MotionEventCompat; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import com.newrelic.agent.android.api.v1.Defaults; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import org.apache.http.MessageConstraintException; import org.apache.http.annotation.NotThreadSafe; import org.apache.http.config.MessageConstraints; import org.apache.http.io.BufferInfo; import org.apache.http.io.HttpTransportMetrics; import org.apache.http.io.SessionInputBuffer; import org.apache.http.util.Args; import org.apache.http.util.Asserts; import org.apache.http.util.ByteArrayBuffer; import org.apache.http.util.CharArrayBuffer; @NotThreadSafe public class SessionInputBufferImpl implements BufferInfo, SessionInputBuffer { private final byte[] buffer; private int bufferlen; private int bufferpos; private CharBuffer cbuf; private final MessageConstraints constraints; private final CharsetDecoder decoder; private InputStream instream; private final ByteArrayBuffer linebuffer; private final HttpTransportMetricsImpl metrics; private final int minChunkLimit; public SessionInputBufferImpl(HttpTransportMetricsImpl httpTransportMetricsImpl, int i, int i2, MessageConstraints messageConstraints, CharsetDecoder charsetDecoder) { Args.notNull(httpTransportMetricsImpl, "HTTP transport metrcis"); Args.positive(i, "Buffer size"); this.metrics = httpTransportMetricsImpl; this.buffer = new byte[i]; this.bufferpos = 0; this.bufferlen = 0; if (i2 < 0) { i2 = AccessibilityNodeInfoCompat.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; } this.minChunkLimit = i2; if (messageConstraints == null) { messageConstraints = MessageConstraints.DEFAULT; } this.constraints = messageConstraints; this.linebuffer = new ByteArrayBuffer(i); this.decoder = charsetDecoder; } public SessionInputBufferImpl(HttpTransportMetricsImpl httpTransportMetricsImpl, int i) { this(httpTransportMetricsImpl, i, i, null, null); } public void bind(InputStream inputStream) { this.instream = inputStream; } public boolean isBound() { return this.instream != null; } public int capacity() { return this.buffer.length; } public int length() { return this.bufferlen - this.bufferpos; } public int available() { return capacity() - length(); } private int streamRead(byte[] bArr, int i, int i2) throws IOException { Asserts.notNull(this.instream, "Input stream"); return this.instream.read(bArr, i, i2); } public int fillBuffer() throws IOException { int i; if (this.bufferpos > 0) { i = this.bufferlen - this.bufferpos; if (i > 0) { System.arraycopy(this.buffer, this.bufferpos, this.buffer, 0, i); } this.bufferpos = 0; this.bufferlen = i; } int i2 = this.bufferlen; i = streamRead(this.buffer, i2, this.buffer.length - i2); if (i == -1) { return -1; } this.bufferlen = i2 + i; this.metrics.incrementBytesTransferred((long) i); return i; } public boolean hasBufferedData() { return this.bufferpos < this.bufferlen; } public void clear() { this.bufferpos = 0; this.bufferlen = 0; } public int read() throws IOException { while (!hasBufferedData()) { if (fillBuffer() == -1) { return -1; } } byte[] bArr = this.buffer; int i = this.bufferpos; this.bufferpos = i + 1; return bArr[i] & MotionEventCompat.ACTION_MASK; } public int read(byte[] bArr, int i, int i2) throws IOException { if (bArr == null) { return 0; } int min; if (hasBufferedData()) { min = Math.min(i2, this.bufferlen - this.bufferpos); System.arraycopy(this.buffer, this.bufferpos, bArr, i, min); this.bufferpos += min; return min; } else if (i2 > this.minChunkLimit) { min = streamRead(bArr, i, i2); if (min <= 0) { return min; } this.metrics.incrementBytesTransferred((long) min); return min; } else { while (!hasBufferedData()) { if (fillBuffer() == -1) { return -1; } } min = Math.min(i2, this.bufferlen - this.bufferpos); System.arraycopy(this.buffer, this.bufferpos, bArr, i, min); this.bufferpos += min; return min; } } public int read(byte[] bArr) throws IOException { if (bArr == null) { return 0; } return read(bArr, 0, bArr.length); } private int locateLF() { for (int i = this.bufferpos; i < this.bufferlen; i++) { if (this.buffer[i] == 10) { return i; } } return -1; } public int readLine(CharArrayBuffer charArrayBuffer) throws IOException { Args.notNull(charArrayBuffer, "Char array buffer"); Object obj = 1; int i = 0; while (obj != null) { int locateLF = locateLF(); if (locateLF == -1) { if (hasBufferedData()) { this.linebuffer.append(this.buffer, this.bufferpos, this.bufferlen - this.bufferpos); this.bufferpos = this.bufferlen; } i = fillBuffer(); if (i == -1) { obj = null; } } else if (this.linebuffer.isEmpty()) { return lineFromReadBuffer(charArrayBuffer, locateLF); } else { this.linebuffer.append(this.buffer, this.bufferpos, (locateLF + 1) - this.bufferpos); this.bufferpos = locateLF + 1; obj = null; } locateLF = this.constraints.getMaxLineLength(); if (locateLF > 0 && this.linebuffer.length() >= locateLF) { throw new MessageConstraintException("Maximum line length limit exceeded"); } } if (i == -1 && this.linebuffer.isEmpty()) { return -1; } return lineFromLineBuffer(charArrayBuffer); } private int lineFromLineBuffer(CharArrayBuffer charArrayBuffer) throws IOException { int length = this.linebuffer.length(); if (length > 0) { if (this.linebuffer.byteAt(length - 1) == 10) { length--; } if (length > 0 && this.linebuffer.byteAt(length - 1) == 13) { length--; } } if (this.decoder == null) { charArrayBuffer.append(this.linebuffer, 0, length); } else { length = appendDecoded(charArrayBuffer, ByteBuffer.wrap(this.linebuffer.buffer(), 0, length)); } this.linebuffer.clear(); return length; } private int lineFromReadBuffer(CharArrayBuffer charArrayBuffer, int i) throws IOException { int i2 = this.bufferpos; this.bufferpos = i + 1; if (i > i2 && this.buffer[i - 1] == 13) { i--; } int i3 = i - i2; if (this.decoder != null) { return appendDecoded(charArrayBuffer, ByteBuffer.wrap(this.buffer, i2, i3)); } charArrayBuffer.append(this.buffer, i2, i3); return i3; } private int appendDecoded(CharArrayBuffer charArrayBuffer, ByteBuffer byteBuffer) throws IOException { int i = 0; if (!byteBuffer.hasRemaining()) { return 0; } if (this.cbuf == null) { this.cbuf = CharBuffer.allocate(Defaults.RESPONSE_BODY_LIMIT); } this.decoder.reset(); while (byteBuffer.hasRemaining()) { i += handleDecodingResult(this.decoder.decode(byteBuffer, this.cbuf, true), charArrayBuffer, byteBuffer); } i += handleDecodingResult(this.decoder.flush(this.cbuf), charArrayBuffer, byteBuffer); this.cbuf.clear(); return i; } private int handleDecodingResult(CoderResult coderResult, CharArrayBuffer charArrayBuffer, ByteBuffer byteBuffer) throws IOException { if (coderResult.isError()) { coderResult.throwException(); } this.cbuf.flip(); int remaining = this.cbuf.remaining(); while (this.cbuf.hasRemaining()) { charArrayBuffer.append(this.cbuf.get()); } this.cbuf.compact(); return remaining; } public String readLine() throws IOException { CharArrayBuffer charArrayBuffer = new CharArrayBuffer(64); if (readLine(charArrayBuffer) != -1) { return charArrayBuffer.toString(); } return null; } public boolean isDataAvailable(int i) throws IOException { return hasBufferedData(); } public HttpTransportMetrics getMetrics() { return this.metrics; } }