1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.util; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 21 /** 22 * An object that provides bitwise incremental read access to a byte array. 23 * 24 * This is useful, for example, when accessing a series of fields that 25 * may not be aligned on byte boundaries. 26 * 27 * NOTE -- This class is not threadsafe. 28 */ 29 public class BitwiseInputStream { 30 31 // The byte array being read from. 32 private byte[] mBuf; 33 34 // The current position offset, in bits, from the msb in byte 0. 35 private int mPos; 36 37 // The last valid bit offset. 38 private int mEnd; 39 40 /** 41 * An exception to report access problems. 42 */ 43 public static class AccessException extends Exception { AccessException(String s)44 public AccessException(String s) { 45 super("BitwiseInputStream access failed: " + s); 46 } 47 } 48 49 /** 50 * Create object from byte array. 51 * 52 * @param buf a byte array containing data 53 */ 54 @UnsupportedAppUsage BitwiseInputStream(byte buf[])55 public BitwiseInputStream(byte buf[]) { 56 mBuf = buf; 57 mEnd = buf.length << 3; 58 mPos = 0; 59 } 60 61 /** 62 * Return the number of bit still available for reading. 63 */ 64 @UnsupportedAppUsage available()65 public int available() { 66 return mEnd - mPos; 67 } 68 69 /** 70 * Read some data and increment the current position. 71 * 72 * The 8-bit limit on access to bitwise streams is intentional to 73 * avoid endianness issues. 74 * 75 * @param bits the amount of data to read (gte 0, lte 8) 76 * @return byte of read data (possibly partially filled, from lsb) 77 */ 78 @UnsupportedAppUsage read(int bits)79 public int read(int bits) throws AccessException { 80 int index = mPos >>> 3; 81 int offset = 16 - (mPos & 0x07) - bits; // &7==%8 82 if ((bits < 0) || (bits > 8) || ((mPos + bits) > mEnd)) { 83 throw new AccessException("illegal read " + 84 "(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")"); 85 } 86 int data = (mBuf[index] & 0xFF) << 8; 87 if (offset < 8) data |= mBuf[index + 1] & 0xFF; 88 data >>>= offset; 89 data &= (-1 >>> (32 - bits)); 90 mPos += bits; 91 return data; 92 } 93 94 /** 95 * Read data in bulk into a byte array and increment the current position. 96 * 97 * @param bits the amount of data to read 98 * @return newly allocated byte array of read data 99 */ 100 @UnsupportedAppUsage readByteArray(int bits)101 public byte[] readByteArray(int bits) throws AccessException { 102 int bytes = (bits >>> 3) + ((bits & 0x07) > 0 ? 1 : 0); // &7==%8 103 byte[] arr = new byte[bytes]; 104 for (int i = 0; i < bytes; i++) { 105 int increment = Math.min(8, bits - (i << 3)); 106 arr[i] = (byte)(read(increment) << (8 - increment)); 107 } 108 return arr; 109 } 110 111 /** 112 * Increment the current position and ignore contained data. 113 * 114 * @param bits the amount by which to increment the position 115 */ 116 @UnsupportedAppUsage skip(int bits)117 public void skip(int bits) throws AccessException { 118 if ((mPos + bits) > mEnd) { 119 throw new AccessException("illegal skip " + 120 "(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")"); 121 } 122 mPos += bits; 123 } 124 } 125