View Javadoc

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.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         // set title
159         setTitle("");
160         // add status bar
161         getContentPane().add(statusBar, BorderLayout.SOUTH);
162         // add menu bar
163         JMenuBar menuBar = new JMenuBar();
164         JMenu menuFile = new JMenu("File");
165         menuFile.setMnemonic('F');
166         // create Exit menu item
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         // create About menu item
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         // create Open menu item
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                         //java.io.File file = fc.getSelectedFile();
199                         // Write your code here what to do with selected file
200                     } else {
201                         // Write your code here what to do if user has canceled
202                     }
203                 }
204             });
205         menuFile.add(openFile);
206         // create Save menu item
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                         //java.io.File file = fc.getSelectedFile();
215                         // Write your code here what to do with selected file
216                     } else {
217 // Write your code here what to do if user has canceled Save dialog
218                     }
219                 }
220             });
221         menuFile.add(saveFile);
222         // create Print menu item
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         // sets menu bar
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 }