View Javadoc

1   /*
2    *   Copyright 2004-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.asn1.ber ;
18  
19  
20  import java.nio.ByteBuffer;
21  
22  import org.apache.asn1.codec.DecoderException;
23  
24  
25  /***
26   * The length component of a BER TLV Tuple.
27   *
28   * @author <a href="mailto:dev@directory.apache.org">
29   * Apache Directory Project</a>
30   * @version $Rev: 157644 $
31   */
32  public class Length
33  {
34      /*** used to mark length as indefinite */
35      public static final int INDEFINITE = -2 ;
36      /*** used to mark length as undefined */
37      public static final int UNDEFINED = -1 ;
38      /*** the end long form terminate bit flag mask */
39      public static final int END_MASK = 0x80 ;
40  
41      /*** the value for this tlv length */
42      private int value = UNDEFINED ;
43      /*** the number of octets needed to complete this length component */
44      private int numOctets = UNDEFINED ;
45      /*** whether or not this length has been fixated */
46      private boolean isFixated = false ;
47      /*** a byte buffer used to collect the arriving length octets */
48      private final ByteBuffer buf = ByteBuffer.allocate( 5 ) ;
49  
50  
51      /***
52       * Checks to see if the length has been fixated.
53       *
54       * @return true if it is fixated, false if not
55       */
56      public boolean isFixated()
57      {
58          return isFixated ;
59      }
60  
61  
62      /***
63       * Clears this tag's data of all bytes and values calculated so all is as it
64       * was when this instance was created.
65       */
66      void clear()
67      {
68          isFixated = false ;
69          value = 0 ;
70          numOctets = 1 ;
71          buf.clear() ;
72      }
73  
74  
75      /***
76       * Fixates the data within this Length calculating all the derived
77       * properties from the existing set of octets.  While fixated octets
78       * cannot be added.
79       *
80       * @throws org.apache.asn1.codec.DecoderException if this Length is invalid
81       */
82      void fixate() throws DecoderException
83      {
84          buf.flip() ;
85          value = getLength( buf ) ;
86          isFixated = true ;
87      }
88  
89  
90      /***
91       * Adds an octet to this Length component and as a side effect fixates the
92       * Length component if all the required length data has arrived.
93       *
94       * @param octet the 8 bit byte to add
95       */
96      void add( byte octet ) throws DecoderException
97      {
98          if ( isFixated )
99          {
100             throw new IllegalStateException( "data added to fixated length" ) ;
101         }
102 
103         buf.put( octet ) ;
104 
105         if ( buf.position() == 1 )
106         {
107             // if its the long form, but not above 126 octets : (1)111 1111 is not
108         	// allowed : this value is reserved for future extension.
109             if ( END_MASK == ( octet & END_MASK ))
110             {
111             	int typeLength = octet & 0x7F;
112 
113             	if (typeLength == 0)
114             	{
115                     numOctets = INDEFINITE;
116                     fixate() ;
117             	}
118             	else if (typeLength == 0x7F)
119             	{
120             		throw new DecoderException( "The number of octets must not be 127 (reserved for future extension) " ) ;
121             	}
122             	else
123             	{
124 	                // capture number of octets we need to compute length
125 	                numOctets = octet & 0x7F ;
126             	}
127             }
128             else
129             {
130                 fixate() ;
131             }
132         }
133 
134         /*
135          * if we have collected all the octets needed for computing the long
136          * form length so we need to calculate the length and just fixate
137          */
138         else if ( buf.position() >= numOctets + 1 )
139         {
140             fixate() ;
141         }
142     }
143 
144 
145     /***
146      * Gets the length of the value.
147      *
148      * @return the length of the value
149      */
150     public int getLength()
151     {
152         return value ;
153     }
154 
155 
156     /***
157      * Gets the number of octets currently in this Length component.
158      *
159      * @return the number of octets currently within this Length component
160      */
161     public int size()
162     {
163         return buf.position() ;
164     }
165 
166 
167     /***
168      * Decodes the length of a value for a tlv using the Length field bytes.
169      *
170      * @param octets the length field bytes in the TLV
171      * @return the length of the TLV
172      * @throws DecoderException if the precision cannot hold the number
173      */
174     public static int getLength( ByteBuffer octets ) throws DecoderException
175     {
176         if ( octets.remaining() >= 6 )
177         {
178             /*
179              * If this exception is ever thrown which is highly unlikely, then
180              * we need to switch to another data type to return because after
181              * 5 bytes the int can no longer hold the number.
182              */
183             throw new DecoderException( "Length number is too large." ) ;
184         }
185 
186         byte octet = octets.get() ;
187 
188         // if we are using the short form then just return the first octet
189         if ( ( octet & END_MASK ) == 0 )
190         {
191             return octet ;
192         }
193         // using the indefinite form
194         else if ( ( octet & 0x7F ) == 0 )
195         {
196             return INDEFINITE ;
197         }
198 
199         // using the long form so we calculate the length from all octets
200         int length = 0 ;
201         for ( int ii = octets.remaining(), shift = (ii-1)<<3; ii > 0; ii--, shift -= 8 )
202         {
203             length |= ( 0xFF & ( int ) octets.get() ) << shift ;
204         }
205 
206         // calculate tag value w/ long tag format
207 //        int shift = 0 ;
208 //        do
209 //        {
210 //            length |= ( 0xFF & ( int ) octets.get() ) << shift ;
211 //            shift += 8 ;
212 //        }
213 //        while ( octets.hasRemaining() ) ;
214 
215         return length ;
216     }
217 }