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 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 // StatefulDecoder Methods
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 Handle any unusual input by informing the monitor.
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 * This loop is used instead of costly recursion. This requires each
143 * of the statewise decode methods to process bytes from the buffer. If
144 * they can process enough to switch state they do and return
145 * immediately. This loop makes sure the next processing state is
146 * handled if there is more data for that state.
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 /* (non-Javadoc)
167 * @see org.apache.asn1.codec.stateful.StatefulDecoder#setCallback(
168 * org.apache.asn1.codec.stateful.DecoderCallback)
169 */
170 public void setCallback( DecoderCallback cb )
171 {
172 this.cb = ( BERDecoderCallback ) cb ;
173 }
174
175
176 /* (non-Javadoc)
177 * @see org.apache.asn1.codec.stateful.StatefulDecoder#setDecoderMonitor(
178 * org.apache.asn1.codec.stateful.DecoderMonitor)
179 */
180 public void setDecoderMonitor( DecoderMonitor monitor )
181 {
182 this.monitor = monitor ;
183 }
184
185
186 // ------------------------------------------------------------------------
187 // State Based Decode Methods
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 * setup to start decoding the value by figuring how much we need to
202 * read at this point - previous reads of the value may have already
203 * occurred.
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 * check if we have the remainder of the value to complete the
216 * TLV within the current buffer - if so we read all of it
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 * the buffer does not contain the rest of the value we need in order
234 * to complete the current TLV - the value is fragmented so we read
235 * what we can and update indices by that amount.
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 /* (non-Javadoc)
258 * @see org.apache.asn1.codec.stateful.DecoderCallback#decodeOccurred(
259 * org.apache.asn1.codec.stateful.StatefulDecoder, java.lang.Object)
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 // private utility methods
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 Why copy the raw tag here when we can maintain our own stack in the
475 digester that does the pushing and popping instead? Keep this here
476 until we decide what to do.
477
478 public int[] getTagNestingPattern()
479 {
480 int stackSz = tlvStack.size() ;
481 int[] pattern = new int[stackSz+1] ;
482 pattern[stackSz] = tlv.rawTag ;
483
484 for ( int ii = 0; ii < stackSz; ii++ )
485 {
486 pattern[ii] = ( ( Tuple ) tlvStack.get( ii ) ).rawTag ;
487 }
488
489 return pattern ;
490 }
491 */
492
493
494 // ------------------------------------------------------------------------
495 // Methods used for testing
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 }