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.awt.BorderLayout;
21 import java.awt.Dimension;
22 import java.awt.Toolkit;
23 import java.awt.event.ActionEvent;
24 import java.awt.event.ActionListener;
25 import java.awt.event.WindowEvent;
26 import java.io.ByteArrayOutputStream;
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileNotFoundException;
30 import java.io.IOException;
31 import java.nio.ByteBuffer;
32 import java.util.Enumeration;
33
34 import javax.swing.JFileChooser;
35 import javax.swing.JFrame;
36 import javax.swing.JLabel;
37 import javax.swing.JMenu;
38 import javax.swing.JMenuBar;
39 import javax.swing.JMenuItem;
40 import javax.swing.JPanel;
41 import javax.swing.JScrollPane;
42 import javax.swing.JSplitPane;
43 import javax.swing.JTextArea;
44 import javax.swing.JTextField;
45 import javax.swing.JTree;
46 import javax.swing.event.TreeSelectionEvent;
47 import javax.swing.event.TreeSelectionListener;
48 import javax.swing.tree.DefaultTreeModel;
49 import javax.swing.tree.TreeNode;
50 import javax.swing.tree.TreePath;
51
52 import org.apache.asn1.ber.primitives.PrimitiveUtils;
53 import org.apache.asn1.ber.primitives.UniversalTag;
54 import org.apache.asn1.codec.DecoderException;
55 import org.apache.asn1.codec.binary.Hex;
56 import org.apache.asn1.codec.stateful.CallbackHistory;
57 import org.apache.commons.collections.IteratorUtils;
58
59
60 /***
61 * Simple JTree view of a tuple tree.
62 *
63 * @author <a href="mailto:dev@directory.apache.org">
64 * Apache Directory Project</a>
65 * @version $Rev: 157644 $
66 */
67 public class TupleTreeAnalyzer extends JFrame implements TreeSelectionListener
68 {
69 private boolean doVmExit = false;
70 private BorderLayout layout = new BorderLayout();
71 private JLabel statusBar = new JLabel("Ready");
72 private JSplitPane jSplitPane1 = new JSplitPane();
73 private JScrollPane jScrollPane1 = new JScrollPane();
74 private JPanel jPanel1 = new JPanel();
75 private JTree jTree1 = new JTree();
76 private JPanel jPanel2 = new JPanel();
77 private JPanel jPanel5 = new JPanel();
78 private JPanel jPanel3 = new JPanel();
79 private JPanel jPanel4 = new JPanel();
80 private JLabel jLabel1 = new JLabel();
81 private JLabel jLabel3 = new JLabel();
82 private JLabel jLabel2 = new JLabel();
83 private JScrollPane jScrollPane2 = new JScrollPane();
84 private JTextArea jTextArea1 = new JTextArea();
85 private JTextField jTextField1 = new JTextField();
86 private JTextField jTextField3 = new JTextField();
87 private JTextField jTextField2 = new JTextField();
88
89 private DefaultMutableTupleNode root = null ;
90
91
92 /*** Creates new form JFrame */
93 public TupleTreeAnalyzer( DefaultMutableTupleNode root )
94 {
95 this.root = root ;
96
97 initGUI() ;
98 pack() ;
99 }
100
101
102 /*** Creates new form JFrame */
103 public TupleTreeAnalyzer( DefaultMutableTupleNode root, boolean doVmExit )
104 {
105 this.root = root ;
106 this.doVmExit = doVmExit;
107
108 initGUI() ;
109 pack() ;
110 }
111
112
113 public TupleTreeAnalyzer( byte[] encoded ) throws DecoderException
114 {
115 this( ByteBuffer.wrap( encoded ) );
116 }
117
118
119 public TupleTreeAnalyzer( ByteBuffer encoded ) throws DecoderException
120 {
121 TupleTreeDecoder decoder = new TupleTreeDecoder();
122 CallbackHistory history = new CallbackHistory();
123 decoder.setCallback( history );
124 decoder.decode( encoded.duplicate() );
125 root = ( DefaultMutableTupleNode ) history.getMostRecent();
126
127 initGUI();
128 pack();
129 }
130
131
132 public TupleTreeAnalyzer( ByteBuffer[] encoded ) throws DecoderException
133 {
134 TupleTreeDecoder decoder = new TupleTreeDecoder();
135 CallbackHistory history = new CallbackHistory();
136 decoder.setCallback( history );
137
138 for ( int ii = 0; ii < encoded.length; ii++ )
139 {
140 decoder.decode( encoded[ii].duplicate() );
141 }
142
143 root = ( DefaultMutableTupleNode ) history.getMostRecent();
144
145 initGUI();
146 pack();
147 }
148
149
150 /*** This method is called from within
151 * the constructor to initialize the form. */
152 private void initGUI() {
153
154 getContentPane().setLayout(layout);
155 JPanel content = new JPanel();
156 content.setPreferredSize(new Dimension(300, 200));
157 getContentPane().add(content, BorderLayout.CENTER);
158
159 setTitle("");
160
161 getContentPane().add(statusBar, BorderLayout.SOUTH);
162
163 JMenuBar menuBar = new JMenuBar();
164 JMenu menuFile = new JMenu("File");
165 menuFile.setMnemonic('F');
166
167 JMenuItem fileExit = new JMenuItem("Exit");
168 fileExit.setMnemonic('E');
169 fileExit.addActionListener(
170 new ActionListener() {
171 public void actionPerformed(ActionEvent e) {
172 if ( doVmExit )
173 {
174 System.exit(0);
175 }
176 }
177 });
178
179 JMenu menuHelp = new JMenu("Help");
180 menuHelp.setMnemonic('H');
181 JMenuItem helpAbout = new JMenuItem("About");
182 helpAbout.setMnemonic('A');
183 helpAbout.addActionListener(
184 new ActionListener() {
185 public void actionPerformed(ActionEvent e) {
186 }
187 });
188 menuHelp.add(helpAbout);
189
190 final JFileChooser fc = new JFileChooser();
191 JMenuItem openFile = new JMenuItem("Open");
192 openFile.setMnemonic('O');
193 openFile.addActionListener(
194 new java.awt.event.ActionListener() {
195 public void actionPerformed(java.awt.event.ActionEvent e) {
196 int returnVal = fc.showOpenDialog(TupleTreeAnalyzer.this);
197 if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION) {
198
199
200 } else {
201
202 }
203 }
204 });
205 menuFile.add(openFile);
206
207 JMenuItem saveFile = new JMenuItem("Save");
208 saveFile.setMnemonic('S');
209 saveFile.addActionListener(
210 new java.awt.event.ActionListener() {
211 public void actionPerformed(java.awt.event.ActionEvent e) {
212 int returnVal = fc.showSaveDialog(TupleTreeAnalyzer.this);
213 if (returnVal == JFileChooser.APPROVE_OPTION) {
214
215
216 } else {
217
218 }
219 }
220 });
221 menuFile.add(saveFile);
222
223 JMenuItem print = new JMenuItem("Print");
224 print.setMnemonic('P');
225 print.addActionListener(
226 new java.awt.event.ActionListener() {
227 public void actionPerformed(java.awt.event.ActionEvent e) {
228 hexDumpTupleTree();
229 }
230 }); menuFile.add(print);
231 menuFile.add(fileExit);
232 menuBar.add(menuFile);
233 menuBar.add(menuHelp);
234
235 setJMenuBar(menuBar);
236 addWindowListener(
237 new java.awt.event.WindowAdapter() {
238 public void windowClosing(java.awt.event.WindowEvent evt) {
239 exitForm(evt);
240 }
241 });
242
243
244 jLabel3.setText("Type Class:");
245 jPanel5.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
246 jPanel5.add(jLabel3);
247 jPanel5.add(jTextField3);
248 jTextField3.setText("");
249 jTextField3.setMinimumSize(new java.awt.Dimension(184, 25));
250 jTextField3.setPreferredSize(new java.awt.Dimension(184, 25));
251 jSplitPane1.setLastDividerLocation(50);
252 jSplitPane1.setDividerLocation(180);
253 jSplitPane1.add(jScrollPane1, javax.swing.JSplitPane.LEFT);
254 jSplitPane1.add(jPanel1, javax.swing.JSplitPane.RIGHT);
255 addWindowListener(
256 new java.awt.event.WindowAdapter() {
257 public void windowClosing(java.awt.event.WindowEvent evt) {
258 exitForm(evt);
259 }
260 });
261 getContentPane().add(jSplitPane1, java.awt.BorderLayout.CENTER);
262 jScrollPane1.getViewport().add(jTree1);
263 jTree1.setBounds(new java.awt.Rectangle(95,95,85,84));
264 jTree1.setShowsRootHandles(true);
265 jPanel1.setLayout(new java.awt.GridBagLayout());
266 jPanel1.add(jPanel2,
267 new java.awt.GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
268 java.awt.GridBagConstraints.WEST,
269 java.awt.GridBagConstraints.HORIZONTAL,
270 new java.awt.Insets(0, 9, 0, 9), 0, 0));
271 jPanel1.add(jPanel3,
272 new java.awt.GridBagConstraints(0, 1, 1, 1, 1.0, 1.0,
273 java.awt.GridBagConstraints.WEST,
274 java.awt.GridBagConstraints.HORIZONTAL,
275 new java.awt.Insets(0, 9, 0, 9), 0, 0));
276 jPanel1.add(jPanel4,
277 new java.awt.GridBagConstraints(0, 3, 1, 35, 1.0, 1.0,
278 java.awt.GridBagConstraints.CENTER,
279 java.awt.GridBagConstraints.BOTH,
280 new java.awt.Insets(9, 12, 9, 12), 0, 0));
281 jPanel1.add(jPanel5,
282 new java.awt.GridBagConstraints(0, 2, 1, 1, 1.0, 1.0,
283 java.awt.GridBagConstraints.WEST,
284 java.awt.GridBagConstraints.HORIZONTAL,
285 new java.awt.Insets(0, 9, 0, 9), 0, 0));
286 jLabel1.setText("Tag Id:");
287 jPanel2.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
288 jPanel2.add(jLabel1);
289 jPanel2.add(jTextField1);
290 jLabel2.setText("Length:");
291 jPanel3.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
292 jPanel3.add(jLabel2);
293 jPanel3.add(jTextField2);
294 jPanel4.setLayout(new java.awt.BorderLayout());
295 jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder(
296 javax.swing.BorderFactory.createLineBorder(
297 new java.awt.Color(153, 153, 153), 1), "Value",
298 javax.swing.border.TitledBorder.LEADING,
299 javax.swing.border.TitledBorder.TOP,
300 new java.awt.Font("Comic Sans MS", 0, 14),
301 new java.awt.Color(60, 60, 60)));
302 jPanel4.add(jScrollPane2, java.awt.BorderLayout.CENTER);
303 jTextArea1.setText("");
304 jScrollPane2.getViewport().add(jTextArea1);
305 jTextField1.setText("");
306 jTextField1.setMinimumSize(new java.awt.Dimension(164, 25));
307 jTextField1.setPreferredSize(new java.awt.Dimension(164, 25));
308 jTextField1.setEditable(true);
309 jTextField2.setText("");
310 jTextField2.setPreferredSize(new java.awt.Dimension(164,25));
311 jTextField2.setMinimumSize(new java.awt.Dimension(164,25));
312 jTextField2.setEditable(true);
313 jScrollPane2.setVerticalScrollBarPolicy(
314 javax.swing.JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
315 jScrollPane2.setHorizontalScrollBarPolicy(
316 javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
317 jScrollPane2.setBorder(null);
318
319 jTree1.setModel( new DefaultTreeModel(
320 new TupleTreeNodeAdapter( root ) ) );
321 jTree1.getSelectionModel().addTreeSelectionListener( this );
322 }
323
324 private void hexDumpTupleTree()
325 {
326 }
327
328 /*** Exit the Application */
329 private void exitForm(WindowEvent evt)
330 {
331 System.out.println( "Closed window: " + evt.getWindow().getName() );
332
333 if ( doVmExit )
334 {
335 System.exit(0);
336 }
337 }
338
339
340 public void startup()
341 {
342 setSize( 800, 640 ) ;
343 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
344 Dimension frameSize = getSize();
345 frameSize.height = ((frameSize.height > screenSize.height)
346 ? screenSize.height : frameSize.height);
347 frameSize.width = ((frameSize.width > screenSize.width)
348 ? screenSize.width : frameSize.width);
349 setLocation((screenSize.width - frameSize.width) / 2,
350 (screenSize.height - frameSize.height) / 2);
351 setVisible(true);
352 }
353
354
355 public void valueChanged( TreeSelectionEvent e )
356 {
357 TreePath path = e.getPath();
358 TupleTreeNodeAdapter node = ( TupleTreeNodeAdapter )
359 path.getLastPathComponent();
360 TupleNode tn = node.getTupleNode();
361 Tuple tuple = tn.getTuple();
362
363 TypeClass type = TypeClass.getTypeClass( tuple.getRawTag() >> 24 );
364 jTextField3.setText( type.getName() );
365
366
367 if ( tuple.getLength() == Length.INDEFINITE )
368 {
369 jTextField2.setText( "INDEFINITE" );
370 }
371 else
372 {
373 jTextField2.setText( Integer.toString( tuple.getLength() ) );
374 }
375
376 if ( type.equals( TypeClass.UNIVERSAL ) )
377 {
378 UniversalTag tag = UniversalTag.getUniversalTag( tuple.getRawTag() );
379 jTextField1.setText( tag.getName() );
380 }
381 else
382 {
383 jTextField1.setText( Integer.toString( tuple.getId() ) );
384 }
385
386 if ( tuple.isPrimitive() )
387 {
388 ByteBuffer buf = ( ByteBuffer ) tuple.getLastValueChunk().rewind();
389 byte[] bites = new byte[buf.remaining()];
390 buf.get( bites );
391
392 jTextArea1.setText( new String( Hex
393 .encodeHex( bites ) ) );
394
395 if ( type == TypeClass.UNIVERSAL )
396 {
397 UniversalTag tag = UniversalTag
398 .getUniversalTag( tuple.getRawTag() );
399
400 if ( tag == UniversalTag.ENUMERATED ||
401 tag == UniversalTag.INTEGER )
402 {
403 int ii = PrimitiveUtils.decodeInt( bites, 0, bites.length );
404 jTextArea1.setToolTipText( "Numeric: "
405 + Integer.toString( ii ) );
406 }
407 else if ( tag == UniversalTag.BOOLEAN )
408 {
409 boolean bool = PrimitiveUtils.berDecodeBoolean( bites[0] );
410 jTextArea1.setToolTipText( "Boolean: "
411 + Boolean.toString( bool ) );
412 }
413 else
414 {
415 jTextArea1.setToolTipText( "String: "
416 + new String( bites ) );
417 }
418 }
419 else
420 {
421 if ( bites.length > 4 )
422 {
423 jTextArea1.setToolTipText( "String: "
424 + new String( bites ) );
425 return;
426 }
427
428 int ii = PrimitiveUtils.decodeInt( bites, 0, bites.length );
429 boolean bool = PrimitiveUtils.berDecodeBoolean( bites[0] );
430 String tip = "Numeric: " + Integer.toString( ii ) + "\n";
431 tip += "Boolean: " + Boolean.toString( bool ) + "\n";
432 tip += "String: " + new String( bites ) ;
433 jTextArea1.setToolTipText( tip );
434 }
435 }
436 else
437 {
438 jTextArea1.setText( "N/A" );
439 jTextArea1.setToolTipText( null );
440 }
441 }
442
443
444 /***
445 * Gets a hexDump of a direct buffer without affecting the buffer. Used
446 * for primitive analysis especially when direct memory buffers are used
447 * which cannot be easily inspected within debuggers.
448 *
449 * @param buf the buffer to generate a hex dump for
450 * @return a hex string representing the buffer
451 */
452 public static String getHexDump( ByteBuffer buf )
453 {
454 byte[] bites = new byte[buf.remaining()];
455 buf.duplicate().get( bites );
456 return new String( Hex.encodeHex( bites ) );
457 }
458
459
460 public static void analyze( byte[] bites ) throws DecoderException
461 {
462 TupleTreeAnalyzer analyzer = new TupleTreeAnalyzer( bites );
463 analyzer.startup();
464 }
465
466
467 public static void analyze( ByteBuffer bites ) throws DecoderException
468 {
469 TupleTreeAnalyzer analyzer = new TupleTreeAnalyzer( bites );
470 analyzer.startup();
471 }
472
473 class TupleTreeNodeAdapter implements TreeNode
474 {
475 DefaultMutableTupleNode node;
476
477
478 TupleTreeNodeAdapter( DefaultMutableTupleNode node )
479 {
480 this.node = node;
481 }
482
483
484 public int getChildCount()
485 {
486 return node.getChildCount();
487 }
488
489 public boolean getAllowsChildren()
490 {
491 return !node.getTuple().isPrimitive();
492 }
493
494 public boolean isLeaf()
495 {
496 return node.getChildCount() == 0;
497 }
498
499 public Enumeration children()
500 {
501 return IteratorUtils.asEnumeration( node.getChildren() );
502 }
503
504 public TreeNode getParent()
505 {
506 return new TupleTreeNodeAdapter( ( DefaultMutableTupleNode )
507 node.getParentTupleNode() );
508 }
509
510 public TreeNode getChildAt( int childIndex )
511 {
512 return new TupleTreeNodeAdapter( ( DefaultMutableTupleNode )
513 node.getChildTupleNodeAt( childIndex ) );
514 }
515
516 public int getIndex( TreeNode node )
517 {
518 DefaultMutableTupleNode tn =
519 ( ( TupleTreeNodeAdapter ) node ).getTupleNode();
520 return this.node.getIndex( tn );
521 }
522
523 DefaultMutableTupleNode getTupleNode()
524 {
525 return node;
526 }
527
528 public String toString()
529 {
530 StringBuffer buf = new StringBuffer();
531 Tuple tuple = node.getTuple();
532 TypeClass type =
533 TypeClass.getTypeClass( node.getTuple().getRawTag() >> 24 );
534 int id = Tag.getTagId( tuple.getRawTag() );
535
536 buf.append( "[" ).append( type.getName() ).append( "][" )
537 .append( id ).append( "]" ).append( "[" )
538 .append( tuple.getLength() ).append( "]" );
539
540 return buf.toString();
541 }
542
543 }
544
545
546 public static void main( String [] args )
547 {
548 JFileChooser fc = new JFileChooser( "." );
549 fc.setFileFilter( new javax.swing.filechooser.FileFilter()
550 {
551 public boolean accept( File f )
552 {
553 return f.isDirectory() || f.getName().endsWith( ".ber" );
554 }
555
556 public String getDescription()
557 {
558 return "BER encoded data files";
559 }
560 }
561 );
562 fc.showOpenDialog( null );
563 File file = fc.getSelectedFile();
564
565 if ( file == null )
566 {
567 System.exit( 0 );
568 }
569
570 FileInputStream in = null;
571
572 try
573 {
574 in = new FileInputStream( file );
575 }
576 catch ( FileNotFoundException e )
577 {
578 e.printStackTrace();
579 System.exit( -1 );
580 }
581
582 ByteArrayOutputStream out = new ByteArrayOutputStream();
583 try
584 {
585 int ch = -1;
586 while( ( ch = in.read() ) != -1 )
587 {
588 out.write( ch );
589 }
590 }
591 catch ( IOException e )
592 {
593 e.printStackTrace();
594 System.exit( -1 );
595 }
596
597 TupleTreeAnalyzer analyzer;
598 try
599 {
600 analyzer = new TupleTreeAnalyzer( out.toByteArray() );
601 analyzer.startup();
602 }
603 catch ( DecoderException e )
604 {
605 e.printStackTrace();
606 System.exit( -1 );
607 }
608 }
609 }