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     */
020    package org.apache.directory.shared.asn1.primitives;
021    
022    
023    import java.io.Serializable;
024    
025    
026    /**
027     * Implement the Bit String primitive type. A BitString is internally stored as
028     * an array of int.
029     * 
030     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
031     * @version $Rev: 664290 $, $Date: 2008-06-07 08:28:06 +0200 (Sam, 07 jui 2008) $
032     */
033    public class BitString implements Serializable
034    {
035        private static final long serialVersionUID = 1L;
036    
037        // ~ Static fields/initializers
038        // -----------------------------------------------------------------
039    
040        /** A null MutableString */
041        public static final BitString EMPTY_STRING = new BitString( 1 );
042    
043        /**
044         * A flag to mark the OctetString as Streamed (for OctetString larger than
045         * 1024 chars)
046         */
047        // TODO implement the streaming...
048        public static final boolean STREAMED = true;
049    
050        /** The default length of a BitString */
051        private static final int DEFAULT_LENGTH = 1024;
052    
053        // ~ Instance fields
054        // ----------------------------------------------------------------------------
055    
056        /** The number of unused ints */
057        private int nbUnusedBits;
058    
059        /** Tells if the OctetString is streamed or not */
060        private boolean isStreamed;
061    
062        /** The string is stored in a byte array */
063        private byte[] bytes;
064    
065        /** Actual length of the byte array */
066        private int nbBytes;
067    
068        /** Actual length of the bit string */
069        private int nbBits;
070    
071    
072        // ~ Constructors
073        // -------------------------------------------------------------------------------*
074        /**
075         * Creates a BitString with a specific length (length is the number of
076         * bits).
077         * 
078         * @param length The BitString length (it's a number of bits)
079         */
080        public BitString( int length ) 
081        {
082            if ( length <= 0 )
083            {
084                // This is not allowed
085                throw new IndexOutOfBoundsException( "Null or negative length are not allowed" );
086            }
087            
088            nbBits = length;
089    
090            // As we store values in bytes, we must divide the length by 8
091            nbBytes = ( length / 8 ) + ( ( ( length % 8 ) != 0 ) ? 1 : 0 );
092    
093            nbUnusedBits = ( 8 - length % 8 ) % 8;
094    
095            if ( nbBytes > DEFAULT_LENGTH )
096            {
097    
098                // TODO : implement the streaming
099                isStreamed = true;
100                bytes = new byte[nbBytes];
101            }
102            else
103            {
104                isStreamed = false;
105                bytes = new byte[nbBytes];
106            }
107        }
108    
109    
110        /**
111         * Creates a streamed BitString with a specific length. Actually, it's just
112         * a simple BitString. TODO Implement streaming.
113         * 
114         * @param length
115         *            The BitString length, in number of bits
116         * @param isStreamed
117         *            Tells if the BitString must be streamed or not
118         */
119        public BitString( int length, boolean isStreamed )
120        {
121            if ( length <= 0 )
122            {
123                // This is not allowed
124                throw new IndexOutOfBoundsException( "Null or negative length are not allowed" );
125            }
126            
127            nbBits = length;
128            this.isStreamed = isStreamed;
129            nbBytes = ( length / 8 ) + ( ( ( length % 8 ) != 0 ) ? 1 : 0 );
130    
131            nbUnusedBits = length % 8;
132    
133            if ( isStreamed )
134            {
135    
136                // TODO : implement the streaming
137                bytes = new byte[nbBytes];
138            }
139            else
140            {
141                bytes = new byte[nbBytes];
142            }
143        }
144    
145    
146        /**
147         * Creates a BitString with a value.
148         * 
149         * @param bytes The value to store. The first byte contains the number of
150         * unused bits
151         */
152        public BitString( byte[] bytes )
153        {
154            nbBytes = bytes.length - 1;
155    
156            if ( nbBytes > DEFAULT_LENGTH )
157            {
158                isStreamed = true;
159    
160                // It will be a streamed OctetString.
161                // TODO : implement the streaming
162                this.bytes = new byte[nbBytes];
163            }
164            else
165            {
166                isStreamed = false;
167    
168                this.bytes = new byte[nbBytes];
169            }
170    
171            setBytes( bytes, nbBytes );
172        }
173    
174    
175        // ~ Methods
176        // ------------------------------------------------------------------------------------
177    
178        /**
179         * Set the value into the bytes.
180         * 
181         * @param bytes The bytes to copy
182         * @param nbBytes Number of bytes to copy
183         */
184        private void setBytes( byte[] bytes, int nbBytes )
185        {
186    
187            // The first byte contains the number of unused ints
188            nbUnusedBits = bytes[0] & 0x07;
189            nbBits = ( nbBytes * 8 ) - nbUnusedBits;
190    
191            // We have to transfer the data from bytes to ints
192            for ( int i = 0; i < nbBytes; i++ )
193            {
194                this.bytes[i] = bytes[i + 1];
195            }
196        }
197    
198    
199        /**
200         * Set a new BitString in the BitString. It will replace the old BitString,
201         * and reset the current length with the new one.
202         * 
203         * @param bytes The string to store
204         */
205        public void setData( byte[] bytes )
206        {
207    
208            if ( ( bytes == null ) || ( bytes.length == 0 ) )
209            {
210                nbBits = -1;
211                return;
212            }
213    
214            int nbb = bytes.length - 1;
215    
216            if ( ( nbb > DEFAULT_LENGTH ) && ( bytes.length < nbb ) )
217            {
218    
219                // The current size is too small.
220                // We have to allocate more space
221                // TODO : implement the streaming
222                bytes = new byte[nbb];
223            }
224    
225            setBytes( bytes, nbb );
226        }
227    
228    
229        /**
230         * Get the representation of a BitString
231         * 
232         * @return A byte array which represent the BitString
233         */
234        public byte[] getData()
235        {
236            return bytes;
237        }
238    
239    
240        /**
241         * Get the number of unused bits
242         * 
243         * @return A byte which represent the number of unused bits
244         */
245        public byte getUnusedBits()
246        {
247            return ( byte ) nbUnusedBits;
248        }
249    
250        /**
251         * Set a bit at a specified position. 
252         * The bits are stored from left to right.
253         * 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
254         * 
255         * @param pos The bit to set
256         */
257        public void setBit( int pos )
258        {
259            if ( ( pos < 0 ) || ( pos > nbBits ) )
260            {
261                throw new IndexOutOfBoundsException( "Bad bit number : out of bound" );
262            }
263            
264            int posInt = nbBytes - 1 - ( ( pos + nbUnusedBits ) >> 3 );
265            int bitNumber = ( pos + nbUnusedBits ) % 8;
266    
267            bytes[posInt] |= ( 1 << bitNumber );
268        }
269        
270        /**
271         * Clear a bit at a specified position. 
272         * The bits are stored from left to right.
273         * For instance, if we have 10 bits, then they are coded 
274         * as b0 b1 b2 b3 b4 b5 b6 b7 - b8 b9 x x x x x x
275         * 
276         * @param pos The bit to clear
277         */
278        public void clearBit( int pos )
279        {
280            if ( ( pos < 0 ) || ( pos > nbBits ) )
281            {
282                throw new IndexOutOfBoundsException( "Bad bit number : out of bound" );
283            }
284            
285            int posInt = nbBytes - 1 - ( ( pos + nbUnusedBits ) >> 3 );
286            int bitNumber = ( pos + nbUnusedBits ) % 8;
287    
288            bytes[posInt] &= ~( 1 << bitNumber );
289        }
290        
291        /**
292         * Get the bit stored into the BitString at a specific position. 
293         * The bits are stored from left to right, the LSB on the right and the
294         * MSB on the left
295         * For instance, if we have 10 bits, then they are coded as 
296         * b9 b8 b7 b6 - b5 b4 b3 b2 - b1 b0 x x - x x x x
297         * 
298         * With '1001 000x', where x is an unused bit, 
299         *       ^ ^    ^ 
300         *       | |    | 
301         *       | |    |  
302         *       | |    +----- getBit(0) = 0 
303         *       | +---------- getBit(4) = 0 
304         *       +------------ getBit(6) = 1
305         *       
306         * @param pos The position of the requested bit.  
307         * 
308         * @return <code>true</code> if the bit is set, <code>false</code>
309         *         otherwise
310         */
311        public boolean getBit( int pos )
312        {
313    
314            if ( pos > nbBits )
315            {
316                throw new IndexOutOfBoundsException( "Cannot get a bit at position " + pos + " when the BitString contains only "
317                    + nbBits + " ints" );
318            }
319    
320            int posInt = nbBytes - 1 - ( ( pos + nbUnusedBits ) >> 3 );
321            int bitNumber = ( pos + nbUnusedBits ) % 8;
322    
323            int res = bytes[posInt] & ( 1 << bitNumber );
324            return res != 0;
325        }
326        
327        /**
328         * @return The number of bytes used to encode this BitString
329         */
330        public int size()
331        {
332            return nbBytes;
333        }
334    
335    
336        /**
337         * Return a native String representation of the BitString.
338         * 
339         * @return A String representing the BitString
340         */
341        public String toString()
342        {
343    
344            StringBuffer sb = new StringBuffer();
345    
346            for ( int i = nbBits; i > 0; i-- )
347            {
348    
349                if ( getBit( i ) )
350                {
351                    sb.append( '1' );
352                }
353                else
354                {
355                    sb.append( '0' );
356                }
357            }
358    
359            return sb.toString();
360        }
361    
362    
363        /**
364         * Tells if the OctetString is streamed or not
365         * 
366         * @return <code>true</code> if the OctetString is streamed.
367         */
368        public boolean isStreamed()
369        {
370            return isStreamed;
371        }
372    }