1c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei/* 2c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Copyright (C) 2013 The Android Open Source Project 3c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 4c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Licensed under the Apache License, Version 2.0 (the "License"); 5c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * you may not use this file except in compliance with the License. 6c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * You may obtain a copy of the License at 7c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 8c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * http://www.apache.org/licenses/LICENSE-2.0 9c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 10c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Unless required by applicable law or agreed to in writing, software 11c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * distributed under the License is distributed on an "AS IS" BASIS, 12c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * See the License for the specific language governing permissions and 14c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * limitations under the License. 15c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei */ 16c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 17c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Weipackage com.android.ex.photo.util; 18c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 19c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Weiimport android.util.Log; 20c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 21c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Weiimport java.io.IOException; 22c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Weiimport java.io.InputStream; 23c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Weiimport java.util.Arrays; 24c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 25c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei/** 26c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Wrapper for {@link InputStream} that allows you to read bytes from it like a byte[]. An 27c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * internal buffer is kept as small as possible to avoid large unnecessary allocations. 28c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 29c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 30c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Care must be taken so that the internal buffer is kept small. The best practice is to 31c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * precalculate the maximum buffer size that you will need. For example, 32c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * say you have a loop that reads bytes from index <code>0</code> to <code>10</code>, 33c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * skips to index <code>N</code>, reads from index <code>N</code> to <code>N+10</code>, etc. Then 34c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * you know that the internal buffer can have a maximum size of <code>10</code>, 35c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * and you should set the <code>bufferSize</code> parameter to <code>10</code> in the constructor. 36c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 37c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 38c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Use {@link #advanceTo(int)} to declare that you will not need to access lesser indexes. This 39c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * helps to keep the internal buffer small. In the above example, after reading bytes from index 40c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <code>0</code> to <code>10</code>, you should call <code>advanceTo(N)</code> so that internal 41c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * buffer becomes filled with bytes from index <code>N</code> to <code>N+10</code>. 42c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 43c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 44c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * If you know that you are reading bytes from a <strong>strictly</strong> increasing or equal 45c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * index, then you should set the <code>autoAdvance</code> parameter to <code>true</code> in the 46c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * constructor. For complicated access patterns, or when you prefer to control the internal 47c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * buffer yourself, set <code>autoAdvance</code> to <code>false</code>. When 48c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <code>autoAdvance</code> is enabled, every time an index is beyond the buffer length, 49c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * the buffer will be shifted forward such that the index requested becomes the first element in 50c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * the buffer. 51c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 52c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 53c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * All public methods with parameter <code>index</code> are absolute indexed. The index is from 54c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * the beginning of the wrapped input stream. 55c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei */ 56c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Weipublic class InputStreamBuffer { 57c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 58c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private static final boolean DEBUG = false; 59c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private static final int DEBUG_MAX_BUFFER_SIZE = 80; 60c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private static final String TAG = "InputStreamBuffer"; 61c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 62c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private InputStream mInputStream; 63c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private byte[] mBuffer; 64c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private boolean mAutoAdvance; 65c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei /** Byte count the buffer is offset by. */ 66c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private int mOffset = 0; 67c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei /** Number of bytes filled in the buffer. */ 68c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private int mFilled = 0; 69c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 70c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei /** 71c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Construct a new wrapper for an InputStream. 72c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 73c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 74c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * If <code>autoAdvance</code> is true, behavior is undefined if you call {@link #get(int)} 75c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * or {@link #has(int)} with an index N, then some arbitrary time later call {@link #get(int)} 76c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * or {@link #has(int)} with an index M < N. The wrapper may return the right value, 77c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * if the buffer happens to still contain index M, but more likely it will throw an 78c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * {@link IllegalStateException}. 79c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 80c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 81c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * If <code>autoAdvance</code> is false, you must be diligent and call {@link #advanceTo(int)} 82c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * at the appropriate times to ensure that the internal buffer is not unnecessarily resized 83c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * and reallocated. 84c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 85c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @param inputStream The input stream to wrap. The input stream will not be closed by the 86c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * wrapper. 87c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @param bufferSize The initial size for the internal buffer. The buffer size should be 88c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * carefully chosen to avoid resizing and reallocating the internal buffer. 89c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * The internal buffer size used will be the least power of two greater 90c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * than this parameter. 91c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @param autoAdvance Determines the behavior when you need to read an index that is beyond 92c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * the internal buffer size. If true, the internal buffer will shift so 93c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * that the requested index becomes the first element. If false, 94c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * the internal buffer size will grow to the smallest power of 2 which is 95c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * greater than the requested index. 96c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei */ 97c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei public InputStreamBuffer(final InputStream inputStream, int bufferSize, 98c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei final boolean autoAdvance) { 99c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mInputStream = inputStream; 100c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (bufferSize <= 0) { 101c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei throw new IllegalArgumentException( 102c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei String.format("Buffer size %d must be positive.", bufferSize)); 103c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 104c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei bufferSize = leastPowerOf2(bufferSize); 105c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mBuffer = new byte[bufferSize]; 106c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mAutoAdvance = autoAdvance; 107c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 108c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 109c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei /** 110c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Attempt to get byte at the requested index from the wrapped input stream. If the internal 111c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * buffer contains the requested index, return immediately. If the index is less than the 112c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * head of the buffer, or the index is greater or equal to the size of the wrapped input stream, 113c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * a runtime exception is thrown. 114c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 115c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 116c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * If the index is not in the internal buffer, but it can be requested from the input stream, 117c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * {@link #fill(int)} will be called first, and the byte at the index returned. 118c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 119c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 120c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * You should always call {@link #has(int)} with the same index, unless you are sure that no 121c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * exceptions will be thrown as described above. 122c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 123c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 124c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Consider calling {@link #advanceTo(int)} if you know that you will never request a lesser 125c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * index in the future. 126c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @param index The requested index. 127c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @return The byte at that index. 128c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei */ 129c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei public byte get(final int index) throws IllegalStateException, IndexOutOfBoundsException { 130c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.beginSection("get"); 131c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (has(index)) { 132c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei final int i = index - mOffset; 133c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 134c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return mBuffer[i]; 135c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } else { 136c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 137c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei throw new IndexOutOfBoundsException( 138c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei String.format("Index %d beyond length.", index)); 139c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 140c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 141c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 142c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei /** 143c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Attempt to return whether the requested index is within the size of the wrapped input 144c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * stream. One side effect is {@link #fill(int)} will be called. 145c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 146c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 147c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * If this method returns true, it is guaranteed that {@link #get(int)} with the same index 148c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * will not fail. That means that if the requested index is within the size of the wrapped 149c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * input stream, but the index is less than the head of the internal buffer, 150c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * a runtime exception is thrown. 151c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 152c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 153c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * See {@link #get(int)} for caveats. A lot of the same warnings about exceptions and 154c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <code>advanceTo()</code> apply. 155c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @param index The requested index. 156c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @return True if requested index is within the size of the wrapped input stream. False if 157c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * the index is beyond the size. 158c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei */ 159c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei public boolean has(final int index) throws IllegalStateException, IndexOutOfBoundsException { 160c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.beginSection("has"); 161c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (index < mOffset) { 162c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 163c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei throw new IllegalStateException( 164c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei String.format("Index %d is before buffer %d", index, mOffset)); 165c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 166c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 167c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei final int i = index - mOffset; 168c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 169c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei // Requested index not in internal buffer. 170c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (i >= mFilled || i >= mBuffer.length) { 171c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 172c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return fill(index); 173c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 174c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 175c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 176c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return true; 177c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 178c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 179c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei /** 180c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Attempts to advance the head of the buffer to the requested index. If the index is less 181c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * than the head of the buffer, the internal state will not be changed. 182c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 183c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 184c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Advancing does not fill the internal buffer. The next {@link #get(int)} or 185c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * {@link #has(int)} call will fill the buffer. 186c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei */ 187c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei public void advanceTo(final int index) throws IllegalStateException, IndexOutOfBoundsException { 188c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.beginSection("advance to"); 189c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei final int i = index - mOffset; 190c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (i <= 0) { 191c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei // noop 192c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 193c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return; 194c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } else if (i < mFilled) { 195c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei // Shift elements starting at i to position 0. 196c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei shiftToBeginning(i); 197c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mOffset = index; 198c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mFilled = mFilled - i; 199c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } else if (mInputStream != null) { 200c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei // Burn some bytes from the input stream to match the new index. 201c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei int burn = i - mFilled; 202c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei boolean empty = false; 203c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei int fails = 0; 204c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei try { 205c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei while (burn > 0) { 206c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei final long burned = mInputStream.skip(burn); 207c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (burned <= 0) { 208c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei fails++; 209c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } else { 210c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei burn -= burned; 211c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 212c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 213c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (fails >= 5) { 214c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei empty = true; 215c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei break; 216c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 217c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 218c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } catch (IOException ignored) { 219c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei empty = true; 220c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 221c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 222c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (empty) { 223c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei //Mark input stream as consumed. 224c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mInputStream = null; 225c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 226c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 227c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mOffset = index - burn; 228c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mFilled = 0; 229c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } else { 230c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei // Advancing beyond the input stream. 231c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mOffset = index; 232c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mFilled = 0; 233c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 234c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 235c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Log.d(TAG, String.format("advanceTo %d buffer: %s", i, this)); 236c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 237c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 238c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 239c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei /** 240c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Attempt to fill the internal buffer fully. The buffer will be modified such that the 241c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * requested index will always be in the buffer. If the index is less 242c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * than the head of the buffer, a runtime exception is thrown. 243c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 244c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 245c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * If the requested index is already in bounds of the buffer, then the buffer will just be 246c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * filled. 247c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * 248c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <p/> 249c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Otherwise, if <code>autoAdvance</code> was set to true in the constructor, 250c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * {@link #advanceTo(int)} will be called with the requested index, 251c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * and then the buffer filled. If <code>autoAdvance</code> was set to false, 252c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * we allocate a single larger buffer of a least multiple-of-two size that can contain the 253c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * requested index. The elements in the old buffer are copied over to the head of the new 254c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * buffer. Then the entire buffer is filled. 255c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @param index The requested index. 256c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @return True if the byte at the requested index has been filled. False if the wrapped 257c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * input stream ends before we reach the index. 258c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei */ 259c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private boolean fill(final int index) { 260c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.beginSection("fill"); 261c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (index < mOffset) { 262c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 263c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei throw new IllegalStateException( 264c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei String.format("Index %d is before buffer %d", index, mOffset)); 265c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 266c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 267c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei int i = index - mOffset; 268c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei // Can't fill buffer anymore if input stream is consumed. 269c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (mInputStream == null) { 270c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 271c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return false; 272c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 273c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 274c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei // Increase buffer size if necessary. 275c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei int length = i + 1; 276c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (length > mBuffer.length) { 277c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (mAutoAdvance) { 278c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei advanceTo(index); 279c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei i = index - mOffset; 280c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } else { 281c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei length = leastPowerOf2(length); 282c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Log.w(TAG, String.format( 283c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei "Increasing buffer length from %d to %d. Bad buffer size chosen, " 284c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei + "or advanceTo() not called.", 285c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mBuffer.length, length)); 286c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mBuffer = Arrays.copyOf(mBuffer, length); 287c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 288c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 289c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 290c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei // Read from input stream to fill buffer. 291c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei int read = -1; 292c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei try { 293c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei read = mInputStream.read(mBuffer, mFilled, mBuffer.length - mFilled); 294c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } catch (IOException ignored) { 295c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 296c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 297c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (read != -1) { 298c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mFilled = mFilled + read; 299c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } else { 300c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei // Mark input stream as consumed. 301c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mInputStream = null; 302c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 303c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 304c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Log.d(TAG, String.format("fill %d buffer: %s", i, this)); 305c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 306c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 307c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return i < mFilled; 308c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 309c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 310c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei /** 311c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Modify the internal buffer so that all the bytes are shifted towards the head by 312c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <code>i</code>. In other words, the byte at index <code>i</code> will now be at index 313c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * <code>0</code>. Bytes from a lesser index are tossed. 314c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * @param i How much to shift left. 315c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei */ 316c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private void shiftToBeginning(final int i) { 317c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (i >= mBuffer.length) { 318c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei throw new IndexOutOfBoundsException( 319c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei String.format("Index %d out of bounds. Length %d", i, mBuffer.length)); 320c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 321c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei for (int j = 0; j + i < mFilled; j++) { 322c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei mBuffer[j] = mBuffer[j + i]; 323c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 324c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 325c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 326c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei @Override 327c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei public String toString() { 328c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (DEBUG) { 329c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return toDebugString(); 330c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 331c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return String.format("+%d+%d [%d]", mOffset, mBuffer.length, mFilled); 332c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 333c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 334c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei public String toDebugString() { 335c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.beginSection("to debug string"); 336c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei final StringBuilder sb = new StringBuilder(); 337c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei sb.append("+").append(mOffset); 338c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei sb.append("+").append(mBuffer.length); 339c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei sb.append(" ["); 340c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei for (int i = 0; i < mBuffer.length && i < DEBUG_MAX_BUFFER_SIZE; i++) { 341c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (i > 0) { 342c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei sb.append(","); 343c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 344c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (i < mFilled) { 345c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei sb.append(String.format("%02X", mBuffer[i])); 346c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } else { 347c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei sb.append("__"); 348c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 349c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 350c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei if (mInputStream != null) { 351c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei sb.append("..."); 352c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 353c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei sb.append("]"); 354c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 355c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei Trace.endSection(); 356c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return sb.toString(); 357c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 358c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei 359c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei /** 360c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei * Calculate the least power of two greater than or equal to the input. 361c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei */ 362c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei private static int leastPowerOf2(int n) { 363c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei n--; 364c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei n |= n >> 1; 365c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei n |= n >> 2; 366c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei n |= n >> 4; 367c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei n |= n >> 8; 368c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei n |= n >> 16; 369c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei n++; 370c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei return n; 371c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei } 372c631b5a4b1f19f84a70b772bc879fae7c92fd4a8Mark Wei} 373