BitwiseInputStream.java revision 83917db040bd7498ebca3b74f879dc1c9e223d8e
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
17package com.android.internal.util;
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 */
27public 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 * 8;
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     * @param bits the amount of data to read (gte 0, lte 8)
69     *
70     * @return byte of read data (possibly partially filled, from lsb)
71     */
72    public byte read(int bits) throws AccessException {
73        int index = mPos / 8;
74        int offset = 16 - (mPos % 8) - bits;
75        if ((bits < 0) || (bits > 8) || ((mPos + bits) > mEnd)) {
76            throw new AccessException("illegal read " +
77                "(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")");
78        }
79        int data = (mBuf[index] & 0xFF) << 8;
80        if (offset < 8) data |= (mBuf[index + 1] & 0xFF);
81        data >>>= offset;
82        data &= (-1 >>> (32 - bits));
83        mPos += bits;
84        return (byte)data;
85    }
86
87    /**
88     * Read data in bulk into a byte array and increment the current position.
89     *
90     * @param bits the amount of data to read
91     *
92     * @return newly allocated byte array of read data
93     */
94    public byte[] readByteArray(int bits) throws AccessException {
95        int bytes = (bits / 8) + ((bits % 8) > 0 ? 1 : 0);
96        byte[] arr = new byte[bytes];
97        for (int i = 0; i < bytes; i++) {
98            int increment = Math.min(8, bits - (i * 8));
99            arr[i] = (byte)(read(increment) << (8 - increment));
100        }
101        return arr;
102    }
103
104    /**
105     * Increment the current position and ignore contained data.
106     *
107     * @param bits the amount by which to increment the position
108     */
109    public void skip(int bits) throws AccessException {
110        if ((mPos + bits) > mEnd) {
111            throw new AccessException("illegal skip " +
112                "(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")");
113        }
114        mPos += bits;
115    }
116}
117