193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/* 293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Copyright (C) 2013 The Android Open Source Project 393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Licensed under the Apache License, Version 2.0 (the "License"); 593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * you may not use this file except in compliance with the License. 693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * You may obtain a copy of the License at 793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * http://www.apache.org/licenses/LICENSE-2.0 993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 1093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Unless required by applicable law or agreed to in writing, software 1193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * distributed under the License is distributed on an "AS IS" BASIS, 1293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * See the License for the specific language governing permissions and 1493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * limitations under the License. 1593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 1693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpackage com.android.bitmap.util; 1893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.Log; 2093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 2193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.io.IOException; 2293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.io.InputStream; 2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.util.Arrays; 2493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 2593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/** 2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Wrapper for {@link InputStream} that allows you to read bytes from it like a byte[]. An 2793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * internal buffer is kept as small as possible to avoid large unnecessary allocations. 2893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 3093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Care must be taken so that the internal buffer is kept small. The best practice is to 3193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * precalculate the maximum buffer size that you will need. For example, 3293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * say you have a loop that reads bytes from index <code>0</code> to <code>10</code>, 3393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * skips to index <code>N</code>, reads from index <code>N</code> to <code>N+10</code>, etc. Then 3493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * you know that the internal buffer can have a maximum size of <code>10</code>, 3593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * and you should set the <code>bufferSize</code> parameter to <code>10</code> in the constructor. 3693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 3793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Use {@link #advanceTo(int)} to declare that you will not need to access lesser indexes. This 3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * helps to keep the internal buffer small. In the above example, after reading bytes from index 4093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <code>0</code> to <code>10</code>, you should call <code>advanceTo(N)</code> so that internal 4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * buffer becomes filled with bytes from index <code>N</code> to <code>N+10</code>. 4293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 4493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * If you know that you are reading bytes from a <strong>strictly</strong> increasing or equal 4593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * index, then you should set the <code>autoAdvance</code> parameter to <code>true</code> in the 4693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * constructor. For complicated access patterns, or when you prefer to control the internal 4793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * buffer yourself, set <code>autoAdvance</code> to <code>false</code>. When 4893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <code>autoAdvance</code> is enabled, every time an index is beyond the buffer length, 4993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * the buffer will be shifted forward such that the index requested becomes the first element in 5093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * the buffer. 5193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 5293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 5393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * All public methods with parameter <code>index</code> are absolute indexed. The index is from 5493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * the beginning of the wrapped input stream. 5593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 5693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpublic class InputStreamBuffer { 5793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 5893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static final boolean DEBUG = false; 5993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static final int DEBUG_MAX_BUFFER_SIZE = 80; 6093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static final String TAG = InputStreamBuffer.class.getSimpleName(); 6193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 6293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private InputStream mInputStream; 6393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private byte[] mBuffer; 6493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private boolean mAutoAdvance; 6593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** Byte count the buffer is offset by. */ 6693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private int mOffset = 0; 6793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** Number of bytes filled in the buffer. */ 6893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private int mFilled = 0; 6993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 7093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 7193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Construct a new wrapper for an InputStream. 7293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 7393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 7493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * If <code>autoAdvance</code> is true, behavior is undefined if you call {@link #get(int)} 7593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * or {@link #has(int)} with an index N, then some arbitrary time later call {@link #get(int)} 7693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * or {@link #has(int)} with an index M < N. The wrapper may return the right value, 7793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * if the buffer happens to still contain index M, but more likely it will throw an 7893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * {@link IllegalStateException}. 7993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 8093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 8193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * If <code>autoAdvance</code> is false, you must be diligent and call {@link #advanceTo(int)} 8293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * at the appropriate times to ensure that the internal buffer is not unnecessarily resized 8393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * and reallocated. 8493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 8593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @param inputStream The input stream to wrap. The input stream will not be closed by the 8693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * wrapper. 8793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @param bufferSize The initial size for the internal buffer. The buffer size should be 8893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * carefully chosen to avoid resizing and reallocating the internal buffer. 8993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * The internal buffer size used will be the least power of two greater 9093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * than this parameter. 9193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @param autoAdvance Determines the behavior when you need to read an index that is beyond 9293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * the internal buffer size. If true, the internal buffer will shift so 9393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * that the requested index becomes the first element. If false, 9493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * the internal buffer size will grow to the smallest power of 2 which is 9593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * greater than the requested index. 9693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 9793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public InputStreamBuffer(final InputStream inputStream, int bufferSize, 9893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final boolean autoAdvance) { 9993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mInputStream = inputStream; 10093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (bufferSize <= 0) { 10193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein throw new IllegalArgumentException( 10293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein String.format("Buffer size %d must be positive.", bufferSize)); 10393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 10493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein bufferSize = leastPowerOf2(bufferSize); 10593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mBuffer = new byte[bufferSize]; 10693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mAutoAdvance = autoAdvance; 10793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 10893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 10993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 11093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Attempt to get byte at the requested index from the wrapped input stream. If the internal 11193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * buffer contains the requested index, return immediately. If the index is less than the 11293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * head of the buffer, or the index is greater or equal to the size of the wrapped input stream, 11393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * a runtime exception is thrown. 11493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 11593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 11693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * If the index is not in the internal buffer, but it can be requested from the input stream, 11793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * {@link #fill(int)} will be called first, and the byte at the index returned. 11893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 11993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 12093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * You should always call {@link #has(int)} with the same index, unless you are sure that no 12193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * exceptions will be thrown as described above. 12293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 12393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 12493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Consider calling {@link #advanceTo(int)} if you know that you will never request a lesser 12593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * index in the future. 12693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @param index The requested index. 12793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @return The byte at that index. 12893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 12993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public byte get(final int index) throws IllegalStateException, IndexOutOfBoundsException { 13093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("get"); 13193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (has(index)) { 13293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int i = index - mOffset; 13393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 13493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return mBuffer[i]; 13593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 13693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 13793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein throw new IndexOutOfBoundsException( 13893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein String.format("Index %d beyond length.", index)); 13993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 14093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 14193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 14293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 14393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Attempt to return whether the requested index is within the size of the wrapped input 14493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * stream. One side effect is {@link #fill(int)} will be called. 14593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 14693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 14793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * If this method returns true, it is guaranteed that {@link #get(int)} with the same index 14893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * will not fail. That means that if the requested index is within the size of the wrapped 14993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * input stream, but the index is less than the head of the internal buffer, 15093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * a runtime exception is thrown. 15193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 15293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 15393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * See {@link #get(int)} for caveats. A lot of the same warnings about exceptions and 15493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <code>advanceTo()</code> apply. 15593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @param index The requested index. 15693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @return True if requested index is within the size of the wrapped input stream. False if 15793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * the index is beyond the size. 15893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 15993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public boolean has(final int index) throws IllegalStateException, IndexOutOfBoundsException { 16093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("has"); 16193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (index < mOffset) { 16293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 16393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein throw new IllegalStateException( 16493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein String.format("Index %d is before buffer %d", index, mOffset)); 16593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 16693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 16793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int i = index - mOffset; 16893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 16993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Requested index not in internal buffer. 17093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (i >= mFilled || i >= mBuffer.length) { 17193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 17293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return fill(index); 17393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 17493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 17593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 17693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return true; 17793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 17893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 17993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 18093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Attempts to advance the head of the buffer to the requested index. If the index is less 18193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * than the head of the buffer, the internal state will not be changed. 18293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 18393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 18493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Advancing does not fill the internal buffer. The next {@link #get(int)} or 18593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * {@link #has(int)} call will fill the buffer. 18693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 18793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void advanceTo(final int index) throws IllegalStateException, IndexOutOfBoundsException { 18893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("advance to"); 18993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int i = index - mOffset; 19093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (i <= 0) { 19193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // noop 19293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 19393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return; 19493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else if (i < mFilled) { 19593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Shift elements starting at i to position 0. 19693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein shiftToBeginning(i); 19793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOffset = index; 19893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mFilled = mFilled - i; 19993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else if (mInputStream != null) { 20093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Burn some bytes from the input stream to match the new index. 20193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int burn = i - mFilled; 20293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein boolean empty = false; 20393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int fails = 0; 20493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein try { 20593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein while (burn > 0) { 20693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final long burned = mInputStream.skip(burn); 20793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (burned <= 0) { 20893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein fails++; 20993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 21093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein burn -= burned; 21193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 21293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 21393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (fails >= 5) { 21493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein empty = true; 21593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein break; 21693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 21793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 21893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (IOException ignored) { 21993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein empty = true; 22093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 22193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 22293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (empty) { 22393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein //Mark input stream as consumed. 22493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mInputStream = null; 22593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 22693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 22793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOffset = index - burn; 22893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mFilled = 0; 22993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 23093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Advancing beyond the input stream. 23193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mOffset = index; 23293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mFilled = 0; 23393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 23493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 23593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (Log.isLoggable(TAG, Log.DEBUG)) { 23693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.d(TAG, String.format("advanceTo %d buffer: %s", i, this)); 23793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 23893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 23993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 24093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 24193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 24293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Attempt to fill the internal buffer fully. The buffer will be modified such that the 24393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * requested index will always be in the buffer. If the index is less 24493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * than the head of the buffer, a runtime exception is thrown. 24593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 24693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 24793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * If the requested index is already in bounds of the buffer, then the buffer will just be 24893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * filled. 24993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 25093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p/> 25193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Otherwise, if <code>autoAdvance</code> was set to true in the constructor, 25293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * {@link #advanceTo(int)} will be called with the requested index, 25393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * and then the buffer filled. If <code>autoAdvance</code> was set to false, 25493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * we allocate a single larger buffer of a least multiple-of-two size that can contain the 25593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * requested index. The elements in the old buffer are copied over to the head of the new 25693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * buffer. Then the entire buffer is filled. 25793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @param index The requested index. 25893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @return True if the byte at the requested index has been filled. False if the wrapped 25993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * input stream ends before we reach the index. 26093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 26193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private boolean fill(final int index) { 26293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("fill"); 26393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (index < mOffset) { 26493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 26593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein throw new IllegalStateException( 26693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein String.format("Index %d is before buffer %d", index, mOffset)); 26793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 26893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 26993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int i = index - mOffset; 27093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Can't fill buffer anymore if input stream is consumed. 27193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mInputStream == null) { 27293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 27393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return false; 27493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 27593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 27693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Increase buffer size if necessary. 27793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int length = i + 1; 27893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (length > mBuffer.length) { 27993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mAutoAdvance) { 28093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein advanceTo(index); 28193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein i = index - mOffset; 28293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 28393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein length = leastPowerOf2(length); 28493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.w(TAG, String.format( 28593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein "Increasing buffer length from %d to %d. Bad buffer size chosen, " 28693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein + "or advanceTo() not called.", 28793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mBuffer.length, length)); 28893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mBuffer = Arrays.copyOf(mBuffer, length); 28993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 29093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 29193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 29293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Read from input stream to fill buffer. 29393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int read = -1; 29493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein try { 29593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein read = mInputStream.read(mBuffer, mFilled, mBuffer.length - mFilled); 29693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (IOException ignored) { 29793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 29893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 29993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (read != -1) { 30093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mFilled = mFilled + read; 30193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 30293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Mark input stream as consumed. 30393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mInputStream = null; 30493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 30593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 30693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (Log.isLoggable(TAG, Log.DEBUG)) { 30793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.d(TAG, String.format("fill %d buffer: %s", i, this)); 30893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 30993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 31093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 31193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return i < mFilled; 31293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 31393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 31493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 31593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Modify the internal buffer so that all the bytes are shifted towards the head by 31693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <code>i</code>. In other words, the byte at index <code>i</code> will now be at index 31793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <code>0</code>. Bytes from a lesser index are tossed. 31893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @param i How much to shift left. 31993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 32093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private void shiftToBeginning(final int i) { 32193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (i >= mBuffer.length) { 32293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein throw new IndexOutOfBoundsException( 32393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein String.format("Index %d out of bounds. Length %d", i, mBuffer.length)); 32493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 32593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein for (int j = 0; j + i < mFilled; j++) { 32693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mBuffer[j] = mBuffer[j + i]; 32793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 32893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 32993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 33093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 33193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public String toString() { 33293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 33393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return toDebugString(); 33493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 33593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return String.format("+%d+%d [%d]", mOffset, mBuffer.length, mFilled); 33693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 33793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 33893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public String toDebugString() { 33993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("to debug string"); 34093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final StringBuilder sb = new StringBuilder(); 34193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein sb.append("+").append(mOffset); 34293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein sb.append("+").append(mBuffer.length); 34393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein sb.append(" ["); 34493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein for (int i = 0; i < mBuffer.length && i < DEBUG_MAX_BUFFER_SIZE; i++) { 34593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (i > 0) { 34693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein sb.append(","); 34793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 34893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (i < mFilled) { 34993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein sb.append(String.format("%02X", mBuffer[i])); 35093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 35193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein sb.append("__"); 35293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 35393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 35493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mInputStream != null) { 35593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein sb.append("..."); 35693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 35793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein sb.append("]"); 35893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 35993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 36093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return sb.toString(); 36193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 36293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 36393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 36493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Calculate the least power of two greater than or equal to the input. 36593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 36693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static int leastPowerOf2(int n) { 36793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein n--; 36893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein n |= n >> 1; 36993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein n |= n >> 2; 37093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein n |= n >> 4; 37193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein n |= n >> 8; 37293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein n |= n >> 16; 37393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein n++; 37493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return n; 37593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 37693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein}