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.ber.tlv;
021    
022    
023    import org.apache.directory.shared.asn1.util.Asn1StringUtils;
024    
025    
026    /**
027     * This class is used to store Tag, Length and Value decoded from a PDU.
028     * 
029     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
030     * @version $Rev: 664290 $, $Date: 2008-06-07 08:28:06 +0200 (Sat, 07 Jun 2008) $
031     */
032    public class TLV
033    {
034        // ~ Static fields/initializers
035        // -----------------------------------------------------------------
036    
037        // ~ Instance fields
038        // ----------------------------------------------------------------------------
039    
040        /** The current Tag being processed */
041        private byte tag;
042    
043        /** The current Length being processed */
044        private int length;
045    
046        /** The number of byte to store the Length being processed */
047        private int lengthNbBytes;
048        
049        /** The number of length's bytes currently read */
050        private int lengthBytesRead;
051    
052        /** The current Value being processed */
053        private Value value;
054    
055        /** An identity for the TLV. It store the TLV hashCode */
056        private int id;
057        
058        /**
059         * Reference the TLV which contains the current TLV, if any. As the
060         * enclosing TLV of a PDU does not have parent, it can be null in this case.
061         * Otherwise, it must point to a constructed TLV
062         */
063        private TLV parent;
064    
065        /**
066         * The expected length of the TLV's elements, if the current TLV is a
067         * constructed TLV.
068         */
069        private int expectedLength;
070    
071        /** tag flag for the primitive/constructed bit - 0010 0000 - 0x20 */
072        public static final byte CONSTRUCTED_FLAG = 0x20;
073    
074        /** mask to get the type class value */
075        public static final byte TYPE_CLASS_MASK = (byte)0xC0;
076        
077        /** value for the universal type class */
078        public static final byte TYPE_CLASS_UNIVERSAL = 0x00;
079    
080        /** tag mask for the short tag format - 0001 1111 - 0x1F */
081        public static final int SHORT_MASK = 0x1F;
082    
083        /** A mask to get the Length form */
084        public static final int LENGTH_LONG_FORM = 0x0080;
085    
086        /** Value of the reserved extension */
087        public static final int LENGTH_EXTENSION_RESERVED = 0x7F;
088    
089        /** A mask to get the long form value */
090        public static final int LENGTH_SHORT_MASK = 0x007F;
091        
092        /** A speedup for single bytes length */
093        static byte[][] ONE_BYTE = new byte[256][];
094        
095        static
096        {
097            for ( int i = 0; i < 256; i++ )
098            {
099                ONE_BYTE[i] = new byte[1];
100                ONE_BYTE[i][0] = (byte)i;
101            }
102        }
103        
104    
105        /**
106         * Creates a new TLV object.
107         * 
108         * @param id the TLV's id
109         */
110        public TLV( int id )
111        {
112            tag = 0;
113            length = 0;
114            lengthNbBytes = 0;
115            value = new Value();
116            this.id = id;
117            
118            expectedLength = 0;
119        }
120    
121    
122        // ~ Methods
123        // ------------------------------------------------------------------------------------
124    
125        /**
126         * Checks to see if the tag is constructed.
127         * 
128         * @param tag the TLV's tag 
129         * @return true if constructed, false if primitive
130         */
131        public static boolean isConstructed( byte tag )
132        {
133            return ( tag & CONSTRUCTED_FLAG ) != 0;
134        }
135    
136        /**
137         * Checks to see if the current tlv's tag is constructed.
138         * 
139         * @return true if constructed, false if primitive
140         */
141        public boolean isConstructed()
142        {
143            return ( tag & CONSTRUCTED_FLAG ) != 0;
144        }
145    
146    
147        /**
148         * Checks to see if the tag represented by this Tag is primitive or
149         * constructed.
150         * 
151         * @param tag the tag to be checked 
152         * @return true if it is primitive, false if it is constructed
153         */
154        public static boolean isPrimitive( byte tag )
155        {
156            return ( tag & CONSTRUCTED_FLAG ) == 0;
157        }
158    
159        /**
160         * Tells if the tag is Universal or not
161         * 
162         * @param tag the tag to be checked
163         * @return true if it is primitive, false if it is constructed
164         */
165        public static boolean isUniversal( byte tag )
166        {
167            return ( tag & TYPE_CLASS_MASK ) == TYPE_CLASS_UNIVERSAL; 
168        }
169    
170        /**
171         * Reset the TLV, so it can be reused for the next PDU decoding.
172         */
173        public void reset()
174        {
175            tag = 0;
176            length = 0;
177            lengthNbBytes = 0;
178            value.reset();
179    
180            expectedLength = 0;
181        }
182    
183        /**
184         * @return Returns the tag.
185         */
186        public byte getTag()
187        {
188            return tag;
189        }
190    
191        /**
192         * Set a tag value for this TLV.
193         * 
194         * @param tag the tag field for this TLV.
195         */
196        public void setTag( byte tag )
197        {
198            this.tag = tag;
199        }
200    
201        /**
202         * @return Returns the value.
203         */
204        public Value getValue()
205        {
206            return value;
207        }
208    
209        /**
210         * Get a String representation of the TLV
211         * 
212         * @return A String
213         */
214        public String toString()
215        {
216    
217            StringBuffer sb = new StringBuffer();
218    
219            sb.append( "TLV[ " );
220            sb.append( Asn1StringUtils.dumpByte( tag ) ).append( ", " );
221            sb.append( length ).append( ", " );
222            sb.append( value.toString() );
223            sb.append( "]" );
224    
225            return sb.toString();
226        }
227    
228    
229        /**
230         * The TLV size is calculated by adding the Tag's size, the Length's size
231         * and the Value's length, if any.
232         * 
233         * @return Returns the size of the TLV.
234         */
235        public int getSize()
236        {
237            return 1 + lengthNbBytes + length;
238        }
239    
240        /**
241         * Utility function that return the number of bytes necessary to store the
242         * length
243         * 
244         * @param length The length to store in a byte array
245         * @return The number of bytes necessary to store the length.
246         */
247        public static int getNbBytes( int length )
248        {
249    
250            if ( length >= 0 )
251            {
252    
253                if ( length < 128 )
254                {
255                    return 1;
256                }
257                else if ( length < 256 )
258                {
259                    return 2;
260                }
261                else if ( length < 65536 )
262                {
263                    return 3;
264                }
265                else if ( length < 16777216 )
266                {
267                    return 4;
268                }
269                else
270                {
271                    return 5;
272                }
273            }
274            else
275            {
276                return 5;
277            }
278        }
279    
280        /**
281         * Utility function that return a byte array representing the length
282         * 
283         * @param length The length to store in a byte array
284         * @return The byte array representing the length.
285         */
286        public static byte[] getBytes( int length )
287        {
288            if ( length >= 0 )
289            {
290                if ( length < 128 )
291                {
292                    return ONE_BYTE[length];
293                }
294                else 
295                {
296                    byte[] bytes = new byte[getNbBytes( length )];
297                    
298                    if ( length < 256 )
299                    {
300                        bytes[0] = ( byte ) 0x81;
301                        bytes[1] = ( byte ) length;
302                    }
303                    else if ( length < 65536 )
304                    {
305                        bytes[0] = ( byte ) 0x82;
306                        bytes[1] = ( byte ) ( length >> 8 );
307                        bytes[2] = ( byte ) ( length & 0x00FF );
308                    }
309                    else if ( length < 16777216 )
310                    {
311                        bytes[0] = ( byte ) 0x83;
312                        bytes[1] = ( byte ) ( length >> 16 );
313                        bytes[2] = ( byte ) ( ( length >> 8 ) & 0x00FF );
314                        bytes[3] = ( byte ) ( length & 0x00FF );
315                    }
316                    else
317                    {
318                        bytes[0] = ( byte ) 0x84;
319                        bytes[1] = ( byte ) ( length >> 24 );
320                        bytes[2] = ( byte ) ( ( length >> 16 ) & 0x00FF );
321                        bytes[3] = ( byte ) ( ( length >> 8 ) & 0x00FF );
322                        bytes[4] = ( byte ) ( length & 0x00FF );
323                    }
324                    
325                    return bytes;
326                }
327            }
328            else
329            {
330                byte[] bytes = new byte[getNbBytes( length )];
331    
332                bytes[0] = ( byte ) 0x84;
333                bytes[1] = ( byte ) ( length >> 24 );
334                bytes[2] = ( byte ) ( ( length >> 16 ) & 0x00FF );
335                bytes[3] = ( byte ) ( ( length >> 8 ) & 0x00FF );
336                bytes[4] = ( byte ) ( length & 0x00FF );
337    
338                return bytes;
339            }
340        }
341        
342    
343        /**
344         * @return Returns the parent.
345         */
346        public TLV getParent()
347        {
348            return parent;
349        }
350    
351    
352        /**
353         * @param parent The parent to set.
354         */
355        public void setParent( TLV parent )
356        {
357            this.parent = parent;
358        }
359    
360    
361        /**
362         * Get the TLV expected length.
363         * 
364         * @return Returns the expectedLength.
365         */
366        public int getExpectedLength()
367        {
368            return expectedLength;
369        }
370    
371    
372        /**
373         * Set the new expected length of the current TLV.
374         * 
375         * @param expectedLength The expectedLength to set.
376         */
377        public void setExpectedLength( int expectedLength )
378        {
379            this.expectedLength = expectedLength;
380        }
381    
382    
383        /**
384         * @return the number of bytes necessary to store the TLV's length
385         */
386        public int getLengthNbBytes()
387        {
388            return lengthNbBytes;
389        }
390    
391    
392        /**
393         * Set the number of bytes we should use to store the TLV's length
394         *  @param lengthNbBytes the number of bytes necessary to store the TLV's length
395         */
396        public void setLengthNbBytes( int lengthNbBytes )
397        {
398            this.lengthNbBytes = lengthNbBytes;
399        }
400    
401    
402        /**
403         * @return the tLV's length
404         */
405        public int getLength()
406        {
407            return length;
408        }
409    
410    
411        /**
412         * Set the TLV's length
413         *
414         * @param length the TLV's length
415         */
416        public void setLength( int length )
417        {
418            this.length = length;
419        }
420    
421    
422        /**
423         * @return the currently read TLV's length bytes
424         */
425        public int getLengthBytesRead()
426        {
427            return lengthBytesRead;
428        }
429    
430    
431        /**
432         * Set the currently read TLV's length bytes.
433         * 
434         * @param lengthBytesRead the currently read TLV's length bytes
435         */
436        public void setLengthBytesRead( int lengthBytesRead )
437        {
438            this.lengthBytesRead = lengthBytesRead;
439        }
440        
441        
442        /**
443         * Increment the number of bytes read for this TLV
444         *
445         */
446        public void incLengthBytesRead()
447        {
448            lengthBytesRead++;
449        }
450    
451        
452        /**
453         * @return the TLV's ID 
454         */
455        public int getId()
456        {
457            return id;
458        }
459    }
460