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.ber.tlv;
18  
19  import org.apache.asn1.codec.EncoderException;
20  import org.apache.asn1new.primitives.OID;
21  import org.apache.asn1new.primitives.OctetString;
22  import org.apache.asn1new.util.StringUtils;
23  
24  import java.io.Serializable;
25  import java.io.UnsupportedEncodingException;
26  import java.nio.BufferOverflowException;
27  import java.nio.ByteBuffer;
28  
29  /***
30   * This class stores the data decoded from a TLV.
31   * 
32   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
33   */
34  public class Value implements Cloneable, Serializable
35  {
36      public static final long serialVersionUID = 1L;
37  
38      //~ Instance fields ----------------------------------------------------------------------------
39  
40      /*** The data buffer.  
41       * TODO Create a streamed data to store large data */
42      private byte[] data;
43  
44      /*** The current position of the last byte in the data buffer */
45      private int    currentPos;
46      
47      /*** The encoded byte for a TRUE value */ 
48      public static final byte TRUE_VALUE = (byte)0xFF;
49      
50      /*** The encoded byte for a FALSE value */ 
51      public static final byte FALSE_VALUE = (byte)0x00;
52      
53      /*** Pre-encoded PDUs for a TRUE and FALSE TLV */
54      private static final byte[] ENCODED_TRUE = new byte[] { 0x01, 0x01, TRUE_VALUE};
55      private static final byte[] ENCODED_FALSE = new byte[] { 0x01, 0x01, FALSE_VALUE};
56      
57      /*** Integer limits for encoding */
58      private static final int ONE_BYTE_MAX   = ( 1 << 7 ) - 1;    // 0x7F
59      private static final int ONE_BYTE_MIN   = -(1<<7);
60      private static final int TWO_BYTE_MAX   = ( 1 << 15 ) - 1;   // 0x7FFF
61      private static final int TWO_BYTE_MIN   = -(1<<15);
62      private static final int THREE_BYTE_MAX = ( 1 << 23 ) - 1;   // 0x7FFFFF
63      private static final int THREE_BYTE_MIN = -(1<<23);
64      private static final int FOUR_BYTE_MAX  = ( 1 << 31 ) - 1;   // 0x7FFFFFFF
65      private static final int FOUR_BYTE_MIN  =  Integer.MIN_VALUE;
66      
67      //~ Methods ------------------------------------------------------------------------------------
68  
69      /***
70       * The constructor.
71       */
72      public Value( byte[] value )
73      {
74          data = value;
75          currentPos = 0;
76      }
77      
78      /***
79       * The constructor.
80       */
81      public Value()
82      {
83          data = null;
84          currentPos = 0;
85      }
86      
87      /***
88       * Initialize the Value
89       *
90       * @param size The data size to allocate.
91       */
92      public void init( int size )
93      {
94          data = new byte[size];
95          currentPos = 0;
96      }
97  
98      /***
99       * Reset the Value so that it can be reused
100      */
101     public void reset()
102     {
103         data = null;
104         currentPos = 0;
105     }
106 
107     /***
108      * Clone the Value
109      *
110      * @return An object that is a copy of this Value
111      *
112      * @throws CloneNotSupportedException Thrown when the cloning failed
113      */
114     public Object clone() throws CloneNotSupportedException
115     {
116 
117         return super.clone();
118     }
119 
120     /***
121      * Get the Values'data
122      *
123      * @return Returns the data.
124      */
125     public byte[] getData()
126     {
127         return data;
128     }
129 
130     /***
131      * Set a block of bytes in the Value
132      *
133      * @param data The data to set.
134      */
135     public void setData( ByteBuffer data )
136     {
137         int length = data.remaining();
138         data.get( this.data, 0, length );
139         currentPos = length;
140     }
141 
142     /***
143      * Append some bytes to the data buffer. 
144      *
145      * @param data The data to append.
146      */
147     public void addData( ByteBuffer data )
148     {
149         int length = data.remaining();
150         data.get( this.data, currentPos, length );
151         currentPos += length;
152     }
153 
154     /***
155      * Set a block of bytes in the Value
156      *
157      * @param data The data to set.
158      */
159     public void setData( byte[] data )
160     {
161         System.arraycopy( data, 0, this.data, 0, data.length );
162         currentPos = data.length;
163     }
164 
165     /***
166      * Append some bytes to the data buffer. 
167      *
168      * @param data The data to append.
169      */
170     public void addData( byte[] data )
171     {
172         System.arraycopy( data, 0, this.data, currentPos, data.length );
173         currentPos = data.length;
174     }
175 
176     /***
177      * @return The number of bytes actually stored
178      */
179     public int getCurrentLength()
180     {
181         return currentPos;
182     }
183 
184     /***
185      * Utility function that return the number of bytes necessary to store 
186      * an integer value. Note that this value must be  in [Integer.MIN_VALUE, Integer.MAX_VALUE].
187      * 
188      * @param value The value to store in a byte array
189      * @param sign The integer value sign 
190      * @return The number of bytes necessary to store the value.
191      */
192     public static int getNbBytes( int value )
193     {
194         if ( value >= ONE_BYTE_MIN && value <= ONE_BYTE_MAX )
195         {
196             return 1;
197         }
198         else if ( value >= TWO_BYTE_MIN && value <= TWO_BYTE_MAX )
199         {
200             return 2;
201         }
202         else if ( value >= THREE_BYTE_MIN && value <= THREE_BYTE_MAX )
203         {
204             return 3;
205         }
206         else if ( value >= FOUR_BYTE_MIN && value <= FOUR_BYTE_MAX )
207         {
208             return 4;
209         }
210         else
211         {
212             return 5;
213         }
214     }
215 
216     /***
217      * Utility function that return a byte array representing the Value
218      * We must respect the ASN.1 BER encoding scheme :
219      * 1) positive integer 
220      *  - [0 - 0x7F]                : 0xVV 
221      *  - [0x80 -  0xFF]            : 0x00 0xVV
222      *  - [0x0100 - 0x7FFF]         : 0xVV 0xVV
223      *  - [0x8000 - 0xFFFF]         : 0x00 0xVV 0xVV 
224      *  - [0x010000 - 0x7FFFFF]     : 0xVV 0xVV 0xVV
225      *  - [0x800000 - 0xFFFFFF]     : 0x00 0xVV 0xVV 0xVV 
226      *  - [0x01000000 - 0x7FFFFFFF] : 0xVV 0xVV 0xVV 0xVV
227      *  - [0x80000000 - 0xFFFFFFFF] : 0x00 0xVV 0xVV 0xVV 0xVV
228      *  2) Negative number
229      *   - (~value) + 1
230      *   
231      * @param value The value to store in a byte array
232      * @param sign The value sign : positive or negative
233      * @return The byte array representing the value.
234      */
235     public static byte[] getBytes( int value )
236     {
237         byte[] bytes = null;
238         
239         if ( value >= ONE_BYTE_MIN && value <= ONE_BYTE_MAX )
240         {
241             bytes = new byte[1];
242             bytes[0] = ( byte ) value;
243         }
244         else if ( value >= TWO_BYTE_MIN && value <= TWO_BYTE_MAX )
245         {
246             bytes = new byte[2];
247             bytes[1] = ( byte ) value;
248             bytes[0] = ( byte ) ( value >> 8 );
249         }
250         else if ( value >= THREE_BYTE_MIN && value <= THREE_BYTE_MAX )
251         {
252             bytes = new byte[3];
253             bytes[2] = ( byte ) value;
254             bytes[1] = ( byte ) ( value >> 8 );
255             bytes[0] = ( byte ) ( value >> 16 );
256         }
257         else if ( value >= FOUR_BYTE_MIN && value <= FOUR_BYTE_MAX )
258         {
259             bytes = new byte[4];
260             bytes[3] = ( byte ) value;
261             bytes[2] = ( byte ) ( value >> 8 );
262             bytes[1] = ( byte ) ( value >> 16 );
263             bytes[0] = ( byte ) ( value >> 24 );
264         }
265 
266         return bytes;
267     }
268 
269     /***
270      * Encode a String value 
271      * 
272      * @param buffer The PDU in which the value will be put
273      * @param string The String to be encoded. It is supposed to be UTF-8 
274      */
275     public static void encode( ByteBuffer buffer, String string ) throws EncoderException
276     {
277         if ( buffer == null )
278         {
279             throw new EncoderException( "Cannot put a PDU in a null buffer !" );
280         }
281 
282         try 
283         {
284             buffer.put( UniversalTag.OCTET_STRING_TAG );
285             
286             byte[] value = null;
287             
288             try 
289             {
290                 value = string.getBytes("UTF-8");
291             } 
292             catch (UnsupportedEncodingException uee)
293             {
294                 throw new EncoderException("The Value encoding is not UTF-8");
295             }
296             
297             buffer.put( Length.getBytes( value.length ) );
298     
299             if ( value.length != 0 )
300             {
301                 buffer.put( value );
302             }
303         }
304         catch ( BufferOverflowException boe )
305         {
306             throw new EncoderException("The PDU buffer size is too small !"); 
307         }
308 
309         return;
310     }
311 
312     /***
313      * Encode an OctetString value 
314      * 
315      * @param buffer The PDU in which the value will be put
316      * @param string The OctetString to be encoded
317      */
318     public static void encode( ByteBuffer buffer, OctetString string ) throws EncoderException
319     {
320         if ( buffer == null )
321         {
322             throw new EncoderException( "Cannot put a PDU in a null buffer !" );
323         }
324 
325         try 
326         {
327             buffer.put( UniversalTag.OCTET_STRING_TAG );
328             buffer.put( Length.getBytes( string.getNbBytes() ) );
329     
330             if ( string.getNbBytes() != 0 )
331             {
332                 buffer.put( string.getValue() );
333             }
334         }
335         catch ( BufferOverflowException boe )
336         {
337             throw new EncoderException("The PDU buffer size is too small !"); 
338         }
339 
340         return;
341     }
342 
343     /***
344      * Encode an OctetString value 
345      * 
346      * @param buffer The PDU in which the value will be put
347      * @param byte[] The bytes to be encoded
348      */
349     public static void encode( ByteBuffer buffer, byte[] bytes ) throws EncoderException
350     {
351         if ( buffer == null )
352         {
353             throw new EncoderException( "Cannot put a PDU in a null buffer !" );
354         }
355 
356         try 
357         {
358             buffer.put( UniversalTag.OCTET_STRING_TAG );
359             
360             if ( ( bytes == null ) || ( bytes.length == 0 ) )
361             {
362                 buffer.put( (byte) 0 );
363             }
364             else
365             {
366                 buffer.put( Length.getBytes( bytes.length ) );
367                 buffer.put( bytes );
368             }
369         }
370         catch ( BufferOverflowException boe )
371         {
372             throw new EncoderException("The PDU buffer size is too small !"); 
373         }
374 
375         return;
376     }
377 
378     /***
379      * Encode an OID value 
380      * 
381      * @param buffer The PDU in which the value will be put
382      * @param string The OID to be encoded
383      */
384     public static void encode( ByteBuffer buffer, OID oid ) throws EncoderException
385     {
386         if ( buffer == null )
387         {
388             throw new EncoderException( "Cannot put a PDU in a null buffer !" );
389         }
390 
391         try 
392         {
393             buffer.put( UniversalTag.OCTET_STRING_TAG );
394             buffer.put( Length.getBytes( oid.getOIDLength() ) );
395     
396             if ( oid.getOIDLength() != 0 )
397             {
398                 buffer.put( oid.getOID() );
399             }
400         }
401         catch ( BufferOverflowException boe )
402         {
403             throw new EncoderException("The PDU buffer size is too small !"); 
404         }
405 
406         return;
407     }
408 
409     /***
410      * Encode an integer value 
411      * 
412      * @param buffer The PDU in which the value will be put
413      * @param value The integer to be encoded
414      */
415     public static void encode( ByteBuffer buffer, int value ) throws EncoderException
416     {
417         if ( buffer == null )
418         {
419             throw new EncoderException( "Cannot put a PDU in a null buffer !" );
420         }
421 
422         try
423         {
424             buffer.put( UniversalTag.INTEGER_TAG );
425             buffer.put( Length.getBytes( getNbBytes( value ) ) );
426             buffer.put( getBytes( value ) );
427         }
428         catch ( BufferOverflowException boe )
429         {
430             throw new EncoderException("The PDU buffer size is too small !"); 
431         }
432 
433         return;
434     }
435 
436     /***
437      * Encode an enumerated value 
438      * 
439      * @param buffer The PDU in which the value will be put
440      * @param value The integer to be encoded
441      */
442     public static void encodeEnumerated( ByteBuffer buffer, int value ) throws EncoderException
443     {
444         if ( buffer == null )
445         {
446             throw new EncoderException( "Cannot put a PDU in a null buffer !" );
447         }
448 
449         try
450         {
451             buffer.put( UniversalTag.ENUMERATED_TAG );
452             buffer.put( Length.getBytes( getNbBytes( value ) ) );
453             buffer.put( getBytes( value ) );
454         }
455         catch ( BufferOverflowException boe )
456         {
457             throw new EncoderException("The PDU buffer size is too small !"); 
458         }
459 
460         return;
461     }
462 
463     /***
464      * Encode a boolean value 
465      * 
466      * @param buffer The PDU in which the value will be put
467      * @param bool The boolean to be encoded
468      */
469     public static void encode( ByteBuffer buffer, boolean bool ) throws EncoderException
470     {
471         if ( buffer == null )
472         {
473             throw new EncoderException( "Cannot put a PDU in a null buffer !" );
474         }
475 
476         try
477         {
478             buffer.put( bool ? ENCODED_TRUE : ENCODED_FALSE ) ;
479         }
480         catch ( BufferOverflowException boe )
481         {
482             throw new EncoderException("The PDU buffer size is too small !"); 
483         }
484 
485         return;
486     }
487 
488     /***
489      * Return a string representing the Value
490      *
491      * @return A string representing the value
492      */
493     public String toString()
494     {
495 
496         StringBuffer sb = new StringBuffer();
497         sb.append( "DATA" );
498 
499         if ( data != null )
500         {
501             sb.append( '[' );
502             sb.append( StringUtils.dumpBytes( data ) );
503             sb.append( ']' );
504         }
505         else
506         {
507 
508             return "[]";
509         }
510 
511         return sb.toString();
512     }
513 }