| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.directory.shared.asn1.util; |
| |
| |
| import java.io.Serializable; |
| |
| import org.apache.directory.shared.i18n.I18n; |
| |
| |
| /** |
| * Implement the Bit String primitive type. A BitString is internally stored as |
| * an array of byte. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class BitString implements Serializable |
| { |
| /** The serialVersion UID constant */ |
| private static final long serialVersionUID = 1L; |
| |
| /** A null MutableString */ |
| public static final BitString EMPTY_STRING = new BitString( 1 ); |
| |
| /** The number of unused bits in the last byte */ |
| private int nbUnusedBits; |
| |
| /** The string is stored in a byte array */ |
| private byte[] bytes; |
| |
| /** Actual length of the byte array */ |
| private int nbBytes; |
| |
| /** Actual length of the bit string */ |
| private int nbBits; |
| |
| |
| /** |
| * Creates a BitString with a specific length (length is the number of |
| * bits). |
| * |
| * @param length The BitString length (it's a number of bits) |
| */ |
| public BitString( int length ) |
| { |
| if ( length <= 0 ) |
| { |
| // This is not allowed |
| throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00029_NULL_OR_NEG_LENGTH_NOT_ALLOWED ) ); |
| } |
| |
| nbBits = length; |
| |
| // As we store values in bytes, we must divide the length by 8 |
| nbBytes = ( length / 8 ); |
| |
| if ( ( length % 8 ) != 0 ) |
| { |
| nbBytes += 1; |
| } |
| |
| nbUnusedBits = ( 8 - ( length % 8 ) ) & 0x07; |
| |
| bytes = new byte[nbBytes]; |
| } |
| |
| |
| /** |
| * Creates a BitString from a byte[]. As the first byteis the number of unused bits |
| * in the last byte, we have to ignore it. |
| * |
| * @param bytes The value to store. The first byte contains the number of |
| * unused bits |
| */ |
| public BitString( byte[] bytes ) |
| { |
| if ( ( bytes == null ) || ( bytes.length == 0 ) ) |
| { |
| nbBits = -1; |
| return; |
| } |
| |
| setData( bytes ); |
| } |
| |
| |
| /** |
| * Set a new BitString in the BitString. It will replace the old BitString, |
| * and reset the current length with the new one. |
| * |
| * @param bytes The string to store |
| */ |
| public void setData( byte[] bytes ) |
| { |
| if ( ( bytes == null ) || ( bytes.length == 0 ) ) |
| { |
| nbBits = -1; |
| return; |
| } |
| |
| // The first byte contains the number of unused bits |
| nbUnusedBits = bytes[0] & 0x07; |
| nbBytes = bytes.length - 1; |
| nbBits = ( nbBytes * 8 ) - nbUnusedBits; |
| this.bytes = new byte[nbBytes]; |
| |
| // We have to transfer the data |
| for ( int i = 0; i < nbBytes; i++ ) |
| { |
| this.bytes[i] = bytes[i + 1]; |
| } |
| } |
| |
| |
| /** |
| * Get the representation of a BitString. A first byte containing the number |
| * of unused bits is added |
| * |
| * @return A byte array which represent the BitString |
| */ |
| public byte[] getData() |
| { |
| byte[] copy = new byte[bytes.length + 1]; |
| |
| System.arraycopy( bytes, 0, copy, 1, bytes.length ); |
| copy[0] = (byte)nbUnusedBits; |
| |
| return copy; |
| } |
| |
| |
| /** |
| * Get the number of unused bits |
| * |
| * @return A byte which represent the number of unused bits |
| */ |
| public byte getUnusedBits() |
| { |
| return ( byte ) nbUnusedBits; |
| } |
| |
| |
| /** |
| * Set a bit at a specified position. |
| * The bits are stored from left to right. |
| * 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 |
| * |
| * @param pos The bit to set |
| */ |
| public void setBit( int pos ) |
| { |
| if ( ( pos < 0 ) || ( pos > nbBits ) ) |
| { |
| throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00030_BIT_NUMBER_OUT_OF_BOUND ) ); |
| } |
| |
| int posBytes = pos>>>3; |
| int bitNumber = 7 - pos % 8; |
| byte mask = (byte)( 1 << bitNumber ); |
| |
| bytes[posBytes] |= mask; |
| } |
| |
| |
| /** |
| * Clear a bit at a specified position. |
| * The bits are stored from left to right. |
| * 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 |
| * |
| * @param pos The bit to clear |
| */ |
| public void clearBit( int pos ) |
| { |
| if ( ( pos < 0 ) || ( pos > nbBits ) ) |
| { |
| throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00030_BIT_NUMBER_OUT_OF_BOUND ) ); |
| } |
| |
| int posBytes = pos>>>3; |
| int bitNumber = 7 - pos % 8; |
| byte mask = (byte)( 1 << bitNumber ); |
| |
| bytes[posBytes] &= ~mask; |
| } |
| |
| |
| /** |
| * Get the bit stored into the BitString at a specific position. |
| * The bits are stored from left to right, the LSB on the left and the |
| * MSB on the right.<br/> |
| * 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 |
| * <pre> |
| * With '1001 000x', where x is an unused bit, |
| * ^ ^ ^ |
| * | | | |
| * | | | |
| * | | +----- getBit(6) = 0 |
| * | +---------- getBit(2) = 0 |
| * +------------ getBit(0) = 1 |
| * </pre> |
| * @param pos The position of the requested bit. |
| * |
| * @return <code>true</code> if the bit is set, <code>false</code> otherwise |
| */ |
| public boolean getBit( int pos ) |
| { |
| if ( pos > nbBits ) |
| { |
| throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00031_CANNOT_FIND_BIT, pos, nbBits ) ); |
| } |
| |
| int posBytes = pos>>>3; |
| int bitNumber = 7 - pos % 8; |
| byte mask = (byte)( 1 << bitNumber ); |
| |
| int res = bytes[posBytes] & mask; |
| |
| return res != 0; |
| } |
| |
| |
| /** |
| * @return The number of bits stored in this BitString |
| */ |
| public int size() |
| { |
| return nbBits; |
| } |
| |
| |
| /** |
| * Return a native String representation of the BitString. |
| * |
| * @return A String representing the BitString |
| */ |
| @Override |
| public String toString() |
| { |
| StringBuilder sb = new StringBuilder(); |
| |
| for ( int i = 0; i < nbBits; i++ ) |
| { |
| if ( getBit( i ) ) |
| { |
| sb.append( '1' ); |
| } |
| else |
| { |
| sb.append( '0' ); |
| } |
| } |
| |
| return sb.toString(); |
| } |
| } |