# BitField.java

    /*
    ** Module   :BitField.java
    ** Abstract :BitField, a subclass of BitSet which forbids dynamic set growth
    **
    ** Copyright (c) 2005-2017, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
    ** 001 SIY 20050217 ADD  @20015  Created initial implementation
    ** 002 SIY 20050310 CHG  @20354  Organized imports and reordered methods.
    ** 003 SIY 20050323 CHG  @20468  Fixed formatting.
    ** 004 SIY 20050328 CHG  @20574  Fixed missing tags in comments.
    ** 005 SIY 20050421 ADD  @21007  Added parsing for the LDAP bit string values.
    ** 006 SIY 20050515 CHG  @21187  Extended and fixed comments.
    */
    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.directory;

    import java.util.BitSet;

    /**
     * BitField, a subclass of BitSet which forbids dynamic set growth.
     * <p>
     * The main purpose of this class is to provide Java representation of the
     * <code>Bit Field</code> attribute type.
     *
     * @author  SIY
     * @version 1.0
     */
    public class BitField extends BitSet
    {
       /** The "real" width of the bit field. */
       private int width;

       /**
        * Construct a BitField of specified width with all bits set
        * to <code>false</code>.
        *
        * @param   width
        *          Number of bits in field, indexed from <code>0</code> to
        *          <code>width-1</code>.
        * @throws  NegativeArraySizeException if the specified width is negative.
        */
       public BitField(int width)
       {
          super(width);
          this.width = width;
       }

       /**
        * Parse <code>String</code> like 00011000 and create an instance of
        * <code>BitField</code>.
        *
        * @param   str
        *          Source string.
        * @return  New <code>BitField</code> instance or <code>null</code> if
        *          source string does not contain properly formatted bit field.
        */
       public static BitField valueOf(String str)
       {
          if (str == null || str.length() == 0)
             return null;

          str = str.trim();

          if (str.charAt(0) == '\'')
          {
             str = str.substring(1);

             int pos = str.indexOf('\'');

             if (pos > 0)
                str = str.substring(0, pos);
          }

          if (str.length() == 0)
             return null;

          char[] data = str.toCharArray();

          BitField fld = new BitField(data.length);

          for (int i = 0; i < data.length; i++)
          {
             if (data[i] == '1')
                fld.set(data.length - i - 1);
             else
                if (data[i] != '0')
                   return null;
          }

          return fld;
       }

       /**
        * Performs a logical AND of this bit field with the argument bit set.
        *
        * @param   set
        *          A bit set to perform operation with.
        * @throws  IndexOutOfBoundsException
        *          if the specified set is too wide.
        */
       public void and(BitSet set)
       {
          checkBitSet(set);
          super.and(set);
       }

       /**
        * Clears all of the bits whose corresponding bit is set in the specified
        * BitSet.
        *
        * @param   set
        *          A bit set to perform operation with.
        * @throws  IndexOutOfBoundsException
        *          if the specified set is too wide.
        */
       public void andNot(BitSet set)
       {
          checkBitSet(set);
          super.andNot(set);
       }

       /**
        * Set specified bit into <code>false</code>.
        *
        * @param   index
        *          The index of the bit to clear.
        * @throws  IndexOutOfBoundsException if the specified index is negative
        *          or exceeds BitField width.
        */
       public void clear(int index)
       {
          checkIndex(index);
          super.clear(index);
       }

       /**
        * Set specified range of bits into <code>false</code>.
        *
        * @param   from
        *          The index of the first bit in range.
        * @param   to
        *          The index of the last bit in range.
        * @throws  IndexOutOfBoundsException if the specified range does not fit
        *          into BitField width.
        */
       public void clear(int from, int to)
       {
          //Note: there is no need to check low bound of range,
          //remaining checks are done by base class.
          checkIndex(to);
          super.clear(from, to);
       }

       /**
        * Set specified bit into opposite value.
        *
        * @param   index
        *          The index of the bit to change.
        * @throws  IndexOutOfBoundsException if the specified index is negative
        *          or exceeds BitField width.
        */
       public void flip(int index)
       {
          checkIndex(index);
          super.flip(index);
       }

       /**
        * Set specified range of bits into opposite value.
        *
        * @param   from
        *          The index of the first bit in range.
        * @param   to
        *          The index of the last bit in range.
        * @throws  IndexOutOfBoundsException if the specified range does not fit
        *          into BitField width.
        */
       public void flip(int from, int to)
       {
          //Note: there is no need to check low bound of range,
          //remaining checks are done by base class.
          checkIndex(to);
          super.flip(from, to);
       }

       /**
        * Get value of the specified bit.
        *
        * @param   index
        *          The index of the bit to get.
        * @throws  IndexOutOfBoundsException
        *          if the specified index is negative or exceeds BitField width.
        * @return  <code>true</code> if specified bit is set.
        */
       public boolean get(int index)
       {
          checkIndex(index);
          return super.get(index);
       }

       /**
        * Performs a logical OR of this bit field with the argument bit set.
        *
        * @param   set
        *          A bit set to perform operation with.
        * @throws  IndexOutOfBoundsException if the specified set is too wide.
        */
       public void or(BitSet set)
       {
          checkBitSet(set);
          super.or(set);
       }

       /**
        * Set specified bit into <code>true</code>.
        *
        * @param   index
        *          The index of the bit to set.
        * @throws  IndexOutOfBoundsException if the specified index is negative
        *          or exceeds BitField width.
        */
       public void set(int index)
       {
          checkIndex(index);
          super.set(index);
       }

       /**
        * Set specified bit into specified value.
        *
        * @param   index
        *          The index of the bit to set
        * @param   val
        *          New bit value.
        * @throws  IndexOutOfBoundsException if the specified index is negative
        *          or exceeds BitField width.
        */
       public void set(int index, boolean val)
       {
          checkIndex(index);
          super.set(index, val);
       }

       /**
        * Set specified range of bits into <code>true</code>.
        *
        * @param   from
        *          The index of the first bit in range.
        * @param   to
        *          The index of the last bit in range.
        * @throws  IndexOutOfBoundsException if the specified range does not fit
        *          into BitField width.
        */
       public void set(int from, int to)
       {
          checkIndex(to);
          super.set(from, to);
       }

       /**
        * Set specified range of bits into specified value.
        *
        * @param   from
        *          The index of the first bit in range.
        * @param   to
        *          The index of the last bit in range.
        * @param   val
        *          New value for the bits in range.
        * @throws  IndexOutOfBoundsException if the specified range does not fit
        *          into BitField width.
        */
       public void set(int from, int to, boolean val)
       {
          checkIndex(to);
          super.set(from, to, val);
       }

       /**
        * Return a field width as specified in the constructor. Note that this is
        * not the same value as returned by the parent class.
        *
        * @return  Bit field width as it was specified in the constructor.
        */
       public int size()
       {
          return width;
       }

       /**
        * Convert bit field into string representation. The result is a string
        * consisting of '0's and '1's from most significant bit (with highest
        * index) to least significant bit.
        *
        * @return  <code>String</code> on '0's and '1's which represent state of
        *          the bit field.
        */
       public String toString()
       {
          char[] field = new char[size()];

          for (int i = 0; i < field.length; i++)
          {
             field[i] = get(field.length - i - 1) ? '1' : '0';
          }

          return new String(field);
       }

       /**
        * Performs a logical XOR of this bit field with the argument bit set.
        *
        * @param   set
        *          A bit set to perform operation with.
        * @throws  IndexOutOfBoundsException
        *          if the specified set is too wide.
        */
       public void xor(BitSet set)
       {
          checkBitSet(set);
          super.xor(set);
       }

       /**
        * Check specified BitSet is narrow enough to be used for operation.
        *
        * @param   set
        *          BitSet instance to check.
        * @throws  IndexOutOfBoundsException
        *          if specified bit set is too wide.
        */
       private void checkBitSet(BitSet set)
       {
          if (set instanceof BitField)
          {
             if (size() < set.size())
                throw new IndexOutOfBoundsException("Input set is too wide :"
                   + set.size());
          }

          //Comparing with old version of size()
          if (super.size() < set.size())
             throw new IndexOutOfBoundsException("Input set is too wide :"
                + set.size());
       }

       /**
        * Check specified index to fit into range.
        *
        * @param   index
        *          index to check.
        * @throws  IndexOutOfBoundsException
        *          if index does not fit into range.
        */
       private void checkIndex(int index)
       {
          if (index >= size())
             throw new IndexOutOfBoundsException("No such bit in field: " + index);
       }
    }