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 }