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 java.nio.ByteBuffer;
21 import java.util.Stack;
22
23 import org.apache.asn1.codec.DecoderException;
24 import org.apache.asn1.codec.stateful.DecoderCallback;
25 import org.apache.asn1.codec.stateful.DecoderMonitor;
26 import org.apache.asn1.codec.stateful.DecoderMonitorAdapter;
27 import org.apache.asn1.codec.stateful.StatefulDecoder;
28 import org.apache.commons.lang.ArrayUtils;
29
30
31 /***
32 * A decoder that decodes BER encoded bytes to Tag Value Length (TLV) tuples.
33 * This decoder is a low level event based parser which operates in a fashion
34 * similar to the way SAX works except the elements of concern are the tag,
35 * length, and value entities. The decoder is a state machine which processes
36 * input as it is made available.
37 * <p>
38 * A Stack is used to track the state of the decoder between decode calls. It
39 * maintains the nesting of TLV tuples. Rather than creating new TLV tuple
40 * instances every time a single tuple is reused for primitive types and new
41 * tlv tuples are cloned for constructed types which are pushed onto the stack.
42 * The tuple fed to the callback must therefore be used very carefully - its
43 * values must be copied to prevent their loss if they are to be used later
44 * after the callback invokation has returned.
45 * </p>
46 * <p>
47 * Note that all tuples are not created equal. Constructed TLVs nesting others
48 * will have null value members or empty buffers. Only TLV tuples of primitive
49 * types or the leaf TLV tuples of the TLV tuple tree will contain non null
50 * values. Therefore the nature of a TLV tuple should be investigated by
51 * callbacks before attempting to interpret their values. Also this decoder
52 * chunks value data returning it in parts rather than in one complete peice
53 * in the end. The value of the TLV Tuple returned is the part of the value
54 * that was read from the input fed into the decoder. These 'chunks' returned
55 * by callback makes it so there are no size limits to the value of a TLV. Again
56 * to reiterate chunking on values is only performed on primitive TLV Tuple
57 * types.
58 * </p>
59 *
60 * @author <a href="mailto:dev@directory.apache.org">
61 * Apache Directory Project</a>
62 * @version $Rev: 157644 $
63 */
64 public class BERDecoder implements StatefulDecoder, DecoderCallback
65 {
66 /*** empty byte buffer to be reused */
67 private static final ByteBuffer EMPTY_BUFFER =
68 ByteBuffer.wrap( ArrayUtils.EMPTY_BYTE_ARRAY ) ;
69 /*** the callback used by this decoder */
70 private static final BERDecoderCallback DEFAULT_CALLBACK =
71 new BERDecoderCallbackAdapter() ;
72 /*** the monitor used by this decoder */
73 private static final DecoderMonitor DEFAULT_MONITOR =
74 new DecoderMonitorAdapter() ;
75
76 /*** this decoder's callback */
77 private BERDecoderCallback cb = DEFAULT_CALLBACK ;
78 /*** the monitor used by this decoder */
79 private DecoderMonitor monitor = DEFAULT_MONITOR ;
80
81 /*** the single TLV tuple used by this decoder */
82 private final Tuple tlv = new Tuple() ;
83
84 /*** a decoder used to decode tag octets */
85 private final TagDecoder tagDecoder = new TagDecoder() ;
86 /*** a decoder used to decode length octets */
87 private final LengthDecoder lengthDecoder = new LengthDecoder() ;
88
89 /*** stack of nested/constructed TLV tuples */
90 private final Stack tlvStack = new Stack() ;
91
92 /*** the state of this decoder */
93 private BERDecoderState state = BERDecoderState.getStartState() ;
94
95
96 /***
97 * Creates a stateful BER decoder which limits the tuple's value size.
98 */
99 public BERDecoder()
100 {
101 tagDecoder.setCallback( this ) ;
102 lengthDecoder.setCallback( this ) ;
103 }
104
105
106
107
108
109
110
111 /***
112 * Expects a ByteBuffer containing BER encoded data.
113 *
114 * @see org.apache.asn1.codec.stateful.StatefulDecoder#decode(
115 * java.lang.Object)
116 * @throws ClassCastException if the encoded argument is not a ByteBuffer
117 * @throws IllegalArgumentException if the buffer is null or empty
118 */
119 public void decode( Object encoded ) throws DecoderException
120 {
121 ByteBuffer buf = ( ByteBuffer ) encoded ;
122
123
124
125
126
127 if ( buf == null && monitor != null )
128 {
129 String msg = "ignoring null argument to decode()" ;
130 monitor.warning( this, new IllegalArgumentException( msg ) ) ;
131 return ;
132 }
133
134 if ( buf.remaining() == 0 && monitor != null )
135 {
136 String msg = "ignoring empty buffer" ;
137 monitor.warning( this, new IllegalArgumentException( msg ) ) ;
138 return ;
139 }
140
141
142
143
144
145
146
147
148 while ( buf.hasRemaining() )
149 {
150 switch( state.getValue() )
151 {
152 case( BERDecoderState.TAG_VAL ):
153 tagDecoder.decode( buf ) ;
154 break ;
155 case( BERDecoderState.LENGTH_VAL ):
156 lengthDecoder.decode( buf ) ;
157 break ;
158 case( BERDecoderState.VALUE_VAL ):
159 decodeValue( buf ) ;
160 break ;
161 }
162 }
163 }
164
165
166
167
168
169
170 public void setCallback( DecoderCallback cb )
171 {
172 this.cb = ( BERDecoderCallback ) cb ;
173 }
174
175
176
177
178
179
180 public void setDecoderMonitor( DecoderMonitor monitor )
181 {
182 this.monitor = monitor ;
183 }
184
185
186
187
188
189
190
191 /***
192 * Extracts the value portion from the buffer for a primitive type.
193 *
194 * @param buf the byte byffer containing BER encoded data
195 */
196 private void decodeValue( ByteBuffer buf )
197 {
198 int needToRead = Length.UNDEFINED ;
199
200
201
202
203
204
205 if ( tlv.valueIndex == Length.UNDEFINED )
206 {
207 needToRead = tlv.length ;
208 }
209 else
210 {
211 needToRead = tlv.length - tlv.valueIndex ;
212 }
213
214
215
216
217
218 if ( buf.remaining() >= needToRead )
219 {
220 tlv.valueChunk = ( ByteBuffer ) buf.slice().limit( needToRead ) ;
221 buf.position( buf.position() + needToRead ) ;
222 tlv.valueIndex = tlv.length ;
223 tlv.index += tlv.length ;
224
225 cb.partialValueDecoded( tlv ) ;
226 fireDecodeOccurred( tlv ) ;
227 updateStack( needToRead ) ;
228 tlv.clear() ;
229 state = BERDecoderState.TAG ;
230 }
231
232
233
234
235
236
237 else
238 {
239 if ( tlv.valueIndex == Length.UNDEFINED )
240 {
241 tlv.valueIndex = 0 ;
242 }
243
244 int remaining = buf.remaining() ;
245 tlv.valueChunk = buf.slice() ;
246 buf.position( buf.limit() ) ;
247 tlv.valueIndex += remaining ;
248 tlv.index +=remaining ;
249
250 cb.partialValueDecoded( tlv ) ;
251 updateStack( remaining ) ;
252 }
253 }
254
255
256
257
258
259
260
261 public void decodeOccurred( StatefulDecoder decoder, Object decoded )
262 {
263 if ( decoder == tagDecoder )
264 {
265 Tag tag = ( Tag ) decoded ;
266 tlv.rawTag = tag.getRawTag() ;
267 tlv.id = tag.getId() ;
268 tlv.isPrimitive = tag.isPrimitive() ;
269 tlv.typeClass = tag.getTypeClass() ;
270 tlv.index = tag.size() ;
271
272 if ( ! tlv.isIndefiniteTerminator() )
273 {
274 fireTagDecoded() ;
275 updateStack( tag.size() ) ;
276 }
277
278 state = state.getNext( tag.isPrimitive() ) ;
279 }
280 else if ( decoder == lengthDecoder )
281 {
282 Length length = ( Length ) decoded ;
283 tlv.length = length.getLength() ;
284
285 if ( tlv.length == Length.INDEFINITE )
286 {
287 tlv.index = Length.INDEFINITE ;
288 tlv.valueIndex = Length.INDEFINITE ;
289 }
290 else
291 {
292 tlv.index += length.size() ;
293 }
294
295 if ( ! tlv.isIndefiniteTerminator() )
296 {
297 fireLengthDecoded() ;
298 }
299 updateStack( length.size() ) ;
300
301 if ( ! tlv.isPrimitive )
302 {
303 if ( tlv.isIndefinite() || tlv.length > 0 )
304 {
305 tlvStack.push( tlv.clone() ) ;
306 }
307 else
308 {
309 state = BERDecoderState.VALUE ;
310 fireDecodeOccurred( tlv ) ;
311 }
312
313 state = BERDecoderState.TAG ;
314 tlv.clear() ;
315 }
316 else if ( tlv.isIndefiniteTerminator() )
317 {
318 return ;
319 }
320 else if ( tlv.length > 0 )
321 {
322 state = BERDecoderState.VALUE ;
323 }
324 else
325 {
326 state = BERDecoderState.VALUE ;
327 tlv.valueChunk = EMPTY_BUFFER ;
328 cb.partialValueDecoded( tlv ) ;
329 fireDecodeOccurred( tlv ) ;
330 state = BERDecoderState.TAG ;
331 }
332 }
333 else
334 {
335 throw new IllegalArgumentException( "unrecognized decoder" ) ;
336 }
337 }
338
339
340
341
342
343
344
345 /***
346 * Fires a tag decoded event by making the appropriate calls to the
347 * callback and the monitor. If the monitor is a BERDecoderMonitor with
348 * extended reporting, then those methods are invoked.
349 *
350 * Also as a side-effect this method clears the tag buffer once it has
351 * finished notifying the monitor and calling the callback.
352 */
353 private void fireTagDecoded()
354 {
355 if ( cb != null )
356 {
357 cb.tagDecoded( tlv ) ;
358 }
359
360 if ( monitor != null && monitor instanceof BERDecoderMonitor )
361 {
362 BERDecoderMonitor berMonitor = ( BERDecoderMonitor ) monitor ;
363 berMonitor.tagDecoded( tlv ) ;
364 }
365 }
366
367
368 /***
369 * Fires a length decoded event by making the appropriate calls to the
370 * callback and the monitor. If the monitor is a BERDecoderMonitor with
371 * extended reporting, then those methods are invoked.
372 *
373 * Also as a side-effect this method clears the length buffer once it has
374 * finished notifying the monitor and calling the callback.
375 */
376 private void fireLengthDecoded()
377 {
378 if ( cb != null )
379 {
380 cb.lengthDecoded( tlv ) ;
381 }
382
383 if ( monitor != null && monitor instanceof BERDecoderMonitor )
384 {
385 BERDecoderMonitor berMonitor = ( BERDecoderMonitor ) monitor ;
386 berMonitor.lengthDecoded( tlv ) ;
387 }
388 }
389
390
391 /***
392 * Fires a complete TLV decoded event by making the appropriate calls to
393 * the callback and the monitor.
394 */
395 private void fireDecodeOccurred( Tuple tlv )
396 {
397 if ( cb != null )
398 {
399 cb.decodeOccurred( this, tlv ) ;
400 }
401
402 if ( monitor != null )
403 {
404 monitor.callbackOccured( this, cb, tlv ) ;
405 }
406 }
407
408
409 /***
410 * Increments the indices of constructed TLV's within the TLV Stack.
411 *
412 * @param increment the amount to increment indices by.
413 */
414 private void updateStack( int increment )
415 {
416 for ( int ii = 0; ii < tlvStack.size(); ii++ )
417 {
418 Tuple t = ( Tuple ) tlvStack.get( ii ) ;
419
420 if ( t.isIndefinite() )
421 {
422 continue ;
423 }
424
425 t.index += increment ;
426
427 if ( t.valueIndex == Length.UNDEFINED )
428 {
429 t.valueIndex = 0 ;
430 }
431
432 t.valueIndex += increment ;
433 }
434
435 if ( tlvStack.isEmpty() )
436 {
437 return ;
438 }
439
440 do
441 {
442 Tuple top = ( Tuple ) tlvStack.peek() ;
443
444 if ( top.isIndefinite() && tlv.isIndefiniteTerminator() )
445 {
446 tlvStack.pop() ;
447 state = BERDecoderState.VALUE ;
448 fireDecodeOccurred( top ) ;
449 state = BERDecoderState.TAG ;
450 break;
451 }
452 else if ( top.isIndefinite() )
453 {
454 break ;
455 }
456 else if ( top.valueIndex >= top.length )
457 {
458 tlvStack.pop() ;
459 state = BERDecoderState.VALUE ;
460 fireDecodeOccurred( top ) ;
461 state = BERDecoderState.TAG ;
462 }
463 else
464 {
465 break ;
466 }
467
468 } while( tlvStack.size() > 0 ) ;
469 }
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499 /***
500 * Gets the current state of this BERDecoder. Used only for debugging and
501 * testing.
502 *
503 * @return the state enum
504 */
505 BERDecoderState getState()
506 {
507 return state ;
508 }
509
510
511 /***
512 * Gets a cloned copy of the current tuple. Used only for debugging and
513 * testing.
514 *
515 * @return a clone of the current tlv
516 */
517 Tuple getCurrentTuple()
518 {
519 return ( Tuple ) tlv.clone() ;
520 }
521
522
523 /***
524 * Gets a deep copy of the constructed tuple stack. Used only for debugging
525 * and testing.
526 *
527 * @return a deep copy of the tuple stack
528 */
529 Stack getTupleStack()
530 {
531 Stack stack = new Stack() ;
532
533 for ( int ii = 0; ii < tlvStack.size(); ii++ )
534 {
535 Tuple t = ( Tuple ) tlvStack.get( ii ) ;
536 stack.add( t.clone() ) ;
537 }
538
539 return stack ;
540 }
541 }