Putting the Code Together
Listing 7 illustrates the parser class.
Listing 7 Base Parser Class
class ParseAnyDataType { public: virtual ~ParseAnyDataType() {}; virtual void ParseData() {}; protected: ParseAnyDataType() {}; };
Listing 8 illustrates the subclass of ParseAnyDataType.
Listing 8 Main ASN.1 Parser Class
class ParseDataStream : ParseAnyDataType { public: explicit ParseDataStream(const char * dataSet); ~ParseDataStream() { } void parseAsnElement(const char * dataSet, int * offset, int elementLength, int overallLength); // Recursive member function void echoDataStream(const char * dataSet, int offset); };
The constructor for the class ParseDataStream is illustrated in Listing 9.
Listing 9 Main Parser Constructor
ParseDataStream::ParseDataStream(const char * dataSet) { int offset = 0; printf("Making the first call to parseAsnElement()\n"); parseAsnElement(dataSet, &offset, dataSet[1], strlen(dataSet)); }
The code in Listing 9 starts the recursive processing of the ASN.1 data. The parseAsnElement() member function is called by each of the individual parsers (Listings 3–6). I mentioned at the beginning that using recursion can help produce elegant solutions. Recursion has an interesting characteristic that I’ve never seen discussed: it is a type of reuse. In effect, when you call a method recursively—as in the case of parseAsnElement()—you are reusing the code, which can facilitate a certain economy in the solution. Take a look at Listing 10 to see the complete source code for the parseAsnElement()method.
Listing 10 Recursive Member Function—parseAsnElement()
void ParseDataStream::parseAsnElement(const char * dataSet, int * offset, int elementLength, int overallLength) { char dataSetType; int i; while (*offset < overallLength - 1) { dataSetType = dataSet[*offset]; elementLength = dataSet[*offset + 1]; switch (dataSetType) { case SEQ_CLASS: *offset += 2; parseAsnElement(dataSet, offset, elementLength, overallLength); break; case INT_CLASS: for (i = *offset + 2; i <= *offset + elementLength + 1; i++) printf("%x", dataSet[i]); printf("\n"); *offset += 4; parseAsnElement(dataSet, offset, elementLength, overallLength); break; case STR_CLASS: printf("String character "); for (i = *offset + 2; i <= *offset + elementLength + 1; i++) printf("%c", dataSet[i]); printf("\n\n"); *offset += elementLength + 1; parseAsnElement(dataSet, offset, elementLength, overallLength); break; default: printf("Unknown type\n"); break; } } }
I think Listing 10 achieves a lot for such a small amount of code! (Please see the "Additional Reading" section for the complete source code.) If you want to execute the code, just drop the two files into a Microsoft Visual C++ console project, build and run.