Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2017 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 android.location.cts.asn1.base;
     18 
     19 import com.google.common.annotations.VisibleForTesting;
     20 import com.google.common.base.Preconditions;
     21 
     22 import java.util.Arrays;
     23 
     24 /**
     25  * Outputs a stream of bits.
     26  *
     27  * <p>This class is not thread-safe.
     28  *
     29  */
     30 public final class BitStream {
     31 
     32   /**
     33    * The number of bytes that is initially allocated and by which the buffer
     34    * gets expanded when necessary.
     35    */
     36   static final int BUFFER_CHUNK = 50;
     37   private static final int BITS_IN_BYTE = 8;
     38 
     39   private byte[] buffer = new byte[BUFFER_CHUNK];
     40   /**
     41    * The position in the buffer of the unfinished byte in progress.
     42    */
     43   private int position = 0;
     44   /**
     45    *   The number of high bits accumulated in the unfinished byte.
     46    */
     47   private int setBits = 0;
     48 
     49   public byte[] getPaddedBytes() {
     50     return Arrays.copyOf(buffer, position + (setBits == 0 ? 0 : 1));
     51   }
     52 
     53   public void appendByte(byte data) {
     54     buffer[position] = (byte) (buffer[position] | (data & 0xFF) >> setBits);
     55     incrementPosition();
     56     buffer[position] = (byte) (buffer[position] | (data << (BITS_IN_BYTE - setBits)) & 0xFF);
     57   }
     58 
     59   private void incrementPosition() {
     60     position++;
     61     if (position >= buffer.length) {
     62       buffer = Arrays.copyOf(buffer, buffer.length + BUFFER_CHUNK);
     63     }
     64   }
     65 
     66   public void appendBit(boolean one) {
     67     if (one) {
     68       buffer[position] = (byte) (buffer[position] | 1 << (BITS_IN_BYTE - 1 - setBits));
     69     }
     70     setBits++;
     71     if (setBits == BITS_IN_BYTE) {
     72       incrementPosition();
     73       setBits = 0;
     74     }
     75   }
     76 
     77   public int getBitCount() {
     78     return BITS_IN_BYTE * position + setBits;
     79   }
     80 
     81   /**
     82    * Appends the lowest {@code howManyBits} from the {@code data} in order from
     83    * most significant to least significant.
     84    */
     85   public void appendLowBits(int howManyBits, byte data) {
     86     Preconditions.checkArgument(howManyBits < BITS_IN_BYTE);
     87     int lowMask = (1 << howManyBits) - 1;
     88     int highMask = ~lowMask;
     89     int maskedData = data;
     90     while (highMask < -1) {
     91       maskedData &= ~highMask;
     92       highMask >>= 1;
     93       appendBit((maskedData & highMask) != 0);
     94     }
     95   }
     96 
     97   private boolean beginByteAligned;
     98 
     99   public boolean beginsByteAligned() {
    100     return beginByteAligned;
    101   }
    102 
    103   public void setBeginByteAligned() {
    104     beginByteAligned = true;
    105   }
    106 
    107   public void spoolToByteBoundary() {
    108     if (setBits != 0) {
    109       setBits = 0;
    110       incrementPosition();
    111     }
    112   }
    113 }
    114