Jordan Liu | 9e3c859 | 2019-11-12 13:59:39 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (C) 2019 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.cellbroadcastservice; |
| 18 | |
| 19 | /** |
| 20 | * An object that provides bitwise incremental read access to a byte array. |
| 21 | * |
| 22 | * This is useful, for example, when accessing a series of fields that |
| 23 | * may not be aligned on byte boundaries. |
| 24 | * |
| 25 | * NOTE -- This class is not threadsafe. |
| 26 | */ |
| 27 | public class BitwiseInputStream { |
| 28 | |
| 29 | // The byte array being read from. |
| 30 | private byte[] mBuf; |
| 31 | |
| 32 | // The current position offset, in bits, from the msb in byte 0. |
| 33 | private int mPos; |
| 34 | |
| 35 | // The last valid bit offset. |
| 36 | private int mEnd; |
| 37 | |
| 38 | /** |
| 39 | * An exception to report access problems. |
| 40 | */ |
| 41 | public static class AccessException extends Exception { |
| 42 | public AccessException(String s) { |
| 43 | super("BitwiseInputStream access failed: " + s); |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | /** |
| 48 | * Create object from byte array. |
| 49 | * |
| 50 | * @param buf a byte array containing data |
| 51 | */ |
| 52 | public BitwiseInputStream(byte[] buf) { |
| 53 | mBuf = buf; |
| 54 | mEnd = buf.length << 3; |
| 55 | mPos = 0; |
| 56 | } |
| 57 | |
| 58 | /** |
| 59 | * Return the number of bit still available for reading. |
| 60 | */ |
| 61 | public int available() { |
| 62 | return mEnd - mPos; |
| 63 | } |
| 64 | |
| 65 | /** |
| 66 | * Read some data and increment the current position. |
| 67 | * |
| 68 | * The 8-bit limit on access to bitwise streams is intentional to |
| 69 | * avoid endianness issues. |
| 70 | * |
| 71 | * @param bits the amount of data to read (gte 0, lte 8) |
| 72 | * @return byte of read data (possibly partially filled, from lsb) |
| 73 | */ |
| 74 | public int read(int bits) throws AccessException { |
| 75 | int index = mPos >>> 3; |
| 76 | int offset = 16 - (mPos & 0x07) - bits; // &7==%8 |
| 77 | if ((bits < 0) || (bits > 8) || ((mPos + bits) > mEnd)) { |
| 78 | throw new AccessException( |
| 79 | "illegal read (pos " + mPos + ", end " + mEnd + ", bits " + bits + ")"); |
| 80 | } |
| 81 | int data = (mBuf[index] & 0xFF) << 8; |
| 82 | if (offset < 8) data |= mBuf[index + 1] & 0xFF; |
| 83 | data >>>= offset; |
| 84 | data &= (-1 >>> (32 - bits)); |
| 85 | mPos += bits; |
| 86 | return data; |
| 87 | } |
| 88 | |
| 89 | /** |
| 90 | * Read data in bulk into a byte array and increment the current position. |
| 91 | * |
| 92 | * @param bits the amount of data to read |
| 93 | * @return newly allocated byte array of read data |
| 94 | */ |
| 95 | public byte[] readByteArray(int bits) throws AccessException { |
| 96 | int bytes = (bits >>> 3) + ((bits & 0x07) > 0 ? 1 : 0); // &7==%8 |
| 97 | byte[] arr = new byte[bytes]; |
| 98 | for (int i = 0; i < bytes; i++) { |
| 99 | int increment = Math.min(8, bits - (i << 3)); |
| 100 | arr[i] = (byte) (read(increment) << (8 - increment)); |
| 101 | } |
| 102 | return arr; |
| 103 | } |
| 104 | |
| 105 | /** |
| 106 | * Increment the current position and ignore contained data. |
| 107 | * |
| 108 | * @param bits the amount by which to increment the position |
| 109 | */ |
| 110 | public void skip(int bits) throws AccessException { |
| 111 | if ((mPos + bits) > mEnd) { |
| 112 | throw new AccessException( |
| 113 | "illegal skip (pos " + mPos + ", end " + mEnd + ", bits " + bits + ")"); |
| 114 | } |
| 115 | mPos += bits; |
| 116 | } |
| 117 | } |