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.ArrayList;
22 import java.util.Stack;
23
24 import org.apache.asn1.codec.DecoderException;
25 import org.apache.asn1.codec.stateful.CallbackHistory;
26 import org.apache.asn1.codec.stateful.DecoderCallback;
27 import org.apache.asn1.codec.stateful.DecoderMonitor;
28 import org.apache.asn1.codec.stateful.DecoderMonitorAdapter;
29 import org.apache.asn1.codec.stateful.StatefulDecoder;
30
31
32 /***
33 * Builds a TLV tree from the TLV stream emitted from the decoder. The decoded
34 * objects delivered to this StatefulDecoder's DecoderCallback are
35 * DefaultMutableTupleNodes.
36 *
37 * @author <a href="mailto:dev@directory.apache.org">
38 * Apache Directory Project</a>
39 * @version $Rev: 157644 $
40 */
41 public class TupleTreeDecoder implements StatefulDecoder
42 {
43 /*** a stack of nested constructed tuples used to track state */
44 Stack stack = new Stack() ;
45 /*** the underlying BER data stream to TLV stream decoder */
46 BERDecoder decoder = new BERDecoder() ;
47 /*** the callback to use for this StatefulDecoder */
48 DecoderCallback cb = null ;
49 /*** the monitor to use for this StatefulDecoder */
50 DecoderMonitor monitor = new DecoderMonitorAdapter() ;
51 /*** the value chunks buffer collection */
52 ArrayList valueChunks = new ArrayList() ;
53
54
55 /***
56 * Creates a simple BER byte stream to TLV Tuple tree decoder.
57 */
58 public TupleTreeDecoder()
59 {
60 BERDecoderCallback berCallback = new BERDecoderCallback()
61 {
62 public void tagDecoded( Tuple tlv ) { }
63
64 public void partialValueDecoded( Tuple tlv )
65 {
66 ByteBuffer copy = ByteBuffer.allocate(
67 tlv.getLastValueChunk().remaining() ) ;
68 copy.put( tlv.getLastValueChunk() ) ;
69 tlv.getLastValueChunk().rewind() ;
70 copy.rewind() ;
71 valueChunks.add( copy ) ;
72 }
73
74 public void lengthDecoded( Tuple tlv )
75 {
76 if ( ! tlv.isPrimitive )
77 {
78 DefaultMutableTupleNode child = null ;
79 DefaultMutableTupleNode parent = null ;
80 Tuple cloned = ( Tuple ) tlv.clone() ;
81
82 if ( stack.isEmpty() )
83 {
84 stack.push( new DefaultMutableTupleNode( cloned ) ) ;
85 return ;
86 }
87
88 parent = ( DefaultMutableTupleNode ) stack.peek() ;
89 child = new DefaultMutableTupleNode( cloned ) ;
90 child.setParent( parent ) ;
91 parent.addLast( child ) ;
92 stack.push( child ) ;
93 }
94 }
95
96 public void
97 decodeOccurred( StatefulDecoder decoder, Object decoded )
98 {
99 handleTuple( ( Tuple ) decoded ) ;
100 }
101 } ;
102
103 decoder.setCallback( berCallback ) ;
104 decoder.setDecoderMonitor( monitor ) ;
105 }
106
107
108 /***
109 * Handles a tuple recieved from the underlying BER byte stream decoder.
110 *
111 * @param t the tuple to handle
112 */
113 private void handleTuple( Tuple t )
114 {
115 DefaultMutableTupleNode node = null ;
116 DefaultMutableTupleNode parent = null ;
117
118 if ( t.isPrimitive )
119 {
120 node = new DefaultMutableTupleNode( ( Tuple ) t.clone(),
121 valueChunks ) ;
122 valueChunks.clear() ;
123
124 if ( ! stack.isEmpty() )
125 {
126 parent = ( DefaultMutableTupleNode ) stack.peek() ;
127 node.setParent( parent ) ;
128 parent.addLast( node ) ;
129 }
130
131 return ;
132 }
133
134 node = ( DefaultMutableTupleNode ) stack.pop() ;
135
136 if ( cb != null && stack.isEmpty() )
137 {
138 cb.decodeOccurred( this, node ) ;
139 }
140 }
141
142
143
144
145
146
147 public void decode( Object encoded ) throws DecoderException
148 {
149 decoder.decode( encoded ) ;
150 }
151
152
153 /***
154 * Decodes a BER byte buffer into a tree of TLV tuples.
155 *
156 * @param buf the buffer to decode
157 * @return the TLV tuple node with children if applicable
158 * @throws DecoderException if there is a problem decoding the data
159 * @throws java.util.NoSuchElementException if there is not enough data
160 * to properly decode a complete TLV tree
161 */
162 public static TupleNode treeDecode( ByteBuffer buf ) throws DecoderException
163 {
164 TupleTreeDecoder decoder = new TupleTreeDecoder() ;
165 CallbackHistory history = new CallbackHistory( 1 ) ;
166
167 decoder.setCallback( history ) ;
168 decoder.decode( buf ) ;
169
170 if ( history.isEmpty() )
171 {
172 return null ;
173 }
174
175 return ( TupleNode ) history.getMostRecent() ;
176 }
177
178
179
180
181
182
183 public void setCallback( DecoderCallback cb )
184 {
185 this.cb = cb ;
186 }
187
188
189
190
191
192
193 public void setDecoderMonitor( DecoderMonitor monitor )
194 {
195 this.monitor = monitor ;
196 decoder.setDecoderMonitor( monitor ) ;
197 }
198 }