diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/java/com/android/internal/util/BitwiseInputStream.java | 116 | ||||
-rw-r--r-- | core/java/com/android/internal/util/BitwiseOutputStream.java | 126 |
2 files changed, 242 insertions, 0 deletions
diff --git a/core/java/com/android/internal/util/BitwiseInputStream.java b/core/java/com/android/internal/util/BitwiseInputStream.java new file mode 100644 index 0000000..5da3bc6 --- /dev/null +++ b/core/java/com/android/internal/util/BitwiseInputStream.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +/** + * An object that provides bitwise incremental read access to a byte array. + * + * This is useful, for example, when accessing a series of fields that + * may not be aligned on byte boundaries. + * + * NOTE -- This class is not threadsafe. + */ +public class BitwiseInputStream { + + // The byte array being read from. + private byte[] mBuf; + + // The current position offset, in bits, from the msb in byte 0. + private int mPos; + + // The last valid bit offset. + private int mEnd; + + /** + * An exception to report access problems. + */ + public static class AccessException extends Exception { + public AccessException(String s) { + super("BitwiseInputStream access failed: " + s); + } + } + + /** + * Create object from byte array. + * + * @param buf a byte array containing data + */ + public BitwiseInputStream(byte buf[]) { + mBuf = buf; + mEnd = buf.length * 8; + mPos = 0; + } + + /** + * Return the number of bit still available for reading. + */ + public int available() { + return mEnd - mPos; + } + + /** + * Read some data and increment the current position. + * + * @param bits the amount of data to read (gte 0, lte 8) + * + * @return byte of read data (possibly partially filled, from lsb) + */ + public byte read(int bits) throws AccessException { + int index = mPos / 8; + int offset = 16 - (mPos % 8) - bits; + if ((bits < 0) || (bits > 8) || ((mPos + bits) > mEnd)) { + throw new AccessException("illegal read " + + "(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")"); + } + int data = (mBuf[index] & 0xFF) << 8; + if (offset < 8) data |= (mBuf[index + 1] & 0xFF); + data >>>= offset; + data &= (-1 >>> (32 - bits)); + mPos += bits; + return (byte)data; + } + + /** + * Read data in bulk into a byte array and increment the current position. + * + * @param bits the amount of data to read + * + * @return newly allocated byte array of read data + */ + public byte[] readByteArray(int bits) throws AccessException { + int bytes = (bits / 8) + ((bits % 8) > 0 ? 1 : 0); + byte[] arr = new byte[bytes]; + for (int i = 0; i < bytes; i++) { + int increment = Math.min(8, bits - (i * 8)); + arr[i] = (byte)(read(increment) << (8 - increment)); + } + return arr; + } + + /** + * Increment the current position and ignore contained data. + * + * @param bits the amount by which to increment the position + */ + public void skip(int bits) throws AccessException { + if ((mPos + bits) > mEnd) { + throw new AccessException("illegal skip " + + "(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")"); + } + mPos += bits; + } +} diff --git a/core/java/com/android/internal/util/BitwiseOutputStream.java b/core/java/com/android/internal/util/BitwiseOutputStream.java new file mode 100644 index 0000000..5941bf3 --- /dev/null +++ b/core/java/com/android/internal/util/BitwiseOutputStream.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +/** + * An object that rovides bitwise incremental write access to a byte array. + * + * This is useful, for example, when writing a series of fields that + * may not be aligned on byte boundaries. + * + * NOTE -- This class is not threadsafe. + */ +public class BitwiseOutputStream { + + // The byte array being written to, which will be grown as needed. + private byte[] mBuf; + + // The current position offset, in bits, from the msb in byte 0. + private int mPos; + + // The last bit offset, given the current buf length. + private int mEnd; + + /** + * An exception to report access problems. + */ + public static class AccessException extends Exception { + public AccessException(String s) { + super("BitwiseOutputStream access failed: " + s); + } + } + + /** + * Create object from hint at desired size. + * + * @param startingLength initial internal byte array length in bytes + */ + public BitwiseOutputStream(int startingLength) { + mBuf = new byte[startingLength]; + mEnd = startingLength * 8; + mPos = 0; + } + + /** + * Return byte array containing accumulated data, sized to just fit. + * + * @return newly allocated byte array + */ + public byte[] toByteArray() { + int len = (mPos / 8) + ((mPos % 8) > 0 ? 1 : 0); + byte[] newBuf = new byte[len]; + System.arraycopy(mBuf, 0, newBuf, 0, len); + return newBuf; + } + + /** + * Allocate a new internal buffer, if needed. + * + * @param bits additional bits to be accommodated + */ + private void possExpand(int bits) { + if ((mPos + bits) < mEnd) return; + byte[] newBuf = new byte[((mPos + bits) * 2) / 8]; + System.arraycopy(mBuf, 0, newBuf, 0, mEnd / 8); + mBuf = newBuf; + } + + /** + * Write some data and increment the current position. + * + * @param bits the amount of data to write (gte 0, lte 8) + * @param data to write, will be masked to expose only bits param from lsb + */ + public void write(int bits, int data) throws AccessException { + if ((bits < 0) || (bits > 8)) { + throw new AccessException("illegal write (" + bits + " bits)"); + } + possExpand(bits); + data &= (-1 >>> (32 - bits)); + int index = mPos / 8; + int offset = 16 - (mPos % 8) - bits; + data <<= offset; + mPos += bits; + mBuf[index] |= (data >>> 8); + if (offset < 8) mBuf[index + 1] |= (data & 0xFF); + } + + /** + * Write data in bulk from a byte array and increment the current position. + * + * @param bits the amount of data to write + * @param arr the byte array containing data to be written + */ + public void writeByteArray(int bits, byte[] arr) throws AccessException { + for (int i = 0; i < arr.length; i++) { + int increment = Math.min(8, bits - (i * 8)); + if (increment > 0) { + write(increment, (byte)(arr[i] >>> (8 - increment))); + } + } + } + + /** + * Increment the current position, implicitly writing zeros. + * + * @param bits the amount by which to increment the position + */ + public void skip(int bits) { + possExpand(bits); + mPos += bits; + } +} |