16c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato/*
26c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * Copyright (C) 2012 The Android Open Source Project
36c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato *
46c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * Licensed under the Apache License, Version 2.0 (the "License");
56c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * you may not use this file except in compliance with the License.
66c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * You may obtain a copy of the License at
76c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato *
86c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato *      http://www.apache.org/licenses/LICENSE-2.0
96c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato *
106c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * Unless required by applicable law or agreed to in writing, software
116c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * distributed under the License is distributed on an "AS IS" BASIS,
126c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * See the License for the specific language governing permissions and
146c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * limitations under the License.
156c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato */
166c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
176c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onoratopackage android.util.proto;
186c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
196c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onoratoimport android.annotation.TestApi;
206c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onoratoimport android.util.Log;
216c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
226c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onoratoimport java.util.ArrayList;
236c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
246c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato/**
256c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * A stream of bytes containing a read pointer and a write pointer,
266c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * backed by a set of fixed-size buffers.  There are write functions for the
276c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * primitive types stored by protocol buffers, but none of the logic
286c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * for tags, inner objects, or any of that.
296c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato *
306c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * Terminology:
316c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato *      *Pos:       Position in the whole data set (as if it were a single buffer).
326c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato *      *Index:     Position within a buffer.
336c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato *      *BufIndex:  Index of a buffer within the mBuffers list
346c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato * @hide
356c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato */
366c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato@TestApi
376c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onoratopublic final class EncodedBuffer {
386c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private static final String TAG = "EncodedBuffer";
396c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
406c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private final ArrayList<byte[]> mBuffers = new ArrayList<byte[]>();
416c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
426c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private final int mChunkSize;
436c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
446c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
456c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * The number of buffers in mBuffers. Stored separately to avoid the extra
466c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * function call to size() everywhere for bounds checking.
476c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
486c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private int mBufferCount;
496c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
506c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
516c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * The buffer we are currently writing to.
526c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
536c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private byte[] mWriteBuffer;
546c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
556c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
566c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * The index into mWriteBuffer that we will write to next.
576c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * It may point to the end of the buffer, in which case,
586c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * the NEXT write will allocate a new buffer.
596c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
606c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private int mWriteIndex;
616c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
626c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
636c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * The index of mWriteBuffer in mBuffers.
646c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
656c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private int mWriteBufIndex;
666c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
676c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
686c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * The buffer we are currently reading from.
696c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
706c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private byte[] mReadBuffer;
716c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
726c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
736c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * The index of mReadBuffer in mBuffers.
746c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
756c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private int mReadBufIndex;
766c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
776c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
786c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * The index into mReadBuffer that we will read from next.
796c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * It may point to the end of the buffer, in which case,
806c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * the NEXT read will advance to the next buffer.
816c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
826c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private int mReadIndex;
836c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
846c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
856c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * The amount of data in the last buffer.
866c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
876c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private int mReadLimit = -1;
886c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
896c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
906c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * How much data there is total.
916c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
926c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private int mReadableSize = -1;
936c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
946c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public EncodedBuffer() {
956c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        this(0);
966c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
976c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
986c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
996c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Construct an EncodedBuffer object.
1006c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *
1016c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * @param chunkSize The size of the buffers to use.  If chunkSize &lt;= 0, a default
1026c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *                  size will be used instead.
1036c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
1046c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public EncodedBuffer(int chunkSize) {
1056c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (chunkSize <= 0) {
1066c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            chunkSize = 8 * 1024;
1076c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
1086c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mChunkSize = chunkSize;
1096c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteBuffer = new byte[mChunkSize];
1106c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mBuffers.add(mWriteBuffer);
1116c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mBufferCount = 1;
1126c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
1136c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1146c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
1156c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    // Buffer management.
1166c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
1176c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1186c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
1196c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Rewind the read and write pointers, and record how much data was last written.
1206c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
1216c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void startEditing() {
1226c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mReadableSize = ((mWriteBufIndex) * mChunkSize) + mWriteIndex;
1236c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mReadLimit = mWriteIndex;
1246c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1256c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteBuffer = mBuffers.get(0);
1266c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteIndex = 0;
1276c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteBufIndex = 0;
1286c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1296c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mReadBuffer = mWriteBuffer;
1306c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mReadBufIndex = 0;
1316c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mReadIndex = 0;
1326c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
1336c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1346c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
1356c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Rewind the read pointer. Don't touch the write pointer.
1366c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
1376c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void rewindRead() {
1386c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mReadBuffer = mBuffers.get(0);
1396c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mReadBufIndex = 0;
1406c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mReadIndex = 0;
1416c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
1426c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1436c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
1446c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Only valid after startEditing. Returns -1 before that.
1456c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
1466c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public int getReadableSize() {
1476c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return mReadableSize;
1486c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
1496c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1506c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
1516c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    // Reading from the read position.
1526c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
1536c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1546c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
1556c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Only valid after startEditing.
1566c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
1576c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public int getReadPos() {
1586c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return ((mReadBufIndex) * mChunkSize) + mReadIndex;
1596c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
1606c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1616c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
1626c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Skip over _amount_ bytes.
1636c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
1646c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void skipRead(int amount) {
1656c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (amount < 0) {
1666c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            throw new RuntimeException("skipRead with negative amount=" + amount);
1676c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
1686c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (amount == 0) {
1696c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            return;
1706c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
1716c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (amount <= mChunkSize - mReadIndex) {
1726c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mReadIndex += amount;
1736c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        } else {
1746c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            amount -= mChunkSize - mReadIndex;
1756c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mReadIndex = amount % mChunkSize;
1766c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            if (mReadIndex == 0) {
1776c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                mReadIndex = mChunkSize;
1786c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                mReadBufIndex += (amount / mChunkSize);
1796c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            } else {
1806c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                mReadBufIndex += 1 + (amount / mChunkSize);
1816c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
1826c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mReadBuffer = mBuffers.get(mReadBufIndex);
1836c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
1846c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
1856c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
1866c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
1876c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Read one byte from the stream and advance the read pointer.
1886c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *
1896c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * @throws IndexOutOfBoundsException if the read point is past the end of
1906c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * the buffer or past the read limit previously set by startEditing().
1916c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
1926c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public byte readRawByte() {
1936c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (mReadBufIndex > mBufferCount
1946c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                || (mReadBufIndex == mBufferCount - 1 && mReadIndex >= mReadLimit)) {
1956c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            throw new IndexOutOfBoundsException("Trying to read too much data"
1966c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    + " mReadBufIndex=" + mReadBufIndex + " mBufferCount=" + mBufferCount
1976c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    + " mReadIndex=" + mReadIndex + " mReadLimit=" + mReadLimit);
1986c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
1996c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (mReadIndex >= mChunkSize) {
2006c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mReadBufIndex++;
2016c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mReadBuffer = mBuffers.get(mReadBufIndex);
2026c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mReadIndex = 0;
2036c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
2046c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return mReadBuffer[mReadIndex++];
2056c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
2066c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
2076c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
2086c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Read an unsigned varint. The value will be returend in a java signed long.
2096c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
2106c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public long readRawUnsigned() {
2116c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        int bits = 0;
2126c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        long result = 0;
2136c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        while (true) {
2146c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            final byte b = readRawByte();
2156c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            result |= ((long)(b & 0x7F)) << bits;
2166c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            if ((b & 0x80) == 0) {
2176c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                return result;
2186c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
2196c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            bits += 7;
2206c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            if (bits > 64) {
2216c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                throw new ProtoParseException("Varint too long -- " + getDebugString());
2226c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
2236c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
2246c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
2256c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
2266c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
2276c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Read 32 little endian bits from the stream.
2286c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
2296c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public int readRawFixed32() {
2306c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return (readRawByte() & 0x0ff)
2316c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                | ((readRawByte() & 0x0ff) << 8)
2326c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                | ((readRawByte() & 0x0ff) << 16)
2336c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                | ((readRawByte() & 0x0ff) << 24);
2346c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
2356c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
2366c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
2376c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    // Writing at a the end of the stream.
2386c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
2396c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
2406c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
2416c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Advance to the next write buffer, allocating it if necessary.
2426c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *
2436c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Must be called immediately <b>before</b> the next write, not after a write,
2446c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * so that a dangling empty buffer is not created.  Doing so will interfere
2456c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * with the expectation that mWriteIndex will point past the end of the buffer
2466c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * until the next read happens.
2476c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
2486c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private void nextWriteBuffer() {
2496c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteBufIndex++;
2506c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (mWriteBufIndex >= mBufferCount) {
2516c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mWriteBuffer = new byte[mChunkSize];
2526c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mBuffers.add(mWriteBuffer);
2536c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mBufferCount++;
2546c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        } else {
2556c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mWriteBuffer = mBuffers.get(mWriteBufIndex);
2566c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
2576c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteIndex = 0;
2586c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
2596c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
2606c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
2616c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Write a single byte to the stream.
2626c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
2636c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeRawByte(byte val) {
2646c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (mWriteIndex >= mChunkSize) {
2656c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            nextWriteBuffer();
2666c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
2676c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteBuffer[mWriteIndex++] = val;
2686c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
2696c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
2706c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
2716c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Return how many bytes a 32 bit unsigned varint will take when written to the stream.
2726c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
2736c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public static int getRawVarint32Size(int val) {
2746c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffff << 7)) == 0) return 1;
2756c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffff << 14)) == 0) return 2;
2766c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffff << 21)) == 0) return 3;
2776c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffff << 28)) == 0) return 4;
2786c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return 5;
2796c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
2806c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
2816c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
2826c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Write an unsigned varint to the stream. A signed value would need to take 10 bytes.
2836c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *
2846c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * @param val treated as unsigned.
2856c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
2866c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeRawVarint32(int val) {
2876c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        while (true) {
2886c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            if ((val & ~0x7F) == 0) {
2896c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                writeRawByte((byte)val);
2906c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                return;
2916c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            } else {
2926c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                writeRawByte((byte)((val & 0x7F) | 0x80));
2936c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                val >>>= 7;
2946c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
2956c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
2966c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
2976c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
2986c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
2996c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Return how many bytes a 32 bit signed zig zag value will take when written to the stream.
3006c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3016c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public static int getRawZigZag32Size(int val) {
3026c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return getRawVarint32Size(zigZag32(val));
3036c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
3046c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
3056c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
3066c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *  Write a zig-zag encoded value.
3076c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *
3086c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *  @param val treated as signed
3096c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3106c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeRawZigZag32(int val) {
3116c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawVarint32(zigZag32(val));
3126c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
3136c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
3146c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
3156c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Return how many bytes a 64 bit varint will take when written to the stream.
3166c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3176c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public static int getRawVarint64Size(long val) {
3186c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffffffffffffL << 7)) == 0) return 1;
3196c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffffffffffffL << 14)) == 0) return 2;
3206c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffffffffffffL << 21)) == 0) return 3;
3216c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffffffffffffL << 28)) == 0) return 4;
3226c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffffffffffffL << 35)) == 0) return 5;
3236c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffffffffffffL << 42)) == 0) return 6;
3246c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffffffffffffL << 49)) == 0) return 7;
3256c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffffffffffffL << 56)) == 0) return 8;
3266c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if ((val & (0xffffffffffffffffL << 63)) == 0) return 9;
3276c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return 10;
3286c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
3296c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
3306c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
3316c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Write a 64 bit varint to the stream.
3326c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3336c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeRawVarint64(long val) {
3346c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        while (true) {
3356c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            if ((val & ~0x7FL) == 0) {
3366c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                writeRawByte((byte)val);
3376c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                return;
3386c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            } else {
3396c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                writeRawByte((byte)((val & 0x7F) | 0x80));
3406c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                val >>>= 7;
3416c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
3426c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
3436c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
3446c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
3456c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
3466c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Return how many bytes a signed 64 bit zig zag value will take when written to the stream.
3476c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3486c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public static int getRawZigZag64Size(long val) {
3496c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return getRawVarint64Size(zigZag64(val));
3506c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
3516c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
3526c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
3536c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Write a 64 bit signed zig zag value to the stream.
3546c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3556c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeRawZigZag64(long val) {
3566c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawVarint64(zigZag64(val));
3576c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
3586c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
3596c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
3606c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Write 4 little endian bytes to the stream.
3616c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3626c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeRawFixed32(int val) {
3636c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val));
3646c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 8));
3656c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 16));
3666c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 24));
3676c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
3686c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
3696c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
3706c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Write 8 little endian bytes to the stream.
3716c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3726c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeRawFixed64(long val) {
3736c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val));
3746c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 8));
3756c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 16));
3766c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 24));
3776c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 32));
3786c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 40));
3796c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 48));
3806c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        writeRawByte((byte)(val >> 56));
3816c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
3826c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
3836c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
3846c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Write a buffer to the stream. Writes nothing if val is null or zero-length.
3856c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3866c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeRawBuffer(byte[] val) {
3876c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (val != null && val.length > 0) {
3886c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            writeRawBuffer(val, 0, val.length);
3896c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
3906c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
3916c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
3926c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
3936c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Write part of an array of bytes.
3946c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
3956c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeRawBuffer(byte[] val, int offset, int length) {
3966c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (val == null) {
3976c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            return;
3986c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
3996c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        // Write up to the amount left in the first chunk to write.
4006c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        int amt = length < (mChunkSize - mWriteIndex) ? length : (mChunkSize - mWriteIndex);
4016c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (amt > 0) {
4026c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            System.arraycopy(val, offset, mWriteBuffer, mWriteIndex, amt);
4036c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mWriteIndex += amt;
4046c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            length -= amt;
4056c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            offset += amt;
4066c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
4076c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        while (length > 0) {
4086c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            // We know we're now at the beginning of a chunk
4096c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            nextWriteBuffer();
4106c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            amt = length < mChunkSize ? length : mChunkSize;
4116c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            System.arraycopy(val, offset, mWriteBuffer, mWriteIndex, amt);
4126c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mWriteIndex += amt;
4136c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            length -= amt;
4146c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            offset += amt;
4156c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
4166c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
4176c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
4186c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
4196c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Copies data _size_ bytes of data within this buffer from _srcOffset_
4206c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * to the current write position. Like memmov but handles the chunked buffer.
4216c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
4226c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void writeFromThisBuffer(int srcOffset, int size) {
4236c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (mReadLimit < 0) {
4246c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            throw new IllegalStateException("writeFromThisBuffer before startEditing");
4256c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
4266c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (srcOffset < getWritePos()) {
4276c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            throw new IllegalArgumentException("Can only move forward in the buffer --"
4286c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    + " srcOffset=" + srcOffset + " size=" + size + " " + getDebugString());
4296c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
4306c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (srcOffset + size > mReadableSize) {
4316c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            throw new IllegalArgumentException("Trying to move more data than there is --"
4326c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    + " srcOffset=" + srcOffset + " size=" + size + " " + getDebugString());
4336c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
4346c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (size == 0) {
4356c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            return;
4366c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
4376c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (srcOffset == ((mWriteBufIndex) * mChunkSize) + mWriteIndex /* write pos */) {
4386c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            // Writing to the same location. Just advance the write pointer.  We already
4396c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            // checked that size is in bounds, so we don't need to do any more range
4406c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            // checking.
4416c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            if (size <= mChunkSize - mWriteIndex) {
4426c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                mWriteIndex += size;
4436c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            } else {
4446c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                size -= mChunkSize - mWriteIndex;
4456c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                mWriteIndex = size % mChunkSize;
4466c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                if (mWriteIndex == 0) {
4476c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    // Roll it back so nextWriteBuffer can do its job
4486c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    // on the next call (also makes mBuffers.get() not
4496c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    // fail if we're at the end).
4506c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    mWriteIndex = mChunkSize;
4516c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    mWriteBufIndex += (size / mChunkSize);
4526c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                } else {
4536c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    mWriteBufIndex += 1 + (size / mChunkSize);
4546c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                }
4556c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                mWriteBuffer = mBuffers.get(mWriteBufIndex);
4566c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
4576c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        } else {
4586c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            // Loop through the buffer, copying as much as we can each time.
4596c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            // We already bounds checked so we don't need to do it again here,
4606c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            // and nextWriteBuffer will never allocate.
4616c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            int readBufIndex = srcOffset / mChunkSize;
4626c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            byte[] readBuffer = mBuffers.get(readBufIndex);
4636c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            int readIndex = srcOffset % mChunkSize;
4646c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            while (size > 0) {
4656c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                if (mWriteIndex >= mChunkSize) {
4666c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    nextWriteBuffer();
4676c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                }
4686c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                if (readIndex >= mChunkSize) {
4696c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    readBufIndex++;
4706c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    readBuffer = mBuffers.get(readBufIndex);
4716c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    readIndex = 0;
4726c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                }
4736c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                final int spaceInWriteBuffer = mChunkSize - mWriteIndex;
4746c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                final int availableInReadBuffer = mChunkSize - readIndex;
4756c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                final int amt = Math.min(size, Math.min(spaceInWriteBuffer, availableInReadBuffer));
4766c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                System.arraycopy(readBuffer, readIndex, mWriteBuffer, mWriteIndex, amt);
4776c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                mWriteIndex += amt;
4786c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                readIndex += amt;
4796c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                size -= amt;
4806c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
4816c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
4826c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
4836c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
4846c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
4856c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    // Writing at a particular location.
4866c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
4876c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
4886c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
4896c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Returns the index into the virtual array of the write pointer.
4906c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
4916c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public int getWritePos() {
4926c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return ((mWriteBufIndex) * mChunkSize) + mWriteIndex;
4936c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
4946c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
4956c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
4966c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Resets the write pointer to a virtual location as returned by getWritePos.
4976c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
4986c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void rewindWriteTo(int writePos) {
4996c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (writePos > getWritePos()) {
5006c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            throw new RuntimeException("rewindWriteTo only can go backwards" + writePos);
5016c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
5026c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteBufIndex = writePos / mChunkSize;
5036c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteIndex = writePos % mChunkSize;
5046c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (mWriteIndex == 0 && mWriteBufIndex != 0) {
5056c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            // Roll back so nextWriteBuffer can do its job on the next call
5066c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            // but at the first write we're at 0.
5076c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mWriteIndex = mChunkSize;
5086c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            mWriteBufIndex--;
5096c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
5106c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mWriteBuffer = mBuffers.get(mWriteBufIndex);
5116c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
5126c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5136c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
5146c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Read a 32 bit value from the stream.
5156c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *
5166c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Doesn't touch or affect mWritePos.
5176c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
5186c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public int getRawFixed32At(int pos) {
5196c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return (0x00ff & (int)mBuffers.get(pos / mChunkSize)[pos % mChunkSize])
5206c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                | ((0x0ff & (int)mBuffers.get((pos+1) / mChunkSize)[(pos+1) % mChunkSize]) << 8)
5216c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                | ((0x0ff & (int)mBuffers.get((pos+2) / mChunkSize)[(pos+2) % mChunkSize]) << 16)
5226c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                | ((0x0ff & (int)mBuffers.get((pos+3) / mChunkSize)[(pos+3) % mChunkSize]) << 24);
5236c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
5246c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5256c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
5266c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Overwrite a 32 bit value in the stream.
5276c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     *
5286c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Doesn't touch or affect mWritePos.
5296c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
5306c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void editRawFixed32(int pos, int val) {
5316c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mBuffers.get(pos / mChunkSize)[pos % mChunkSize] = (byte)(val);
5326c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mBuffers.get((pos+1) / mChunkSize)[(pos+1) % mChunkSize] = (byte)(val >> 8);
5336c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mBuffers.get((pos+2) / mChunkSize)[(pos+2) % mChunkSize] = (byte)(val >> 16);
5346c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        mBuffers.get((pos+3) / mChunkSize)[(pos+3) % mChunkSize] = (byte)(val >> 24);
5356c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
5366c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5376c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
5386c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    // Zigging and zagging
5396c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
5406c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5416c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
5426c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Zig-zag encode a 32 bit value.
5436c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
5446c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private static int zigZag32(int val) {
5456c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return (val << 1) ^ (val >> 31);
5466c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
5476c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5486c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
5496c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Zig-zag encode a 64 bit value.
5506c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
5516c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private static long zigZag64(long val) {
5526c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return (val << 1) ^ (val >> 63);
5536c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
5546c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5556c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
5566c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    // Debugging / testing
5576c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    //
5586c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    // VisibleForTesting
5596c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5606c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
5616c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Get a copy of the first _size_ bytes of data. This is not range
5626c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * checked, and if the bounds are outside what has been written you will
5636c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * get garbage and if it is outside the buffers that have been allocated,
5646c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * you will get an exception.
5656c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
5666c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public byte[] getBytes(int size) {
5676c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        final byte[] result = new byte[size];
5686c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5696c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        final int bufCount = size / mChunkSize;
5706c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        int bufIndex;
5716c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        int writeIndex = 0;
5726c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5736c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        for (bufIndex=0; bufIndex<bufCount; bufIndex++) {
5746c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            System.arraycopy(mBuffers.get(bufIndex), 0, result, writeIndex, mChunkSize);
5756c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            writeIndex += mChunkSize;
5766c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
5776c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5786c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        final int lastSize = size - (bufCount * mChunkSize);
5796c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        if (lastSize > 0) {
5806c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            System.arraycopy(mBuffers.get(bufIndex), 0, result, writeIndex, lastSize);
5816c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
5826c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5836c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return result;
5846c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
5856c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5866c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
5876c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Get the number of chunks allocated.
5886c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
5896c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    // VisibleForTesting
5906c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public int getChunkCount() {
5916c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return mBuffers.size();
5926c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
5936c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
5946c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
5956c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Get the write position inside the current write chunk.
5966c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
5976c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     // VisibleForTesting
5986c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public int getWriteIndex() {
5996c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return mWriteIndex;
6006c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
6016c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
6026c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
6036c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Get the index of the current write chunk in the list of chunks.
6046c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
6056c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    // VisibleForTesting
6066c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public int getWriteBufIndex() {
6076c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return mWriteBufIndex;
6086c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
6096c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
6106c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
6116c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Return debugging information about this EncodedBuffer object.
6126c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
6136c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public String getDebugString() {
6146c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return "EncodedBuffer( mChunkSize=" + mChunkSize + " mBuffers.size=" + mBuffers.size()
6156c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                + " mBufferCount=" + mBufferCount + " mWriteIndex=" + mWriteIndex
6166c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                + " mWriteBufIndex=" + mWriteBufIndex + " mReadBufIndex=" + mReadBufIndex
6176c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                + " mReadIndex=" + mReadIndex + " mReadableSize=" + mReadableSize
6186c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                + " mReadLimit=" + mReadLimit + " )";
6196c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
6206c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
6216c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
6226c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Print the internal buffer chunks.
6236c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
6246c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public void dumpBuffers(String tag) {
6256c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        final int N = mBuffers.size();
6266c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        int start = 0;
6276c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        for (int i=0; i<N; i++) {
6286c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            start += dumpByteString(tag, "{" + i + "} ", start, mBuffers.get(i));
6296c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
6306c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
6316c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
6326c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
6336c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Print the internal buffer chunks.
6346c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
6356c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    public static void dumpByteString(String tag, String prefix, byte[] buf) {
6366c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        dumpByteString(tag, prefix, 0, buf);
6376c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
6386c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato
6396c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    /**
6406c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     * Print the internal buffer chunks.
6416c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato     */
6426c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    private static int dumpByteString(String tag, String prefix, int start, byte[] buf) {
6436c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        StringBuffer sb = new StringBuffer();
6446c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        final int length = buf.length;
6456c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        final int lineLen = 16;
6466c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        int i;
6476c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        for (i=0; i<length; i++) {
6486c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            if (i % lineLen == 0) {
6496c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                if (i != 0) {
6506c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    Log.d(tag, sb.toString());
6516c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                    sb = new StringBuffer();
6526c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                }
6536c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append(prefix);
6546c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append('[');
6556c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append(start + i);
6566c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append(']');
6576c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append(' ');
6586c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            } else {
6596c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append(' ');
6606c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
6616c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            byte b = buf[i];
6626c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            byte c = (byte)((b >> 4) & 0x0f);
6636c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            if (c < 10) {
6646c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append((char)('0' + c));
6656c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            } else {
6666c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append((char)('a' - 10 + c));
6676c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
6686c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            byte d = (byte)(b & 0x0f);
6696c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            if (d < 10) {
6706c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append((char)('0' + d));
6716c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            } else {
6726c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato                sb.append((char)('a' - 10 + d));
6736c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato            }
6746c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        }
6756c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        Log.d(tag, sb.toString());
6766c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato        return length;
6776c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato    }
6786c9547d8e1c35d7afa9bc9be11d5ff86ec60db14Joe Onorato}
679