View Javadoc

1   /*
2    *   Copyright 2005 The Apache Software Foundation
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 org.apache.asn1new.primitives;
18  
19  import java.io.Serializable;
20  
21  import org.apache.asn1.codec.DecoderException;
22  
23  
24  /***
25   * Implement the Bit String primitive type.
26   * 
27   * A BitString is internally stored as an array of int. 
28   * 
29   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
30   */
31  public class BitString implements Serializable
32  {
33      private static final long serialVersionUID = 1L;
34  
35      //~ Static fields/initializers -----------------------------------------------------------------
36  
37      /*** A null MutableString */
38      public static final BitString EMPTY_STRING = new BitString();
39  
40      /*** A flag to mark the OctetString as Streamed (for OctetString larger than 1024 chars) */
41      // TODO implement the streaming...
42      public static final boolean STREAMED = true;
43  
44      /*** The default length of an BitString */
45      private static final int DEFAULT_LENGTH = 8;
46  
47      //~ Instance fields ----------------------------------------------------------------------------
48  
49      /*** The number of unused ints */
50      private int nbUnusedBits;
51  
52      /*** Tells if the OctetString is streamed or not */
53      private boolean isStreamed;
54  
55      /*** The string is stored in a byte array */
56      private byte[] bytes;
57  
58      /*** Actual length of the byte array */
59      private int nbBytes;
60  
61      /*** Actual length of the bit string */
62      private int nbBits;
63  
64      //~ Constructors -------------------------------------------------------------------------------
65  
66      /***
67       * Creates a BitString, with a default length.
68       */
69      public BitString()
70      {
71          bytes        = new byte[DEFAULT_LENGTH];
72          nbBytes      = 0;
73          isStreamed   = false;
74          nbUnusedBits = 0;
75          nbBits       = 0;
76      }
77  
78      /***
79       * Creates a BitString with a specific length (length is the number
80       * of bytes).
81       *
82       * @param length The BitString length (it's a number of bits)
83      */
84      public BitString(  int length )
85      {
86          nbBits = length;
87  
88          // As we store values in bytes, we must divide the length by 8
89          nbBytes      = ( length / 8 ) + ( ( ( length % 8 ) != 0 ) ? 1 : 0 );
90  
91          nbUnusedBits = length % 8;
92  
93          if ( nbBytes > DEFAULT_LENGTH )
94          {
95  
96              // TODO : implement the streaming
97              isStreamed = true;
98              bytes      = new byte[nbBytes];
99          }
100         else
101         {
102             isStreamed = false;
103             bytes      = new byte[nbBytes];
104         }
105     }
106 
107     /***
108      * Creates a streamed BitString with a specific length.
109      * Actually, it's just a simple BitString.
110      * TODO Implement streaming.
111      * 
112      * @param length The BitString length, in number of bits 
113      * @param isStreamed Tells if the BitString must be streamed or not 
114     */
115     public BitString(  int length, boolean isStreamed )
116     {
117         nbBits          = length;
118         this.isStreamed = isStreamed;
119         nbBytes         = ( length / 8 ) + ( ( ( length % 8 ) != 0 ) ? 1 : 0 );
120 
121         nbUnusedBits    = length % 8;
122 
123         if ( isStreamed )
124         {
125 
126             // TODO : implement the streaming
127             bytes = new byte[nbBytes];
128         }
129         else
130         {
131             bytes = new byte[nbBytes];
132         }
133     }
134 
135     /***
136      * Creates a BitString with a value.  
137      * 
138      * @param bytes The value to store. The first byte contains the number 
139      * of unused bits
140      */
141     public BitString(  byte[] bytes )
142     {
143         nbBytes = bytes.length - 1;
144 
145         if ( nbBytes > DEFAULT_LENGTH )
146         {
147             isStreamed = true;
148 
149             // It will be a streamed OctetString.
150             // TODO : implement the streaming
151             bytes = new byte[nbBytes];
152         }
153         else
154         {
155             isStreamed = false;
156 
157             bytes      = new byte[nbBytes];
158         }
159 
160         setBytes( bytes, nbBytes );
161     }
162 
163     //~ Methods ------------------------------------------------------------------------------------
164 
165     /***
166      * Set the value into the bytes.
167      * @param bytes The bytes to copy
168      * @param nbBytes Number of bytes to copy
169     */
170     private void setBytes( byte[] bytes, int nbBytes )
171     {
172 
173         // The first byte contains the number of unused ints
174         nbUnusedBits = bytes[0] & 0x07;
175         nbBits       = ( nbBytes * 8 ) - nbUnusedBits;
176 
177         // We have to transfer the data from bytes to ints
178         for ( int i = 0; i < nbBytes; i++ )
179         {
180             this.bytes[i] = bytes[i + 1];
181         }
182     }
183 
184     /***
185      * Set a new BitString in the BitString. It will replace the old BitString,
186      * and reset the current length with the new one.
187      * 
188      * @param bytes The string to store
189      */
190     public void setData( byte[] bytes )
191     {
192 
193         if ( ( bytes == null ) || ( bytes.length == 0 ) )
194         {
195             nbBits = -1;
196             return;
197         }
198 
199         int nbBytes = bytes.length - 1;
200 
201         if ( ( nbBytes > DEFAULT_LENGTH ) && ( bytes.length < nbBytes ) )
202         {
203 
204             // The current size is too small.
205             // We have to allocate more space
206             // TODO : implement the streaming
207             bytes = new byte[nbBytes];
208         }
209 
210         setBytes( bytes, nbBytes );
211     }
212     
213     /***
214      * Get the representation of a BitString
215      * @return A byte array which represent the BitString
216      */
217     public byte[] getData()
218     {
219         return bytes;
220     }
221 
222     /***
223      * Get the number of unused bits 
224      * @return A byte which represent the number of unused bits
225      */
226     public byte getUnusedBits()
227     {
228         return (byte)nbUnusedBits;
229     }
230 
231     /***
232      * Get the bit stored into the BitString at a specific position? The position start at 0,
233      * which is on the left :
234      * With '1001 000x', where x is an unused bit, 
235      *       ^ ^    ^^ 
236      *       | |    ||
237      *       | |    |+---- getBit(7) -> DecoderException
238      *       | |    +----- getBit(6) = 0
239      *       | +---------- getBit(2) = 0
240      *       +------------ getBit(0) = 1 
241      * @param pos The position of the requested bit.
242      * @return <code>true</code> if the bit is set, <code>false</code> otherwise
243      */
244     public boolean getBit( int pos ) throws DecoderException
245     {
246 
247         if ( pos > nbBits )
248         {
249             throw new DecoderException(
250                 "Cannot get a bit at position " + pos + " when the BitString contains only " +
251                 nbBits + " ints" );
252         }
253 
254         int posInt    = pos / 8;
255 
256         int bitNumber = 7 - ( pos % 8 );
257         int res       = bytes[posInt] & ( 1 << bitNumber );
258         return res != 0;
259     }
260 
261     /***
262      * Return a native String representation of the BitString.
263      * @return A String representing the BitString
264     */
265     public String toString()
266     {
267 
268         StringBuffer sb = new StringBuffer();
269 
270         try
271         {
272 
273             for ( int i = 0; i < nbBits; i++ )
274             {
275 
276                 if ( getBit( i ) )
277                 {
278                     sb.append( '1' );
279                 }
280                 else
281                 {
282                     sb.append( '0' );
283                 }
284             }
285         }
286         catch ( DecoderException de )
287         {
288             return "Invalid BitString";
289         }
290 
291         return sb.toString();
292     }
293 
294     /***
295      * Tells if the OctetString is streamed or not
296      * @return <code>true</code> if the OctetString is streamed.
297      */
298     public boolean isStreamed()
299     {
300         return isStreamed;
301     }
302 }