Example 1: A Formatted Print Handler

The ASN1C evaluation and distribution kits include a sample program for doing a formatted print of parsed data. This code can be found in the csharp/sample_ber/EventHandler directory. Parts of the code will be reproduced here for reference, but refer to this directory to see the full implementation.

The format for the printout will be simple. Each element name will be printed followed by an equal sign (=) and an open brace ({) and newline. The value will then be printed followed by another newline. Finally, a closing brace (}) followed by another newline will terminate the printing of the element. An indentation count will be maintained to allow for a properly indented printout.

We will first create a class called PrintHandler that implements the Asn1NamedEventHandler interface and handles the formatted printing of the data. The rule for the implementation of interfaces is that you must provide an implementation for each of the methods listed. That is it. You can add as many additional methods, member variables, etc., that you like.

The PrintHandler implementation that we created is as follows:

   class PrintHandler : Asn1NamedEventHandler {
      protected string mVarName;
      protected int mIndentSpaces = 0;

      public PrintHandler (string varName) {
         mVarName = varName;
         System.Console.Out.WriteLine (mVarName + " = {");
         mIndentSpaces += 3;
      }

      public void StartElement (string name, int index) {
         Indent();
         System.Console.Out.Write (name);
         if (index >= 0)
            System.Console.Out.Write ("[" + index + "]");
         System.Console.Out.WriteLine (" = {");
         mIndentSpaces += 3;
      }

      public void EndElement (string name, int index) {
         mIndentSpaces -= 3;
         Indent ();
         System.Console.Out.WriteLine ("}");
      }

      public void Characters (string svalue, short typeCode) {
         Indent ();
         System.Console.Out.WriteLine (svalue);
      }

      private void Indent () {
         for (int i = 0; i < mIndentSpaces; i++)
            System.Console.Out.Write (" ");
      }
   }

In this definition, we chose to add the mVarName and mIndentSpaces member variables to keep track of these items. The user is free to add any type of member variables he or she wants. The only firm requirement in defining this class is the implementation of the methods defined in the interface.

We implement these methods as follows:

In StartElement, we print the name, equal sign, and opening brace:

   public void StartElement (string name, int index) {
      Indent();
      System.Console.Out.Write (name);
      if (index >= 0)
         System.Console.Out.Write ("[" + index + "]");
      System.Console.Out.WriteLine (" = {");
      mIndentSpaces += 3;
   }

In this simplified implementation, we simply indent (this is another private method within the class) and print out the name, equal sign, and opening brace. We then increment the indent level. Logic is also present to check the index value to see if it is zero or greater. If it is, an array subscript is added to the element name.

In EndElement, we simply terminate our brace block as follows:

   public void EndElement (string name, int index) {
      mIndentSpaces -= 3;
      Indent ();
      System.Console.Out.WriteLine ("}");
   }

The Characters method simply indents and prints the stringified value:

   public void Characters (string svalue, short typeCode) {
      Indent ();
      System.Console.Out.WriteLine (svalue);
   }

That completes the PrintHandler class implementation.

Next, we need to create an object of the class and register it prior to invoking the decode method. In the Reader.cs program, the following lines do this:

   // Register event handler object

   PrintHandler printHandler = new PrintHandler ("personnelRecord");
   decodeBuffer.AddNamedEventHandler (printHandler);

The addEventHandler method defined in the Asn1DecodeBuffer base class is the mechanism used to do this. Note that event handler objects can be stacked. Several can be registered before invoking the decode function. When this is done, the entire list of event handler objects is iterated through and the appropriate event handling callback function invoked whenever a defined event is encountered.

The implementation is now complete. The program can now be compiled and run. When this is done, the resulting output is as follows:

   employee = {
      name = {
         givenName = {
            "John"
         }
         initial = {
            "P"
         }
         familyName = {
            "Smith"
         }
      }
      ...

This can certainly be improved. For one thing it can be changed to print primitive values out in a “name = value” format (i.e., without the braces). But this should provide the general idea of how it is done.