1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.asn1.ber ;
18
19
20 import org.apache.asn1.codec.DecoderException;
21
22
23 /***
24 * The Tag component of a BER TLV Tuple.
25 *
26 * @author <a href="mailto:dev@directory.apache.org">
27 * Apache Directory Project</a>
28 * @version $Rev: 157644 $
29 */
30 public class Tag
31 {
32 /*** tag flag for the primitive/constructed bit - 0010 0000 - 0x20 */
33 private static final int CONSTRUCTED_FLAG = 0x20 ;
34 /*** tag mask for the primitive/constructed bit - 1101 1111 - 0xDF */
35
36
37 /*** tag mask for the short tag format - 0001 1111 - 0x1F */
38 static final int SHORT_MASK = 0x1F ;
39 /*** tag mask for the long tag format - 0111 1111 - 0x7F */
40 static final int LONG_MASK = 0x7F ;
41 /*** tag flag indicating the use of the long tag encoding form */
42 private static final int LONG_FLAG = 0x80 ;
43
44 /*** the max id size with one tag octet */
45 private static final int ONE_OCTET_IDMAX = 30 ;
46 /*** the max id size with two tag octets */
47 private static final int TWO_OCTET_IDMAX = (1<<7)-1 ;
48 /*** the max id size with three tag octets */
49 private static final int THREE_OCTET_IDMAX = (1<<14)-1 ;
50 /*** the max id size with four tag octets */
51 private static final int FOUR_OCTET_IDMAX = (1<<21)-1 ;
52
53 /*** tag id */
54 private int id = 0 ;
55 /*** whether or not this tag represents a primitive type */
56 private boolean isPrimitive = true ;
57 /*** whether or not this tag has been fixated */
58 private boolean isFixated = false ;
59 /*** the type class of this tag */
60 private TypeClass typeClass = TypeClass.APPLICATION ;
61 /*** buffer backed by a Java int to collect the arriving tag octets */
62 private final TagOctetCollector buf = new TagOctetCollector() ;
63
64
65 /***
66 * Clears this tag's data of all bytes and values calculated so all is as it
67 * was when this instance was created.
68 */
69 void clear()
70 {
71 id = 0 ;
72 isFixated = false ;
73 isPrimitive = true ;
74 typeClass = TypeClass.APPLICATION ;
75 buf.clear() ;
76 }
77
78
79 /***
80 * Fixates the data within this Tag calculating all the derived
81 * properties from the existing set of octets. While fixated octets
82 * cannot be added.
83 *
84 * @throws DecoderException if this Tag is invalid
85 */
86 void fixate() throws DecoderException
87 {
88 isFixated = true ;
89 id = getTagId( buf ) ;
90 isPrimitive = isPrimitive( buf.get( 0 ) ) ;
91 typeClass = TypeClass.getTypeClass( buf.get( 0 ) ) ;
92 }
93
94
95 /***
96 * Adds an octet to this Tag and as a size effect may fixate the Tag if
97 * all the expected data has arrived.
98 *
99 * @param octet the 8 bit byte to add
100 */
101 void add( byte octet ) throws DecoderException
102 {
103 if ( isFixated )
104 {
105 throw new IllegalStateException( "data added to fixated tag" ) ;
106 }
107
108 buf.put( octet ) ;
109
110 if ( buf.size() == 1 )
111 {
112
113 if ( ( SHORT_MASK & octet ) != SHORT_MASK )
114 {
115 fixate() ;
116 }
117 }
118
119
120
121
122
123
124
125 else if ( ( octet & LONG_FLAG ) == 0 )
126 {
127 fixate() ;
128 }
129 }
130
131
132 /***
133 * Gets a copy of the octets composing this Tag.
134 *
135 * @return the octets representing this Tag
136 */
137 public byte[] getOctets()
138 {
139 return buf.toArray() ;
140 }
141
142
143 /***
144 * Gets the number of octets in this Tag.
145 *
146 * @return the number of octets within this Tag
147 */
148 public int size()
149 {
150 return buf.size() ;
151 }
152
153
154 /***
155 * Gets the id.
156 *
157 * @return the id
158 */
159 public int getId()
160 {
161 return id ;
162 }
163
164
165 /***
166 * Gets the raw tag as it is stuffed into a primitive int.
167 *
168 * @return a primitive int stuffed with the first four octets of the tag
169 */
170 public int getRawTag()
171 {
172 return buf.getIntValue() ;
173 }
174
175
176 /***
177 * Checks to see if the tag represented by this Tag is primitive or
178 * constructed.
179 *
180 * @return true if it is primitive, false if it is constructed
181 */
182 public boolean isPrimitive()
183 {
184 return isPrimitive ;
185 }
186
187
188 /***
189 * Checks to see if the tag has been fixated.
190 *
191 * @return true if it is fixated, false if not
192 */
193 public boolean isFixated()
194 {
195 return isFixated ;
196 }
197
198
199 /***
200 * Gets the type class for this Tag.
201 *
202 * @return the typeClass for this Tag
203 */
204 public TypeClass getTypeClass()
205 {
206 return typeClass ;
207 }
208
209
210
211
212
213
214
215 /***
216 * Sets the id of a tag encoded as a Java primitive integer.
217 *
218 * @param encodedTag the tag encoded as a Java primitive integer
219 * @param id the new tag id to set within the encodedTag
220 * @return the modified Java primitive int encoded tag with the new tag id
221 */
222 public final static int setIntEncodedId( int encodedTag, int id )
223 {
224 if ( id <= ONE_OCTET_IDMAX )
225 {
226 encodedTag |= ( id << 24 ) ;
227 }
228 else if ( id <= TWO_OCTET_IDMAX )
229 {
230 encodedTag |= ( SHORT_MASK << 24 ) ;
231 encodedTag |= ( id & 0x0000007F ) << 16 ;
232 }
233 else if ( id <= THREE_OCTET_IDMAX )
234 {
235 encodedTag |= ( SHORT_MASK << 24 ) ;
236 encodedTag |= ( id & 0x00003F80 ) << 9 ;
237 encodedTag |= ( id & 0x0000007F ) << 8 ;
238 encodedTag |= 0x00800000 ;
239 }
240 else if ( id <= FOUR_OCTET_IDMAX )
241 {
242 encodedTag |= ( SHORT_MASK << 24 ) ;
243 encodedTag |= ( id & 0x001FC000 ) << 2 ;
244 encodedTag |= ( id & 0x00003F80 ) << 1 ;
245 encodedTag |= ( id & 0x0000007F ) ;
246 encodedTag |= 0x00808000 ;
247 }
248 else
249 {
250 String msg = "Id argument value of " + id
251 + " was greater than the maximum supported id of "
252 + FOUR_OCTET_IDMAX ;
253 throw new IllegalArgumentException( msg ) ;
254 }
255
256 return encodedTag;
257 }
258
259
260 /***
261 * Assembles the Java primitive int based encoding for a tag using a set
262 * of parameters.
263 *
264 * @param type
265 * @param id
266 * @param isConstructed
267 * @return
268 */
269 public final static int
270 getIntEncodedTag( TypeClass type, int id, boolean isConstructed )
271 {
272 int value = type.getValue() << 24 ;
273
274 if ( isConstructed )
275 {
276 value |= ( CONSTRUCTED_FLAG << 24 ) ;
277 }
278
279 value = setIntEncodedId( value, id );
280
281 return value ;
282 }
283
284
285 /***
286 * Gets the tag id of a TLV from tag octets.
287 *
288 * @param octets the set of octets needed to determine the tag value
289 * (a.k.a identifier octets)
290 * @return the tag id
291 * @throws DecoderException if the id cannot be determined due to
292 * type limitations of this method's return type.
293 */
294 public final static int getTagId( byte[] octets )
295 throws DecoderException
296 {
297 if ( octets.length > 4 )
298 {
299
300
301
302
303
304 throw new DecoderException( "Tag number is too large." ) ;
305 }
306
307 int id = octets[0] & SHORT_MASK ;
308
309
310 if ( id != SHORT_MASK && octets.length == 1 )
311 {
312 return id ;
313 }
314
315
316 id = 0 ;
317
318
319 for( int ii = 1 ; ii < octets.length; ii++ )
320 {
321 id = (id << 7) | (octets[ii] & LONG_MASK);
322 }
323
324 return id ;
325 }
326
327
328 /***
329 * Gets the tag id of a TLV from tag octets encoded as a Java primitive int.
330 *
331 * @param octets the tag octets encoded as a Java primitive int
332 * @return the tag id
333 */
334 public final static int getTagId( int octets )
335 {
336
337 int id = ( octets >> 24 ) & SHORT_MASK;
338
339
340 if ( id != SHORT_MASK )
341 {
342 return id;
343 }
344
345
346 id = 0;
347
348
349 int octet = ( octets & 0x00ff0000 ) >> 16;
350 id |= octet & LONG_MASK ;
351
352
353 if ( ( octet & 0x80 ) == 0 )
354 {
355 return id ;
356 }
357
358
359 octet = 0;
360 octet = ( octets & 0x0000ff00 ) >> 8;
361
362 if ( octet == 0 )
363 {
364 return id << 7 ;
365 }
366
367 id <<= 7;
368 id |= octet & LONG_MASK;
369
370
371 if ( ( octet & 0x80 ) == 0 )
372 {
373 return id ;
374 }
375
376
377 octet = 0;
378 octet = octets & 0x000000ff;
379 id <<= 7;
380 id |= octet & LONG_MASK;
381
382 return id ;
383 }
384
385
386 /***
387 * Gets the tag id of a TLV from the tag octets.
388 *
389 * @param octets the set of octets needed to determine the tag value
390 * (a.k.a identifier octets)
391 * @return the tag id
392 */
393 public final static int getTagId( TagOctetCollector octets )
394 {
395 int id = octets.get( 0 ) & SHORT_MASK ;
396
397
398 if ( id != SHORT_MASK && octets.size() == 1 )
399 {
400 return id ;
401 }
402
403
404 id = 0 ;
405
406
407 for( int ii = 1 ; ii < octets.size(); ii++ )
408 {
409 id = (id << 7) | (octets.get(ii) & LONG_MASK);
410 }
411
412 return id ;
413 }
414
415
416 /***
417 * Checks to see if the tag is a primitive.
418 *
419 * @param octet the first octet of the tag
420 * @return true if this tag is of the simple type, false if constructed
421 */
422 public final static boolean isPrimitive( int octet )
423 {
424 return ( octet & CONSTRUCTED_FLAG ) == 0 ;
425 }
426
427
428 /***
429 * Checks to see if the tag is constructed.
430 *
431 * @param octet the first octet of the tag
432 * @return true if constructed, false if primitive
433 */
434 public final static boolean isConstructed( int octet )
435 {
436 return ( octet & CONSTRUCTED_FLAG ) == CONSTRUCTED_FLAG ;
437 }
438
439
440 public static boolean isRawTagConstructed( int rawTag )
441 {
442 if ( ( rawTag & 0x20000000 ) > 0 )
443 {
444 return true;
445 }
446
447 return false;
448 }
449 }