001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.asn1.util; 021 022 023import org.apache.directory.api.i18n.I18n; 024 025 026/** 027 * Implement the Bit String primitive type. A BitString is internally stored as 028 * an array of byte. 029 * 030 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 031 */ 032public class BitString 033{ 034 /** A null MutableString */ 035 public static final BitString EMPTY_STRING = new BitString( 1 ); 036 037 /** The number of unused bits in the last byte */ 038 private int nbUnusedBits; 039 040 /** The string is stored in a byte array */ 041 private byte[] bytes; 042 043 /** Actual length of the byte array */ 044 private int nbBytes; 045 046 /** Actual length of the bit string */ 047 private int nbBits; 048 049 050 /** 051 * Creates a BitString with a specific length (length is the number of 052 * bits). 053 * 054 * @param length The BitString length (it's a number of bits) 055 */ 056 public BitString( int length ) 057 { 058 if ( length <= 0 ) 059 { 060 // This is not allowed 061 throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00029_NULL_OR_NEG_LENGTH_NOT_ALLOWED ) ); 062 } 063 064 nbBits = length; 065 066 // As we store values in bytes, we must divide the length by 8 067 nbBytes = length / 8; 068 069 if ( ( length % 8 ) != 0 ) 070 { 071 nbBytes += 1; 072 } 073 074 nbUnusedBits = ( 8 - ( length % 8 ) ) & 0x07; 075 076 bytes = new byte[nbBytes]; 077 } 078 079 080 /** 081 * Creates a BitString from a byte[]. As the first byte is the number of unused bits 082 * in the last byte, we have to ignore it. 083 * 084 * @param bytes The value to store. The first byte contains the number of 085 * unused bits 086 */ 087 public BitString( byte[] bytes ) 088 { 089 if ( ( bytes == null ) || ( bytes.length == 0 ) ) 090 { 091 nbBits = -1; 092 return; 093 } 094 095 setData( bytes ); 096 } 097 098 099 /** 100 * Set a new BitString in the BitString. It will replace the old BitString, 101 * and reset the current length with the new one. 102 * 103 * @param data The string to store 104 */ 105 public void setData( byte[] data ) 106 { 107 if ( ( data == null ) || ( data.length == 0 ) ) 108 { 109 nbBits = -1; 110 return; 111 } 112 113 // The first byte contains the number of unused bits 114 nbUnusedBits = data[0] & 0x07; 115 nbBytes = data.length - 1; 116 nbBits = ( nbBytes * 8 ) - nbUnusedBits; 117 this.bytes = new byte[nbBytes]; 118 119 // We have to transfer the data 120 for ( int i = 0; i < nbBytes; i++ ) 121 { 122 this.bytes[i] = data[i + 1]; 123 } 124 } 125 126 127 /** 128 * Get the representation of a BitString. A first byte containing the number 129 * of unused bits is added 130 * 131 * @return A byte array which represent the BitString 132 */ 133 public byte[] getData() 134 { 135 byte[] copy = new byte[bytes.length + 1]; 136 137 System.arraycopy( bytes, 0, copy, 1, bytes.length ); 138 copy[0] = ( byte ) nbUnusedBits; 139 140 return copy; 141 } 142 143 144 /** 145 * Get the number of unused bits 146 * 147 * @return A byte which represent the number of unused bits 148 */ 149 public byte getUnusedBits() 150 { 151 return ( byte ) nbUnusedBits; 152 } 153 154 155 /** 156 * Set a bit at a specified position. 157 * The bits are stored from left to right. 158 * For instance, if we have 10 bits, then they are coded as b0 b1 b2 b3 b4 b5 b6 b7 - b8 b9 x x x x x x 159 * 160 * @param pos The bit to set 161 */ 162 public void setBit( int pos ) 163 { 164 if ( ( pos < 0 ) || ( pos > nbBits ) ) 165 { 166 throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00030_BIT_NUMBER_OUT_OF_BOUND ) ); 167 } 168 169 int posBytes = pos >>> 3; 170 int bitNumber = 7 - pos % 8; 171 byte mask = ( byte ) ( 1 << bitNumber ); 172 173 bytes[posBytes] |= mask; 174 } 175 176 177 /** 178 * Clear a bit at a specified position. 179 * The bits are stored from left to right. 180 * For instance, if we have 10 bits, then they are coded 181 * as b0 b1 b2 b3 b4 b5 b6 b7 - b8 b9 x x x x x x 182 * 183 * @param pos The bit to clear 184 */ 185 public void clearBit( int pos ) 186 { 187 if ( ( pos < 0 ) || ( pos > nbBits ) ) 188 { 189 throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00030_BIT_NUMBER_OUT_OF_BOUND ) ); 190 } 191 192 int posBytes = pos >>> 3; 193 int bitNumber = 7 - pos % 8; 194 byte mask = ( byte ) ( 1 << bitNumber ); 195 196 bytes[posBytes] &= ~mask; 197 } 198 199 200 /** 201 * Get the bit stored into the BitString at a specific position. 202 * The bits are stored from left to right, the LSB on the left and the 203 * MSB on the right.<br> 204 * For instance, if we have 10 bits, then they are coded as 205 * b0 b1 b2 b3 - b4 b5 b6 b7 - b8 b9 x x - x x x x 206 * <pre> 207 * With '1001 000x', where x is an unused bit, 208 * ^ ^ ^ 209 * | | | 210 * | | | 211 * | | +----- getBit(6) = 0 212 * | +---------- getBit(2) = 0 213 * +------------ getBit(0) = 1 214 * </pre> 215 * @param pos The position of the requested bit. 216 * 217 * @return <code>true</code> if the bit is set, <code>false</code> otherwise 218 */ 219 public boolean getBit( int pos ) 220 { 221 if ( pos > nbBits ) 222 { 223 throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00031_CANNOT_FIND_BIT, pos, nbBits ) ); 224 } 225 226 int posBytes = pos >>> 3; 227 int bitNumber = 7 - pos % 8; 228 byte mask = ( byte ) ( 1 << bitNumber ); 229 230 int res = bytes[posBytes] & mask; 231 232 return res != 0; 233 } 234 235 236 /** 237 * @return The number of bits stored in this BitString 238 */ 239 public int size() 240 { 241 return nbBits; 242 } 243 244 245 /** 246 * Return a native String representation of the BitString. 247 * 248 * @return A String representing the BitString 249 */ 250 @Override 251 public String toString() 252 { 253 StringBuilder sb = new StringBuilder(); 254 255 for ( int i = 0; i < nbBits; i++ ) 256 { 257 if ( getBit( i ) ) 258 { 259 sb.append( '1' ); 260 } 261 else 262 { 263 sb.append( '0' ); 264 } 265 } 266 267 return sb.toString(); 268 } 269}