ASN1C supports a variety of methods for printing output: standard output, print-to-string, and print-to-stream. The latter methods are popular with customers who integrate our output with their logging tools. We have often recommended that users avoid print-to-string methods because they are generally quite inefficient, despite improvements that help to minimize expensive string operations. strlen in particular is expensive, and the print-to-string methods rely on it quite heavily to avoid buffer overflows.
It is possible to implement efficient print-to-string methods using the print-to-stream interface in ASN1C. Print-to-stream works by allowing users to register a call-back function declared like this:
void (*rtxPrintCallback)
   (void* pPrntStrmInfo, const char* fmtspec, va_list arglist);
A simple print-to-file function might look like this:
void writeToStdout(void* pPrntStrmInfo, const char* fmtspec, va_list arglist) {
   FILE *fp = (FILE *)pPrntStrmInfo;
   vfprintf(fp, fmtspec, arglist);
}
By way of reference, the sample implementation for outputting to a file is available in our documentation. Users are encouraged to consult the documentation for more details, particularly in how to integrate the function with their applications.
A naive implementation of writeToString might look like this:
void writeToString(void* pPrntStrmInfo, const char* fmtspec, va_list arglist) {
   char *dest = (char *)pPrntStrmInfo, buf[1024];
   vsnprintf (buf, sizeof(buf), fmtspec, arglist);
   strncat (dest, buf, sizeof(buf));
}
Problematically, the implementation does not check the size of the destination buffer to ensure that it’s large enough to hold the string, so buffer overflows can occur. Unfortunately, string functions aren’t very helpful (strlen, for example, will not report the size of a character buffer), so it is wise to create a data structure that holds both the string and its allocated length. This will greatly speed up string concatenation and avoid length checks. C++ users can use std::string instead, so typical string methods (like length, reserve and append) may be used as well.
Another possibility is to create a print handler. By passing -events on the command line, ASN1C will generate SAX-like handlers that fire during decode. Implementing an event hander is usually a little more complicated than using a print to stream function, but has the advantage that the events fire during decode instead of after, which can improve efficiency. We provide several reference implementations in our SDK download that print using our typical “brace text” format as well as XML. An annotated brace-text implementation is available in our documentation. The event handler is considerably more flexible than print-to-stream functions and is advisable for users who want to customize the output format or avoid the use of a variadic function.

Published

Category

ASN1C

Tags