blob: cdcd3ee9e0e6c9812748fc9211fb086ad4ac6c82 [file] [log] [blame]
\batchmode
\documentclass[english,oneside,12pt]{book}
\usepackage[no-math]{fontspec}
\usepackage{MnSymbol}
\usepackage{xunicode}
\usepackage{xltxtra}
\usepackage[hmargin={1in,1in},vmargin={1.5in,1.5in}]{geometry}
\defaultfontfeatures{Mapping=tex-text}
\setmainfont{PT Sans}
\setsansfont{PT Sans}
\setmonofont{Consolas}
\usepackage{fancyhdr}
\usepackage{fancyref}
\usepackage{longtable}
\usepackage{array}
\usepackage{enumitem}
\usepackage{booktabs}
\usepackage{url}
\usepackage{xcolor}
\usepackage{listings}
\usepackage{setspace}
\usepackage{unicode-math}
\usepackage{perpage}
\MakePerPage{footnote}
\setstretch{1.1}
% Courier 10 Pitch
\def\courierFont{Courier10 BT WGL4}
%\def\courierFont{Consolas}
\setmonofont[Scale=1.05]{\courierFont}
\setmathfont[Scale=1.05]{Cambria Math}
\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
\lstloadlanguages{C,bash}
\newfontfamily\listingfont[Scale=1.05]{\courierFont}
\newfontfamily\inlinelistingfont[Scale=1.05]{\courierFont}
\definecolor{clrlcomment}{gray}{0.3}
\definecolor{clrlkeyword}{rgb}{0.588,0.145,0.18}
\newcommand{\listingkeyword}[1]{\color{clrlkeyword}{#1}}
\newcommand{\listingstring}[1]{\color{clrlcomment}{#1}}
\newcommand{\listingcomment}[1]{\color{clrlcomment}{#1}}
\lstset{tabsize=4,
showstringspaces=false,
showtabs=false,
showspaces=false,
keywordstyle=\listingkeyword,
stringstyle=\listingstring,
commentstyle=\listingcomment,
xleftmargin=\parindent,
columns=fixed,
escapechar=\%,
texcl
}
\lstdefinestyle{listingStyle}{
basicstyle=\small\listingfont,
stringstyle=\listingstring,
breaklines=true,
breakatwhitespace=true,
flexiblecolumns=false
}
\lstdefinelanguage{asn1}{
morekeywords={DEFINITIONS,BEGIN,END,AUTOMATIC,TAGS,SEQUENCE,SET,OF,CHOICE,OPTIONAL,INTEGER,MAX},
morecomment=[l]{--},
morecomment=[n]{/*}{*/}
}
\lstnewenvironment{signature}[1][]{\lstset{style=listingStyle,language=C,xleftmargin=0pt,#1}}{}
\lstnewenvironment{example}[1][]{\lstset{style=listingStyle,language=C,basicstyle=\scriptsize\listingfont,#1}}{}
\lstnewenvironment{codesample}[1][]{\lstset{style=listingStyle,language=C,#1}}{}
\lstnewenvironment{bash}[1][]{\lstset{style=listingStyle,language=bash,#1}}{}
\lstnewenvironment{asn}[1][]{\lstset{style=listingStyle,language=asn1,#1}}{}
\newcommand{\apisection}[2]{\clearpage\section{\label{#1}#2}}
\newcommand{\api}[2]{\hyperref[#1]{\code{#2}}}
\newcommand{\seealso}[2]{\api{#1}{#2} at page \pageref{#1}}
\newcommand{\code}[1]{\texttt{\textbf{\lstinline{#1}}}}
\newcommand{\cmd}[1]{\texttt{#1}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.
\usepackage{extramarks}
\lhead{\firstxmark}
\rfoot{\lastxmark}
\definecolor{clrlink}{rgb}{0,0.4,0}
\definecolor{clrurl}{rgb}{0,0,.6}
\usepackage[colorlinks=true,
linkcolor={clrlink},
citecolor={clrlink},
urlcolor={clrurl},
pdfauthor={Lev Walkin},
pdftitle={Using the Open Source ASN.1 Compiler},
pdfkeywords={ASN.1,asn1c,compiler},
bookmarksopen,bookmarksopenlevel=1,
pdffitwindow,
xetex
]{hyperref}
\makeatother
\usepackage{babel}
\begin{document}
\title{Using the Open Source ASN.1 Compiler\\
\vspace*{0.4cm}
\Large Documentation for asn1c version \asnver{}}
\author{Lev Walkin <\href{mailto:vlm@lionet.info?Subject=asn1c}{vlm@lionet.info}>}
\pagestyle{fancy}
\fancyhead[L]{\leftmark}
\fancyhead[R]{\href{http://lionet.info/asn1c}{asn1c-\asnver}}
\maketitle
\tableofcontents{}
\chapter{\label{chap:Quick-start-examples}Quick start examples}
\section{A “Rectangle” converter and debugger}
One of the most common need is to create some sort of analysis tool
for the existing ASN.1 data files. Let's build a converter for existing
Rectangle binary files between BER, OER, PER, and XER (XML).
\begin{enumerate}
\item Create a file named \textbf{rectangle.asn} with the following contents:
\begin{asn}
RectangleModule DEFINITIONS ::= BEGIN
Rectangle ::= SEQUENCE {
height INTEGER,
width INTEGER
}
END
\end{asn}
\item Compile it into the set of .c and .h files using \cmd{asn1c} compiler:
\begin{bash}
asn1c -no-gen-example %\textbf{rectangle.asn}%
\end{bash}
\item Create the converter and dumper:
\begin{bash}
make -f Makefile.am.example
\end{bash}
\item Done. The binary file converter is ready:
\begin{bash}
./converter-example -h
\end{bash}
\end{enumerate}
\section{A “Rectangle” Encoder}
This example will help you create a simple BER and XER encoder of
a ``Rectangle'' type used throughout this document.
\begin{enumerate}
\item Create a file named \textbf{rectangle.asn} with the following contents:
\begin{asn}
RectangleModule DEFINITIONS ::= BEGIN
Rectangle ::= SEQUENCE {
height INTEGER,
width INTEGER
}
END
\end{asn}
\item Compile it into the set of .c and .h files using asn1c compiler \cite{ASN1C}:
\begin{bash}
asn1c -no-gen-example %\textbf{rectangle.asn}%
\end{bash}
\item Alternatively, use the Online ASN.1 compiler \cite{AONL} by uploading
the \textbf{rectangle.asn} file into the Web form and unpacking the
produced archive on your computer.
\item By this time, you should have gotten multiple files in the current
directory, including the \textbf{Rectangle.c} and \textbf{Rectangle.h}.
\item Create a main() routine which creates the Rectangle\_t structure in
memory and encodes it using BER and XER encoding rules. Let's name
the file \textbf{main.c}:
\begin{example}
#include <stdio.h>
#include <sys/types.h>
#include <Rectangle.h> /* Rectangle ASN.1 type */
/* Write the encoded output into some FILE stream. */
static int write_out(const void *buffer, size_t size, void *app_key) {
FILE *out_fp = app_key;
size_t wrote = fwrite(buffer, 1, size, out_fp);
return (wrote == size) ? 0 : -1;
}
int main(int ac, char **av) {
Rectangle_t *rectangle; /* Type to encode */
asn_enc_rval_t ec; /* Encoder return value */
/* Allocate the Rectangle_t */
rectangle = calloc(1, sizeof(Rectangle_t)); /* not malloc! */
if(!rectangle) {
perror("calloc() failed");
exit(1);
}
/* Initialize the Rectangle members */
rectangle->height = 42; /* any random value */
rectangle->width = 23; /* any random value */
/* BER encode the data if filename is given */
if(ac < 2) {
fprintf(stderr, "Specify filename for BER output\n");
} else {
const char *filename = av[1];
FILE *fp = fopen(filename, "wb"); /* for BER output */
if(!fp) {
perror(filename);
exit(1);
}
/* Encode the Rectangle type as BER (DER) */
ec = der_encode(&asn_DEF_Rectangle, rectangle, write_out, fp);
fclose(fp);
if(ec.encoded == -1) {
fprintf(stderr, "Could not encode Rectangle (at %\%%s)\n",
ec.failed_type ? ec.failed_type->name : "unknown");
exit(1);
} else {
fprintf(stderr, "Created %\%%s with BER encoded Rectangle\n", filename);
}
}
/* Also print the constructed Rectangle XER encoded (XML) */
xer_fprint(stdout, &asn_DEF_Rectangle, rectangle);
return 0; /* Encoding finished successfully */
}
\end{example}
\item Compile all files together using C compiler (varies by platform):
\begin{bash}
cc -I. -o %\textbf{\emph{rencode}} \emph{*.c}%
\end{bash}
\item Done. You have just created the BER and XER encoder of a Rectangle
type, named \textbf{rencode}!
\end{enumerate}
\section{\label{sec:A-Rectangle-Decoder}A “Rectangle” Decoder}
This example will help you to create a simple BER decoder of a simple
``Rectangle'' type used throughout this document.
\begin{enumerate}
\item Create a file named \textbf{rectangle.asn} with the following contents:
\begin{asn}
RectangleModule DEFINITIONS ::= BEGIN
Rectangle ::= SEQUENCE {
height INTEGER,
width INTEGER
}
END
\end{asn}
\item Compile it into the set of .c and .h files using asn1c compiler \cite{ASN1C}:
\begin{bash}
asn1c -no-gen-example %\textbf{rectangle.asn}%
\end{bash}
\item Alternatively, use the Online ASN.1 compiler \cite{AONL} by uploading
the \textbf{rectangle.asn} file into the Web form and unpacking the
produced archive on your computer.
\item By this time, you should have gotten multiple files in the current
directory, including the \textbf{Rectangle.c} and \textbf{Rectangle.h}.
\item Create a main() routine which takes the binary input file, decodes
it as it were a BER-encoded Rectangle type, and prints out the text
(XML) representation of the Rectangle type. Let's name the file \textbf{main.c}:
\begin{example}
#include <stdio.h>
#include <sys/types.h>
#include <Rectangle.h> /* Rectangle ASN.1 type */
int main(int ac, char **av) {
char buf[1024]; /* Temporary buffer */
asn_dec_rval_t rval; /* Decoder return value */
Rectangle_t *%$\underbracket{\textrm{\listingfont rectangle = 0}}$%; /* Type to decode. %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
FILE *fp; /* Input file handler */
size_t size; /* Number of bytes read */
char *filename; /* Input file name */
/* Require a single filename argument */
if(ac != 2) {
fprintf(stderr, "Usage: %\%%s <file.ber>\n", av[0]);
exit(1);
} else {
filename = av[1];
}
/* Open input file as read-only binary */
fp = fopen(filename, "rb");
if(!fp) {
perror(filename);
exit(1);
}
/* Read up to the buffer size */
size = fread(buf, 1, sizeof(buf), fp);
fclose(fp);
if(!size) {
fprintf(stderr, "%\%%s: Empty or broken\n", filename);
exit(1);
}
/* Decode the input buffer as Rectangle type */
rval = ber_decode(0, &asn_DEF_Rectangle, (void **)&rectangle, buf, size);
if(rval.code != RC_OK) {
fprintf(stderr, "%\%%s: Broken Rectangle encoding at byte %\%%ld\n", filename, (long)rval.consumed);
exit(1);
}
/* Print the decoded Rectangle type as XML */
xer_fprint(stdout, &asn_DEF_Rectangle, rectangle);
return 0; /* Decoding finished successfully */
}
\end{example}
\item Compile all files together using C compiler (varies by platform):
\begin{bash}
cc -I. -o %\textbf{\emph{rdecode}} \emph{*.c}%
\end{bash}
\item Done. You have just created the BER decoder of a Rectangle type,
named \textbf{rdecode}!
\end{enumerate}
\section{Adding constraints to a “Rectangle”}
This example shows how to add basic constraints to the ASN.1 specification
and how to invoke the constraints validation code in your application.
\begin{enumerate}
\item Create a file named \textbf{rectangle.asn} with the following contents:
\begin{asn}
RectangleModuleWithConstraints DEFINITIONS ::= BEGIN
Rectangle ::= SEQUENCE {
height INTEGER (0..100), -- Value range constraint
width INTEGER (0..MAX) -- Makes width non-negative
}
END
\end{asn}
\item Compile the file according to procedures shown in \fref{sec:A-Rectangle-Decoder}.
\item Modify the Rectangle type processing routine (you can start with the
main() routine shown in the \fref{sec:A-Rectangle-Decoder})
by placing the following snippet of code \emph{before} encoding and/or
\emph{after} decoding the Rectangle type:
\begin{example}
int ret; /* Return value */
char errbuf[128]; /* Buffer for error message */
size_t errlen = sizeof(errbuf); /* Size of the buffer */
/* ... here goes the Rectangle %\emph{decoding}% code ... */
ret = asn_check_constraints(&asn_DEF_Rectangle, rectangle, errbuf, &errlen);
/* assert(errlen < sizeof(errbuf)); // you may rely on that */
if(ret) {
fprintf(stderr, "Constraint validation failed: %\%%s\n", errbuf);
/* exit(...); // Replace with appropriate action */
}
/* ... here goes the Rectangle %\emph{encoding}% code ... */
\end{example}
\item Compile the resulting C code as shown in the previous chapters.
\item Test the constraints checking code by assigning integer value
101 to the \textbf{.height} member of the Rectangle structure, or
a negative value to the \textbf{.width} member.
The program will fail with ``Constraint validation failed'' message.
\item Done.
\end{enumerate}
\chapter{ASN.1 Compiler}
\section{The asn1c compiler tool}
The purpose of the ASN.1 compiler is to convert the specifications
in ASN.1 notation into some other language, such as C.
The compiler reads the specification and emits a series of target
language structures (C structs, unions, enums) describing the corresponding
ASN.1 types. The compiler also creates the code which allows automatic
serialization and deserialization of these structures using several
standardized encoding rules (BER, DER, OER, PER, XER).
Let's take the following ASN.1 example%
\footnote{\Fref{chap:Abstract-Syntax-Notation} provides a quick reference
on the ASN.1 notation.}:
\begin{asn}
RectangleModule DEFINITIONS ::= BEGIN
Rectangle ::= SEQUENCE {
height INTEGER, -- Height of the rectangle
width INTEGER -- Width of the rectangle
}
END
\end{asn}
The asn1c compiler reads this ASN.1 definition and produce the following
C type:
\begin{codesample}
typedef struct Rectangle_s {
long height;
long width;
} Rectangle_t;
\end{codesample}
The asn1c compiler also creates the code for converting this structure into
platform-independent wire representation and the decoder
of such wire representation back into local, machine-specific type.
These encoders and decoders are also called serializers and deserializers,
marshallers and unmarshallers, or codecs.
Compiling ASN.1 modules into C codecs can be as simple as invoking \cmd{asn1c}:
may be used to compile the ASN.1 modules:
\begin{bash}
asn1c %\emph{<modules.asn>}%
\end{bash}
If several ASN.1 modules contain interdependencies, all of the files
must be specified altogether:
\begin{bash}
asn1c %\emph{<module1.asn> <module2.asn> ...}%
\end{bash}
The compiler \textbf{-E} and \textbf{-EF} options are used for testing
the parser and the semantic fixer, respectively. These options will
instruct the compiler to dump out the parsed (and fixed, if \textbf{-F}
is involved) ASN.1 specification as it was understood
by the compiler. It might be useful to check whether a particular
syntactic construct is properly supported by the compiler.
\begin{bash}
asn1c %\textbf{-EF} \emph{<module-to-test.asn>}%
\end{bash}
The \textbf{-P} option is used to dump the compiled output on the
screen instead of creating a bunch of .c and .h files on disk in the
current directory. You would probably want to start with \textbf{-P}
option instead of creating a mess in your current directory. Another
option, \textbf{-R}, asks compiler to only generate the files which
need to be generated, and supress linking in the numerous support
files.
Print the compiled output instead of creating multiple source files:
\begin{bash}
asn1c %\textbf{-P} \emph{<module-to-compile-and-print.asn>}%
\end{bash}
\clearpage{}
\section{Compiler output}
The \cmd{asn1c} compiler produces a number of files:
\begin{itemize}
\item A set of .c and .h files for each type defined
in the ASN.1 specification. These files will be named similarly to
the ASN.1 types (\textbf{Rectangle.c} and \textbf{Rectangle.h} for the
RectangleModule ASN.1 module defined in the beginning of this document).
\item A set of helper .c and .h files which contain the generic encoders,
decoders and other useful routines.
Sometimes they are referred to by the term \emph{skeletons}.
There will be quite a few of them, some
of them are not even always necessary, but the overall amount of code
after compilation will be rather small anyway.
\item A \textbf{Makefile.am.libasncodecs} file which explicitly lists all the
generated files.
This makefile can be used on its own to build the just the codec library.
\item A \textbf{converter-example.c} file containing the \emph{int main()} function with a fully functioning encoder and data format converter. It can convert a given PDU between BER, XER, OER and PER. At some point you will want to replace this file with your own file containing the \emph{int main()} function.
\item A \textbf{Makefile.am.example} file which binds together
\textbf{Makefile.am.libasncodecs} and \textbf{converter-example.c}
to build a versatile converter and debugger for your data formats.
\end{itemize}
It is possible to compile everything with just a couple of instructions:
\begin{bash}
asn1c -pdu=%\emph{Rectangle}% *.asn
make -f Makefile.am.example # If you use `make`
\end{bash}
or
\begin{bash}
asn1c *.asn
cc -I. -DPDU=%\emph{Rectangle}% -o rectangle.exe *.c # ... or like this
\end{bash}
Refer to the \fref{chap:Quick-start-examples} for a sample
\emph{int main()} function if you want some custom logic and not satisfied
with the supplied \emph{converter-example.c}.
\clearpage{}
\section{\label{sec:Command-line-options}Command line options}
The following table summarizes the \cmd{asn1c} command line options.
\renewcommand{\arraystretch}{1.33}
\begin{longtable}{lp{4in}}
\textbf{Stage Selection Options} & \textbf{Description}\\
\midrule
{\ttfamily -E} & {\small Stop after the parsing stage and print the reconstructed ASN.1
specification code to the standard output.}\\
{\ttfamily -F} & {\small Used together with \texttt{-E}, instructs the compiler to stop after
the ASN.1 syntax tree fixing stage and dump the reconstructed ASN.1
specification to the standard output.}\\
{\ttfamily -P} & {\small Dump the compiled output to the standard output instead of
creating the target language files on disk.}\\
{\ttfamily -R} & {\small Restrict the compiler to generate only the ASN.1 tables, omitting the usual support code.}\\
{\ttfamily -S~\emph{<directory>}} & {\small Use the specified directory with ASN.1 skeleton files.}\\
{\ttfamily -X} & {\small Generate the XML DTD for the specified ASN.1 modules.}\\\\
\textbf{Warning Options} & \textbf{Description}\\
\midrule
{\ttfamily -Werror} & {\small Treat warnings as errors; abort if any warning is produced.}\\
{\ttfamily -Wdebug-parser} & {\small Enable the parser debugging during the ASN.1 parsing stage.}\\
{\ttfamily -Wdebug-lexer} & {\small Enable the lexer debugging during the ASN.1 parsing stage.}\\
{\ttfamily -Wdebug-fixer} & {\small Enable the ASN.1 syntax tree fixer debugging during the fixing stage.}\\
{\ttfamily -Wdebug-compiler} & {\small Enable debugging during the actual compile time.}\\ \\
\textbf{Language Options} & \textbf{Description}\\
\midrule
{\ttfamily -fbless-SIZE} & {\small Allow SIZE() constraint for INTEGER, ENUMERATED, and other types for which this constraint is normally prohibited by the standard.
This is a violation of an ASN.1 standard and compiler may fail to produce the meaningful code.}\\
{\ttfamily -fcompound-names} & {\small Use complex names for C structures. Using complex names prevents
name clashes in case the module reuses the same identifiers in multiple
contexts.}\\
{\ttfamily -findirect-choice} & {\small When generating code for a CHOICE type, compile the CHOICE
members as indirect pointers instead of declaring them inline. Consider
using this option together with \texttt{-fno-include-deps}
to prevent circular references.}\\
{\ttfamily -fincludes-quoted} & {\small Generate \#include lines in "double" instead of <angle> quotes.}\\
{\ttfamily -fknown-extern-type=\emph{<name>}} & {\small Pretend the specified type is known. The compiler will assume
the target language source files for the given type have been provided
manually. }\\
{\ttfamily -fline-refs} & {\small Include ASN.1 module's line numbers in generated code comments.}\\
{\ttfamily -fno-constraints} & {\small Do not generate the ASN.1 subtype constraint checking code. This
may produce a shorter executable.}\\
{\ttfamily -fno-include-deps} & {\small Do not generate the courtesy \#include lines for non-critical dependencies.}\\
{\ttfamily -funnamed-unions} & {\small Enable unnamed unions in the definitions of target language's structures.}\\
{\ttfamily -fwide-types} & {\small Use the wide integer types (INTEGER\_t, REAL\_t) instead of machine's native data types (long, double). }\\\\
\textbf{Codecs Generation Options} & \textbf{Description}\\
\midrule
{\ttfamily -no-gen-OER} & {\small Do not generate the Octet Encoding Rules (OER, X.696) support code.}\\
{\ttfamily -no-gen-PER} & {\small Do not generate the Packed Encoding Rules (PER, X.691) support code.}\\
{\ttfamily -no-gen-example} & {\small Do not generate the ASN.1 format converter example.}\\
{\ttfamily -pdu=\{\textbf{all}|\textbf{auto}|\emph{Type}\}} & {\small Create a PDU table for specified types, or discover the Protocol Data Units automatically.
In case of \texttt{-pdu=\textbf{all}}, all ASN.1 types defined in all modules wil form a PDU table. In case of \texttt{-pdu=\textbf{auto}}, all types not referenced by any other type will form a PDU table. If \texttt{\emph{Type}} is an ASN.1 type identifier, it is added to a PDU table. The last form may be specified multiple times.}\\ \\
\textbf{Output Options} & \textbf{Description}\\
\midrule
{\ttfamily -print-class-matrix} & {\small When \texttt{-EF} options are given, this option instructs the compiler to print out the collected Information Object Class matrix.}\\
{\ttfamily -print-constraints} & {\small With \texttt{-EF}, this option instructs the compiler
to explain its internal understanding of subtype constraints.}\\
{\ttfamily -print-lines} & {\small Generate \texttt{``-{}- \#line''} comments
in \texttt{-E} output.}\\
\end{longtable}
\renewcommand{\arraystretch}{1}
\chapter{API reference}
The functions desribed in this chapter are to be used by the application
programmer. These functions won't likely change change or get removed until
the next major release.
The API calls not listed here are not public and should not be used by the
application level code.
\apisection{sec:ASN_STRUCT_FREE}{ASN\_STRUCT\_FREE() macro}
\subsection*{Synopsis}
\begin{signature}
#define ASN_STRUCT_FREE(type_descriptor, struct_ptr)
\end{signature}
\subsection*{Description}
Recursively releases memory occupied by the structure
described by the \code{type\_descriptor} and referred to
by the \code{struct\_ptr} pointer.
Does nothing when \code{struct\_ptr} is NULL.
\subsection*{Return values}
Does not return a value.
\subsection*{Example}
\begin{example}
Rectangle_t *rect = ...;
ASN_STRUCT_FREE(asn_DEF_Rectangle, rect);
\end{example}
\apisection{sec:ASN_STRUCT_RESET}{ASN\_STRUCT\_RESET() macro}
\subsection*{Synopsis}
\begin{signature}
#define ASN_STRUCT_RESET(type_descriptor, struct_ptr)
\end{signature}
\subsection*{Description}
Recursively releases memory occupied by the members of the structure
described by the \code{type\_descriptor} and referred to
by the \code{struct\_ptr} pointer.
Does not release the memory pointed to by \code{struct\_ptr} itself.
Instead it clears the memory block by filling it out with 0 bytes.
Does nothing when \code{struct\_ptr} is NULL.
\subsection*{Return values}
Does not return a value.
\subsection*{Example}
\begin{example}
struct my_figure { /* The custom structure */
int flags; /* <some custom member> */
/* The type is generated by the ASN.1 compiler */
Rectangle_t rect;
/* other members of the structure */
};
struct my_figure *fig = ...;
ASN_STRUCT_RESET(asn_DEF_Rectangle, &fig->rect);
\end{example}
\apisection{sec:asn_check_constraints}{asn\_check\_constraints()}
\subsection*{Synopsis}
\begin{signature}
int asn_check_constraints(
const asn_TYPE_descriptor_t *type_descriptor,
const void *struct_ptr, /* Target language's structure */
char *errbuf, /* Returned error description */
size_t *errlen /* Length of the error description */
);
\end{signature}
\subsection*{Description}
Validate a given structure according to the ASN.1 constraints.
If \code{errbuf} and \code{errlen} are given, they shall point to the
appropriate buffer space and its length before calling this function.
Alternatively, they could be passed as \code{NULL}s.
If constraints validation fails, \code{errlen} will contain the actual
number of bytes used in \code{errbuf} to encode an error message.
The message is going to be properly 0-terminated.
\subsection*{Return values}
This function returns 0 in case all ASN.1 constraints are met
and -1 if one or more ASN.1 constraints were violated.
\subsection*{Example}
\begin{codesample}[basicstyle=\scriptsize\listingfont]
Rectangle_t *rect = ...;
char errbuf[128]; /* Buffer for error message */
size_t errlen = sizeof(errbuf); /* Size of the buffer */
int ret = asn_check_constraints(&asn_DEF_Rectangle, rectangle, errbuf, &errlen);
/* assert(errlen < sizeof(errbuf)); // Guaranteed: you may rely on that */
if(ret) {
fprintf(stderr, "Constraint validation failed: %\%%s\n", errbuf);
}
\end{codesample}
\apisection{sec:asn_decode}{asn\_decode()}
\subsection*{Synopsis}
\begin{signature}
asn_dec_rval_t asn_decode(
const asn_codec_ctx_t *opt_codec_ctx,
enum asn_transfer_syntax syntax,
const asn_TYPE_descriptor_t *type_descriptor,
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
const void *buffer, /* Data to be decoded */
size_t size /* Size of that buffer */
);
\end{signature}
\subsection*{Description}
The \code{asn\_decode()} function parses the data given by the \code{buffer}
and \code{size} arguments. The encoding rules are specified in the \code{syntax}
argument and the type to be decoded is specified by the \code{type_descriptor}.
The \code{struct_ptr_ptr} must point to the memory location which contains the
pointer to the structure being decoded. Initially the \code{*struct_ptr_ptr}
pointer is typically set to 0. In that case, \code{asn\_decode()} will
dynamically allocate memory for the structure and its members as needed
during the parsing.
If \code{*struct\_ptr\_ptr} already points to some memory, the \code{asn\_decode()}
will allocate the subsequent members as needed during the parsing.
\subsection*{Return values}
\input{asn_dec_rval.inc}
The \code{.consumed} value is in bytes, even for PER decoding.
For PER, use \code{uper\_decode()} in case you need to get
the number of consumed bits.
\subsection*{Restartability}
Some transfer syntax parsers (such as ATS\_BER) support restartability.
That means that in case the buffer has less data than expected,
the \code{asn_decode()} will process whatever is available and ask for more
data to be provided using the RC\_WMORE return \code{.code}.
Note that in the RC\_WMORE case the decoder may have processed less data than
it is available in the buffer, which means that you must be able to arrange
the next buffer to contain the unprocessed part of the previous buffer.
The \code{RC_WMORE} code may still be returned by parser not supporting
restartabilty. In such cases, the partially decoded structure shall be
discarded and the next invocation should use the extended buffer to parse
from the very beginning.
\subsection*{Example}
\begin{example}
Rectangle_t *%$\underbracket{\textrm{\listingfont rect = 0}}$%; /* %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
asn_dec_rval_t rval;
rval = asn_decode(0, ATS_BER, &asn_DEF_Rectangle, (void **)&rect, buffer, buf_size);
switch(rval.code) {
case RC_OK:
asn_fprint(stdout, &asn_DEF_Rectangle, rect);
ASN_STRUCT_FREE(&asn_DEF_Rectangle, rect);
break;
case RC_WMORE:
case RC_FAIL:
default:
ASN_STRUCT_FREE(&asn_DEF_Rectangle, rect);
break;
}
\end{example}
\subsection*{See also}
\seealso{sec:asn_fprint}{asn_fprint()}.
\apisection{sec:asn_encode}{asn\_encode()}
\subsection*{Synopsis}
\begin{signature}
#include <asn_application.h>
asn_enc_rval_t asn_encode(
const asn_codec_ctx_t *opt_codec_ctx,
enum asn_transfer_syntax syntax,
const asn_TYPE_descriptor_t *type_to_encode,
const void *structure_to_encode,
asn_app_consume_bytes_f *callback, void *callback_key);
\end{signature}
\subsection*{Description}
The \code{asn_encode()} function serializes the given \code{structure_to_encode} using the chosen ASN.1 transfer \code{syntax}.
During serialization, a user-specified \code{callback} is invoked zero
or more times with bytes of data to add to the output stream (if any), and
the \code{callback_key}. The signature for the callback is as follows:
\begin{signature}
typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, void *callback_key);
\end{signature}
\subsection*{Return values}
\input{asn_enc_rval.inc}
The serialized output size is returned in \textbf{bytes} irrespectively of the
ASN.1 transfer \code{syntax} chosen.\footnote{This is different from some
lower level encoding functions, such as \api{sec:uper_encode}{uper_encode()},
which returns the number of encoded \emph{bits} instead of bytes.}
On error (when \code{.encoded} is set to -1),
the \code{errno} is set to one of the following values:
\begin{tabular}[h!]{ll}
\texttt{EINVAL} & Incorrect parameters to the function, such as NULLs \\
\texttt{ENOENT} & Encoding transfer syntax is not defined (for this type) \\
\texttt{EBADF} & The structure has invalid form or content constraint failed \\
\texttt{EIO} & The callback has returned negative value during encoding
\end{tabular}
\subsection*{Example}
\begin{example}
static int
save_to_file(const void *data, size_t size, void *key) {
FILE *fp = key;
return (fwrite(data, 1, size, fp) == size) ? 0 : -1;
}
Rectangle_t *rect = ...;
FILE *fp = ...;
asn_enc_rval_t er;
er = asn_encode(0, ATS_DER, &asn_DEF_Rectangle, rect, save_to_file, fp);
if(er.encoded == -1) {
fprintf(stderr, "Failed to encode %\%%s\n", asn_DEF_Rectangle.name);
} else {
fprintf(stderr, "%\%%s encoded in %\%%zd bytes\n", asn_DEF_Rectangle.name, er.encoded);
}
\end{example}
\apisection{sec:asn_encode_to_buffer}{asn\_encode\_to\_buffer()}
\subsection*{Synopsis}
\begin{signature}
#include <asn_application.h>
asn_enc_rval_t asn_encode_to_buffer(
const asn_codec_ctx_t *opt_codec_ctx,
enum asn_transfer_syntax syntax,
const asn_TYPE_descriptor_t *type_to_encode,
const void *structure_to_encode,
void *buffer, size_t buffer_size);
\end{signature}
\subsection*{Description}
The \code{asn_encode_to_buffer()} function serializes the given \code{structure_to_encode} using the chosen ASN.1 transfer \code{syntax}.
The function places the serialized data into the given
\code{buffer} of size \code{buffer_size}.
\subsection*{Return values}
\input{asn_enc_rval.inc}
The serialized output size is returned in \textbf{bytes} irrespectively of the
ASN.1 transfer \code{syntax} chosen.\footnote{This is different from some
lower level encoding functions, such as \api{sec:uper_encode}{uper_encode()},
which returns the number of encoded \emph{bits} instead of bytes.}
If \code{.encoded} size exceeds the specified \code{buffer_size},
the serialization effectively failed due to insufficient space. The function
will succeed if subsequently called with buffer size no less than the returned
\code{.encoded} size. This behavior modeled after \code{snprintf()}.
On error (when \code{.encoded} is set to -1),
the \code{errno} is set to one of the following values:
\begin{tabular}[h!]{ll}
\texttt{EINVAL} & Incorrect parameters to the function, such as NULLs \\
\texttt{ENOENT} & Encoding transfer syntax is not defined (for this type) \\
\texttt{EBADF} & The structure has invalid form or content constraint failed
\end{tabular}
\subsection*{Example}
\begin{example}
Rectangle_t *rect = ...;
uint8_t buffer[128];
asn_enc_rval_t er;
er = asn_encode_to_buffer(0, ATS_DER, &asn_DEF_Rectangle, rect, buffer, sizeof(buffer));
if(er.encoded == -1) {
fprintf(stderr, "Serialization of %\%%s failed.\n", asn_DEF_Rectangle.name);
} else if(er.encoded > sizeof(buffer)) {
fprintf(stderr, "Buffer of size %\%%zu is too small for %\%%s, need %\%%zu\n",
buf_size, asn_DEF_Rectangle.name, er.encoded);
}
\end{example}
\subsection*{See also}
\seealso{sec:asn_encode_to_new_buffer}{asn_encode_to_new_buffer()}.
\apisection{sec:asn_encode_to_new_buffer}{asn\_encode\_to\_new\_buffer()}
\subsection*{Synopsis}
\begin{signature}
#include <asn_application.h>
typedef struct {
void *buffer; /* NULL if failed to encode. */
asn_enc_rval_t result;
} asn_encode_to_new_buffer_result_t;
asn_encode_to_new_buffer_result_t asn_encode_to_new_buffer(
const asn_codec_ctx_t *opt_codec_ctx,
enum asn_transfer_syntax syntax,
const asn_TYPE_descriptor_t *type_to_encode,
const void *structure_to_encode);
\end{signature}
\subsection*{Description}
The \code{asn_encode_to_new_buffer()} function serializes the given \code{structure_to_encode} using the chosen ASN.1 transfer \code{syntax}.
The function places the serialized data into the newly allocated buffer
which it returns in a compound structure.
\subsection*{Return values}
On failure, the \code{.buffer} is set to \code{NULL}
and \code{.result.encoded} is set to -1. The global \code{errno} is set
to one of the following values:
\begin{tabular}[h!]{ll}
\texttt{EINVAL} & Incorrect parameters to the function, such as NULLs \\
\texttt{ENOENT} & Encoding transfer syntax is not defined (for this type) \\
\texttt{EBADF} & The structure has invalid form or content constraint failed \\
\texttt{ENOMEM} & Memory allocation failed due to system or internal limits
\end{tabular}
\noindent{}On success, the \code{.result.encoded} is set to the number of
\textbf{bytes} that it took to serialize the structure.
The \code{.buffer} contains the serialized content.
The user is responsible for freeing the \code{.buffer}.
\subsection*{Example}
\begin{example}
asn_encode_to_new_buffer_result_t res;
res = asn_encode_to_new_buffer(0, ATS_DER, &asn_DEF_Rectangle, rect);
if(res.buffer) {
/* Encoded successfully. */
free(res.buffer);
} else {
fprintf(stderr, "Failed to encode %\%%s, estimated %\%%zd bytes\n",
asn_DEF_Rectangle.name, res.result.encoded);
}
\end{example}
\subsection*{See also}
\seealso{sec:asn_encode_to_buffer}{asn_encode_to_buffer()}.
\apisection{sec:asn_fprint}{asn\_fprint()}
\subsection*{Synopsis}
\begin{signature}
int asn_fprint(FILE *stream, /* Destination file */
const asn_TYPE_descriptor_t *type_descriptor,
const void *struct_ptr /* Structure to be printed */
);
\end{signature}
\subsection*{Description}
The \code{asn_fprint()} function prints human readable description
of the target language's structure into the file stream specified by
\code{stream} pointer.
The output format does not conform to any standard.
The \code{asn_fprint()} function attempts to
produce a valid output even for incomplete and broken structures, which
makes it more suitable for debugging complex cases than
\api{sec:xer_fprint}{xer_fprint()}.
\subsection*{Return values}
\begin{tabular}[h!]{rl}
0 & Output was successfully made \\
-1 & Error printing out the structure
\end{tabular}
\subsection*{Example}
\begin{example}
Rectangle_t *rect = ...;
asn_fprint(stdout, &asn_DEF_Rectangle, rect);
\end{example}
\subsection*{See also}
\seealso{sec:xer_fprint}{xer_fprint()}.
\apisection{sec:asn_random_fill}{asn\_random\_fill()}
\subsection*{Synopsis}
\begin{signature}
int asn_random_fill(
const asn_TYPE_descriptor_t *type_descriptor,
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
size_t approx_max_length_limit
);
\end{signature}
\subsection*{Description}
Create or initialize a structure with random contents, according to the type
specification and optional member constraints.
For best results the code should be generated without \cmd{-no-gen-PER}
option to \cmd{asn1c}. Making PER constraints code available in runtime
will make \code{asn_random_fill} explore the edges of PER-visible constraints
and sometimes break out of extensible contstraints' ranges.
The \code{asn_random_fill()} function has a bias to generate edge case
values. This property makes it useful for debugging the application level
code and for security testing, as random data can be a good seed to fuzzing.
The \code{approx_max_length_limit} specifies the approximate limit of the
resulting structure in units closely resembling bytes. The actual result
might be several times larger or smaller than the given length limit.
A rule of thumb way to select the initial value for this parameter
is to take a typical structure and use twice its DER output size.
\subsection*{Return values}
\begin{tabular}[h!]{rl}
0 & Structure was properly initialized with random data \\
-1 & Failure to initialize the structure with random data
\end{tabular}
\apisection{sec:ber_decode}{ber\_decode()}
\subsection*{Synopsis}
\begin{signature}
asn_dec_rval_t ber_decode(
const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *type_descriptor,
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
const void *buffer, /* Data to be decoded */
size_t size /* Size of that buffer */
);
\end{signature}
\subsection*{Description}
Decode BER, DER and CER data
(Basic Encoding Rules, Distinguished Encoding Rules, Canonical Encoding Rules),
as defined by ITU-T~X.690.
DER and CER are different subsets of BER.\newline
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_BER)}.}
\subsection*{Return values}
\input{asn_dec_rval.inc}
The \code{.consumed} value is in bytes.
\subsection*{Restartability}
The \code{ber_decode()} function is restartable (stream-oriented).
That means that in case the buffer has less data than expected,
the decoder will process whatever is available and ask for more data
to be provided using the RC\_WMORE return \code{.code}.
Note that in the RC\_WMORE case the decoder may have processed less data than
it is available in the buffer, which means that you must be able to arrange
the next buffer to contain the unprocessed part of the previous buffer.
\subsection*{See also}
\seealso{sec:der_encode}{der_encode()}.
\apisection{sec:der_encode}{der\_encode}
\subsection*{Synopsis}
\begin{signature}
asn_enc_rval_t der_encode(
const asn_TYPE_descriptor_t *type_descriptor,
const void *structure_to_encode,
asn_app_consume_bytes_f *callback,
void *callback_key
\end{signature}
\subsection*{Description}
The \code{der_encode()} function serializes the given \code{structure_to_encode} using the DER transfer syntax (a variant of BER, Basic Encoding Rules).
During serialization, a user-specified \code{callback} is invoked zero
or more times with bytes of data to add to the output stream (if any), and
the \code{callback_key}. The signature for the callback is as follows:
\begin{signature}
typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, void *callback_key);
\end{signature}
\noindent\emph{Consider using a more generic function \api{sec:asn_encode}{asn_encode(ATS_DER)}.}
\subsection*{Return values}
\input{asn_enc_rval.inc}
The serialized output size is returned in \textbf{bytes}.
\subsection*{Example}
\begin{example}
static int
save_to_file(const void *data, size_t size, void *key) {
FILE *fp = key;
return (fwrite(data, 1, size, fp) == size) ? 0 : -1;
}
Rectangle_t *rect = ...;
FILE *fp = ...;
asn_enc_rval_t er;
er = der_encode(&asn_DEF_Rectangle, rect, save_to_file, fp);
if(er.encoded == -1) {
fprintf(stderr, "Failed to encode %\%%s\n", asn_DEF_Rectangle.name);
} else {
fprintf(stderr, "%\%%s encoded in %\%%zd bytes\n", asn_DEF_Rectangle.name, er.encoded);
}
\end{example}
\subsection*{See also}
\seealso{sec:ber_decode}{ber_decode()},
\seealso{sec:asn_decode}{asn_decode(ATS_BER)}.
\apisection{sec:der_encode_to_buffer}{der\_encode\_to\_buffer()}
\subsection*{Synopsis}
\begin{signature}
asn_enc_rval_t der_encode_to_buffer(
const asn_TYPE_descriptor_t *type_descriptor,
const void *structure_to_encode,
void *buffer, size_t buffer_size);
\end{signature}
\subsection*{Description}
The \code{der_encode_to_buffer()} function serializes the given \code{structure_to_encode} using the DER transfer syntax (a variant of BER, Basic Encoding Rules).
The function places the serialized data into the given
\code{buffer} of size \code{buffer_size}.\newline
\noindent\emph{Consider using a more generic function \api{sec:asn_encode_to_buffer}{asn_encode_to_buffer(ATS_DER)}.}
\subsection*{Return values}
\input{asn_enc_rval.inc}
The serialized output size is returned in \textbf{bytes}.
The \code{.encoded} never exceeds the available buffer size.\footnote{This
behavior is different from \api{sec:asn_encode_to_buffer}{asn_encode_to_buffer()}.}
If the \code{buffer_size} is not sufficient, the \code{.encoded}
will be set to -1 and encoding would fail.
\subsection*{Example}
\begin{example}
Rectangle_t *rect = ...;
uint8_t buffer[128];
asn_enc_rval_t er;
er = der_encode_to_buffer(&asn_DEF_Rectangle, rect, buffer, sizeof(buffer));
if(er.encoded == -1) {
fprintf(stderr, "Serialization of %\%%s failed.\n", asn_DEF_Rectangle.name);
}
\end{example}
\subsection*{See also}
\seealso{sec:ber_decode}{ber_decode()},
\seealso{sec:asn_decode}{asn_decode(ATS_BER)},
\seealso{sec:asn_encode_to_buffer}{asn_encode_to_buffer(ATS_DER)}.
\apisection{sec:oer_decode}{oer\_decode()}
\subsection*{Synopsis}
\begin{signature}
asn_dec_rval_t oer_decode(
const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *type_descriptor,
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
const void *buffer, /* Data to be decoded */
size_t size /* Size of that buffer */
);
\end{signature}
\subsection*{Description}
Decode the BASIC-OER and CANONICAL-OER (Octet Encoding Rules),
as defined by ITU-T~X.696.\newline
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_BASIC_OER)}.}
\subsection*{Return values}
\input{asn_dec_rval.inc}
The \code{.consumed} value is in bytes.
\subsection*{Restartability}
The \code{oer_decode()} function is restartable (stream-oriented).
That means that in case the buffer has less data than expected,
the decoder will process whatever is available and ask for more data
to be provided using the RC\_WMORE return \code{.code}.
Note that in the RC\_WMORE case the decoder may have processed less data than
it is available in the buffer, which means that you must be able to arrange
the next buffer to contain the unprocessed part of the previous buffer.
\apisection{sec:oer_encode}{oer\_encode()}
\subsection*{Synopsis}
\begin{signature}
asn_enc_rval_t oer_encode(
const asn_TYPE_descriptor_t *type_descriptor,
const void *structure_to_encode,
asn_app_consume_bytes_f *callback,
void *callback_key);
\end{signature}
\subsection*{Description}
The \code{oer_encode()} function serializes the given \code{structure_to_encode} using the CANONICAL-OER transfer syntax (Octet Encoding Rules, ITU-T~X.691).
During serialization, a user-specified \code{callback} is invoked zero
or more times with bytes of data to add to the output stream (if any), and
the \code{callback_key}. The signature for the callback is as follows:
\begin{signature}
typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, void *callback_key);
\end{signature}
\noindent\emph{Consider using a more generic function \api{sec:asn_encode}{asn_encode(ATS_CANONICAL_OER)}.}
\subsection*{Return values}
\input{asn_enc_rval.inc}
The serialized output size is returned in \textbf{bytes}.
\subsection*{Example}
\begin{example}
static int
save_to_file(const void *data, size_t size, void *key) {
FILE *fp = key;
return (fwrite(data, 1, size, fp) == size) ? 0 : -1;
}
Rectangle_t *rect = ...;
FILE *fp = ...;
asn_enc_rval_t er;
er = oer_encode(&asn_DEF_Rectangle, rect, save_to_file, fp);
if(er.encoded == -1) {
fprintf(stderr, "Failed to encode %\%%s\n", asn_DEF_Rectangle.name);
} else {
fprintf(stderr, "%\%%s encoded in %\%%zd bytes\n", asn_DEF_Rectangle.name, er.encoded);
}
\end{example}
\subsection*{See also}
\seealso{sec:asn_encode}{asn_encode(ATS_CANONICAL_OER)}.
\apisection{sec:oer_encode_to_buffer}{oer\_encode\_to\_buffer()}
\subsection*{Synopsis}
\begin{signature}
asn_enc_rval_t oer_encode_to_buffer(
const asn_TYPE_descriptor_t *type_descriptor,
const asn_oer_constraints_t *constraints,
const void *structure_to_encode,
void *buffer, size_t buffer_size);
\end{signature}
\subsection*{Description}
The \code{oer_encode_to_buffer()} function serializes the given \code{structure_to_encode} using the CANONICAL-OER transfer syntax (Octet Encoding Rules, ITU-T~X.691).
The function places the serialized data into the given
\code{buffer} of size \code{buffer_size}.\newline
\noindent\emph{Consider using a more generic function \api{sec:asn_encode_to_buffer}{asn_encode_to_buffer(ATS_CANONICAL_OER)}.}
\subsection*{Return values}
\input{asn_enc_rval.inc}
The serialized output size is returned in \textbf{bytes}.
The \code{.encoded} never exceeds the available buffer size.\footnote{This
behavior is different from \api{sec:asn_encode_to_buffer}{asn_encode_to_buffer()}.}
If the \code{buffer_size} is not sufficient, the \code{.encoded}
will be set to -1 and encoding would fail.
\subsection*{Example}
\begin{example}
Rectangle_t *rect = ...;
uint8_t buffer[128];
asn_enc_rval_t er;
er = oer_encode_to_buffer(&asn_DEF_Rectangle, 0, rect, buffer, sizeof(buffer));
if(er.encoded == -1) {
fprintf(stderr, "Serialization of %\%%s failed.\n", asn_DEF_Rectangle.name);
}
\end{example}
\subsection*{See also}
\seealso{sec:ber_decode}{ber_decode()},
\seealso{sec:asn_decode}{asn_decode(ATS_BER)},
\seealso{sec:asn_encode_to_buffer}{asn_encode_to_buffer(ATS_DER)}.
\apisection{sec:uper_decode}{uper\_decode()}
\subsection*{Synopsis}
\begin{signature}
asn_dec_rval_t uper_decode(
const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *type_descriptor,
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
const void *buffer, /* Data to be decoded */
size_t size, /* Size of the input data buffer, bytes */
int skip_bits, /* Number of unused leading bits, 0..7 */
int unused_bits /* Number of unused tailing bits, 0..7 */
);
\end{signature}
\subsection*{Description}
Decode the Unaligned BASIC or CANONICAL PER (Packed Encoding Rules),
as defined by ITU-T~X.691.\newline
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_UNALIGNED_BASIC_PER)}.}
\subsection*{Return values}
\input{asn_dec_rval.inc}
Note that the \code{.consumed} value is in bits.
Use \code{(.consumed+7)/8} to convert to bytes.
\subsection*{Restartability}
The \code{uper_decode()} function is not restartable.
Failures are final.
\apisection{sec:uper_decode_complete}{uper\_decode\_complete()}
\subsection*{Synopsis}
\begin{signature}
asn_dec_rval_t uper_decode_complete(
const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *type_descriptor,
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
const void *buffer, /* Data to be decoded */
size_t size /* Size of data buffer */
);
\end{signature}
\subsection*{Description}
Decode a ``Production of a complete encoding'',
according to ITU-T~X.691 (08/2015) \#11.1.\newline
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_UNALIGNED_BASIC_PER)}.}
\subsection*{Return values}
\input{asn_dec_rval.inc}
The the \code{.consumed} value is returned in whole \emph{bytes} (NB).
\subsection*{Restartability}
The \code{uper_decode_complete()} function is not restartable.
Failures are final.
The complete encoding contains at least one byte, so on success
\code{.consumed} will be greater or equal to 1.
\apisection{sec:uper_encode}{uper\_encode()}
\apisection{sec:uper_encode_to_buffer}{uper\_encode\_to\_buffer()}
\apisection{sec:uper_encode_to_new_buffer}{uper\_encode\_to\_new\_buffer()}
\apisection{sec:xer_decode}{xer\_decode()}
\subsection*{Synopsis}
\begin{signature}
asn_dec_rval_t xer_decode(
const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *type_descriptor,
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
const void *buffer, /* Data to be decoded */
size_t size /* Size of data buffer */
);
\end{signature}
\subsection*{Description}
Decode the BASIC-XER and CANONICAL-XER (XML Encoding Rules) encoding,
as defined by ITU-T~X.693.\newline
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_BASIC_XER)}.}
\subsection*{Return values}
\input{asn_dec_rval.inc}
The \code{.consumed} value is in bytes.
\subsection*{Restartability}
The \code{xer_decode()} function is restartable (stream-oriented).
That means that in case the buffer has less data than expected,
the decoder will process whatever is available and ask for more data
to be provided using the RC\_WMORE return \code{.code}.
Note that in the RC\_WMORE case the decoder may have processed less data than
it is available in the buffer, which means that you must be able to arrange
the next buffer to contain the unprocessed part of the previous buffer.
\apisection{sec:xer_encode}{xer\_encode()}
\subsection*{Synopsis}
\begin{signature}
enum xer_encoder_flags_e {
/* Mode of encoding */
XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */
XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */
};
asn_enc_rval_t xer_encode(
const asn_TYPE_descriptor_t *type_descriptor,
const void *structure_to_encode,
enum xer_encoder_flags_e xer_flags,
asn_app_consume_bytes_f *callback,
void *callback_key);
\end{signature}
\subsection*{Description}
The \code{xer_encode()} function serializes the given \code{structure_to_encode} using the BASIC-XER or CANONICAL-XER transfer syntax (XML Encoding Rules, ITU-T~X.693).
During serialization, a user-specified \code{callback} is invoked zero
or more times with bytes of data to add to the output stream (if any), and
the \code{callback_key}. The signature for the callback is as follows:
\begin{signature}
typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, void *callback_key);
\end{signature}
\noindent\emph{Consider using a more generic function \api{sec:asn_encode}{asn_encode()} with \texttt{ATS\_BASIC\_XER} or \texttt{ATS\_CANONICAL\_XER} transfer syntax option.}
\subsection*{Return values}
\input{asn_enc_rval.inc}
The serialized output size is returned in \textbf{bytes}.
\subsection*{Example}
\begin{example}
static int
save_to_file(const void *data, size_t size, void *key) {
FILE *fp = key;
return (fwrite(data, 1, size, fp) == size) ? 0 : -1;
}
Rectangle_t *rect = ...;
FILE *fp = ...;
asn_enc_rval_t er;
er = xer_encode(&asn_DEF_Rectangle, rect, XER_F_CANONICAL, save_to_file, fp);
if(er.encoded == -1) {
fprintf(stderr, "Failed to encode %\%%s\n", asn_DEF_Rectangle.name);
} else {
fprintf(stderr, "%\%%s encoded in %\%%zd bytes\n", asn_DEF_Rectangle.name, er.encoded);
}
\end{example}
\subsection*{See also}
\seealso{sec:xer_fprint}{xer_fprint()}.
\apisection{sec:xer_fprint}{xer\_fprint()}
\subsection*{Synopsis}
\begin{signature}
int xer_fprint(FILE *stream, /* Destination file */
const asn_TYPE_descriptor_t *type_descriptor,
const void *struct_ptr /* Structure to be printed */
);
\end{signature}
\subsection*{Description}
The \code{xer_fprint()} function outputs XML-based serialization
of the given structure into the file stream specified by
\code{stream} pointer.
The output conforms to a BASIC-XER transfer syntax, as defined by ITU-T~X.693.
\subsection*{Return values}
\begin{tabular}[h!]{rl}
0 & XML output was successfully made \\
-1 & Error printing out the structure
\end{tabular}
\noindent{}Since the \code{xer_fprint()} function attempts to produce a conforming output,
it will likely break on partial structures by writing incomplete data
to the output stream and returning -1. This makes it less suitable for
debugging complex cases than \api{sec:asn_fprint}{asn_fprint()}.
\subsection*{Example}
\begin{example}
Rectangle_t *rect = ...;
xer_fprint(stdout, &asn_DEF_Rectangle, rect);
\end{example}
\subsection*{See also}
\seealso{sec:asn_fprint}{asn_fprint()}.
\chapter{API usage examples}
Let's start with including the necessary header files into your
application. Normally it is enough to include the header file of
the main PDU type. For our \emph{Rectangle} module, including the \emph{Rectangle.h} file is sufficient:
\begin{codesample}
#include <Rectangle.h>
\end{codesample}
The header files defines a C structure corresponding to the ASN.1
definition of a rectangle and the declaration of the ASN.1
\emph{type descriptor}. A type descriptor is a special globally accessible
object which is used as an argument to most of the API functions provided by
the ASN.1 codec. A type descriptor starts with \emph{asn\_DEF\_\ldots{}}. For example, here is the code which frees the Rectangle\_t structure:
\begin{codesample}
Rectangle_t *rect = ...;
ASN_STRUCT_FREE(%\textbf{asn\_DEF\_}%Rectangle, rect);
\end{codesample}
This code defines a \emph{rect} pointer which points to the Rectangle\_t
structure which needs to be freed. The second line uses a generic
\api{sec:ASN_STRUCT_FREE}{ASN\_STRUCT\_FREE()} macro which invokes the memory deallocation routine
created specifically for this Rectangle\_t structure.
The \emph{asn\_DEF\_Rectangle} is the type descriptor which holds
a collection of routines and operations defined for the Rectangle\_t structure.
\section{\label{sec:Generic-Encoding}Generic encoders and decoders}
Before we start describing specific encoders and decoders, let's step back
a little and check out a simple high level way.
The asn1c runtime supplies (see \emph{asn\_application.h}) two sets of high level functions, \api{sec:asn_encode}{asn_encode*} and \api{sec:asn_decode}{asn_decode*}, which take a transfer syntax selector as an argument. The transfer syntax selector is defined as this:
\begin{codesample}[basicstyle=\scriptsize\listingfont]
/*
* A selection of ASN.1 Transfer Syntaxes to use with generalized encoders and decoders.
*/
enum asn_transfer_syntax {
ATS_INVALID,
ATS_NONSTANDARD_PLAINTEXT,
ATS_BER,
ATS_DER,
ATS_CER,
ATS_BASIC_OER,
ATS_CANONICAL_OER,
ATS_UNALIGNED_BASIC_PER,
ATS_UNALIGNED_CANONICAL_PER,
ATS_BASIC_XER,
ATS_CANONICAL_XER,
};
\end{codesample}
Using this encoding selector, encoding and decoding becomes very generic:
\noindent{}Encoding:
\begin{codesample}[basicstyle=\scriptsize\listingfont]
uint8_t buffer[128];
size_t buf_size = sizeof(buffer);
asn_enc_rval_t er;
er = %\textbf{asn\_encode\emph{\_to\_buffer}}%(0, %\textbf{ATS\_DER}%, &asn_DEF_Rectangle, buffer, buf_size);
if(er.encoded > buf_size) {
fprintf(stderr, "Buffer of size %\%%zu is too small for %\%%s, need %\%%zu\n",
buf_size, asn_DEF_Rectangle.name, er.encoded);
}
\end{codesample}
\noindent{}Decoding:
\begin{codesample}[basicstyle=\scriptsize\listingfont]
Rectangle_t *%$\underbracket{\textrm{\listingfont rect = 0}}$%; /* %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
... = %\textbf{asn\_decode}%(0, %\textbf{ATS\_BER}%, &asn_DEF_Rectangle, (void **)%$\underbracket{\textrm{\listingfont \&rect}}$%, buffer, buf_size);
\end{codesample}
\section{\label{sec:Decoding-BER}Decoding BER}
The Basic Encoding Rules describe the most widely used (by the ASN.1
community) way to encode and decode a given structure in a machine-independent
way. Several other encoding rules (CER, DER) define a more restrictive
versions of BER, so the generic BER parser is also capable of decoding
the data encoded by the CER and DER encoders. The opposite is not true.
\emph{The ASN.1 compiler provides the generic BER decoder which is
capable of decoding BER, CER and DER encoded data.}
The decoder is restartable (stream-oriented).
That means that in case the buffer has less data than expected,
the decoder will process whatever is available and ask for more data
to be provided using the RC\_WMORE return \code{.code}.
Note that in the RC\_WMORE case the decoder may have processed less data than
it is available in the buffer, which means that you must be able to arrange
the next buffer to contain the unprocessed part of the previous buffer.
Suppose, you have two buffers of encoded data: 100 bytes and 200 bytes.
\begin{itemize}
\item You can concatenate these buffers and feed the BER decoder with 300
bytes of data, or
\item You can feed it the first buffer of 100 bytes of data, realize that
the ber\_decoder consumed only 95 bytes from it and later feed the
decoder with 205 bytes buffer which consists of 5 unprocessed bytes
from the first buffer and the additional 200 bytes from the second
buffer.
\end{itemize}
This is not as convenient as it could be (the BER encoder could
consume the whole 100 bytes and keep these 5 bytes in some temporary
storage), but in case of existing stream based processing it might
actually fit well into existing algorithm. Suggestions are welcome.
Here is the example of BER decoding of a simple structure:
\begin{codesample}
Rectangle_t *
simple_deserializer(const void *buffer, size_t buf_size) {
asn_dec_rval_t rval;
Rectangle_t *%$\underbracket{\textrm{\listingfont rect = 0}}$%; /* %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
rval = %\textbf{asn\_DEF\_Rectangle.op->ber\_decoder}%(0,
&asn_DEF_Rectangle,
(void **)%$\underbracket{\textrm{\listingfont \&rect}}$%, /* Decoder %\emph{changes}% the pointer */
buffer, buf_size, 0);
if(rval%\textbf{.code}% == RC_OK) {
return rect; /* Decoding succeeded */
} else {
/* Free the partially decoded rectangle */
ASN_STRUCT_FREE(asn_DEF_Rectangle, rect);
return 0;
}
}
\end{codesample}
The code above defines a function, \emph{simple\_deserializer}, which
takes a buffer and its length and is expected to return a pointer
to the Rectangle\_t structure. Inside, it tries to convert the bytes
passed into the target structure (rect) using the BER decoder and
returns the rect pointer afterwards. If the structure cannot be deserialized,
it frees the memory which might be left allocated by the unfinished
\emph{ber\_decoder} routine and returns 0 (no data). (This \textbf{freeing
is necessary} because the ber\_decoder is a restartable procedure,
and may fail just because there is more data needs to be provided
before decoding could be finalized). The code above obviously does
not take into account the way the \emph{ber\_decoder()} failed, so
the freeing is necessary because the part of the buffer may already
be decoded into the structure by the time something goes wrong.
A little less wordy would be to invoke a globally available \emph{ber\_decode()}
function instead of dereferencing the asn\_DEF\_Rectangle type descriptor:
\begin{codesample}
rval = ber_decode(0, &asn_DEF_Rectangle, (void **)&rect, buffer, buf_size);
\end{codesample}
Note that the initial (asn\_DEF\_Rectangle.op->ber\_decoder) reference
is gone, and also the last argument (0) is no longer necessary.
These two ways of BER decoder invocations are fully equivalent.
The BER de\emph{coder} may fail because of (\emph{the following RC\_\ldots{}
codes are defined in ber\_decoder.h}):
\begin{itemize}
\item RC\_WMORE: There is more data expected than it is provided (stream
mode continuation feature);
\item RC\_FAIL: General failure to decode the buffer;
\item \ldots{} other codes may be defined as well.
\end{itemize}
Together with the return code (.code) the asn\_dec\_rval\_t type contains
the number of bytes which is consumed from the buffer. In the previous
hypothetical example of two buffers (of 100 and 200 bytes), the first
call to ber\_decode() would return with .code = RC\_WMORE and .consumed
= 95. The .consumed field of the BER decoder return value is \textbf{always}
valid, even if the decoder succeeds or fails with any other return
code.
Look into ber\_decoder.h for the precise definition of ber\_decode()
and related types.
\section{\label{sec:Encoding-DER}Encoding DER}
The Distinguished Encoding Rules is the \emph{canonical} variant of
BER encoding rules. The DER is best suited to encode the structures
where all the lengths are known beforehand. This is probably exactly
how you want to encode: either after a BER decoding or after a manual
fill-up, the target structure contains the data which size is implicitly
known before encoding. Among other uses, the DER encoding is used
to encode X.509 certificates.
As with BER decoder, the DER encoder may be invoked either directly
from the ASN.1 type descriptor (asn\_DEF\_Rectangle) or from the stand-alone
function, which is somewhat simpler:
\begin{codesample}
/*
* This is the serializer itself.
* It supplies the DER encoder with the
* pointer to the custom output function.
*/
ssize_t
simple_serializer(FILE *ostream, Rectangle_t *rect) {
asn_enc_rval_t er; /* Encoder return value */
er = der_encode(&asn_DEF_Rect, rect, write_stream, ostream);
if(er%\textbf{.encoded}% == -1) {
fprintf(stderr, "Cannot encode %\%%s: %\%%s\n",
er%\textbf{.failed\_type}%->name, strerror(errno));
return -1;
} else {
/* Return the number of bytes */
return er.encoded;
}
}
\end{codesample}
As you see, the DER encoder does not write into some sort of buffer.
It just invokes the custom function (possible, multiple
times) which would save the data into appropriate storage. The optional
argument \emph{app\_key} is opaque for the DER encoder code and just
used by \emph{write\_stream()} as the pointer to the appropriate
output stream to be used.
If the custom write function is not given (passed as 0), then the
DER encoder will essentially do the same thing (i.~e., encode the data)
but no callbacks will be invoked (so the data goes nowhere). It may
prove useful to determine the size of the structure's encoding before
actually doing the encoding%
\footnote{It is actually faster too: the encoder might skip over some computations
which aren't important for the size determination.%
}.
Look into der\_encoder.h for the precise definition of der\_encode()
and related types.
\section{\label{sec:Encoding-XER}Encoding XER}
The XER stands for XML Encoding Rules, where XML, in turn, is eXtensible
Markup Language, a text-based format for information exchange. The
encoder routine API comes in two flavors: stdio-based and callback-based.
With the callback-based encoder, the encoding process is very similar
to the DER one, described in \fref{sec:Encoding-DER}. The
following example uses the definition of write\_stream() from up there.
\begin{codesample}
/*
* This procedure generates an XML document
* by invoking the XER encoder.
* NOTE: Do not copy this code verbatim!
* If the stdio output is necessary,
* use the xer_fprint() procedure instead.
* See %\fref{sec:Printing-the-target}%.
*/
int
print_as_XML(FILE *ostream, Rectangle_t *rect) {
asn_enc_rval_t er; /* Encoder return value */
er = xer_encode(&asn_DEF_Rectangle, rect,
XER_F_BASIC, /* BASIC-XER or CANONICAL-XER */
write_stream, ostream);
return (er.encoded == -1) ? -1 : 0;
}
\end{codesample}
Look into xer\_encoder.h for the precise definition of xer\_encode()
and related types.
See \fref{sec:Printing-the-target} for the example of stdio-based
XML encoder and other pretty-printing suggestions.
\section{\label{sec:Decoding-XER}Decoding XER}
The data encoded using the XER rules can be subsequently decoded using
the xer\_decode() API call:
\begin{codesample}
Rectangle_t *
XML_to_Rectangle(const void *buffer, size_t buf_size) {
asn_dec_rval_t rval;
Rectangle_t *%$\underbracket{\textrm{\listingfont rect = 0}}$%; /* %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
rval = xer_decode(0, &asn_DEF_Rectangle, (void **)&rect, buffer, buf_size);
if(rval%\textbf{.code}% == RC_OK) {
return rect; /* Decoding succeeded */
} else {
/* Free partially decoded rect */
ASN_STRUCT_FREE(asn_DEF_Rectangle, rect);
return 0;
}
}
\end{codesample}
The decoder takes both BASIC-XER and CANONICAL-XER encodings.
The decoder shares its data consumption properties with BER decoder;
please read the \fref{sec:Decoding-BER} to know more.
Look into xer\_decoder.h for the precise definition of xer\_decode()
and related types.
\section{\label{sec:Validating-the-target}Validating the target structure}
Sometimes the target structure needs to be validated. For example,
if the structure was created by the application (as opposed to being
decoded from some external source), some important information required
by the ASN.1 specification might be missing. On the other hand, the
successful decoding of the data from some external source does not
necessarily mean that the data is fully valid either. It might well
be the case that the specification describes some subtype constraints
that were not taken into account during decoding, and it would actually
be useful to perform the last check when the data is ready to be encoded
or when the data has just been decoded to ensure its validity according
to some stricter rules.
The \api{sec:asn_check_constraints}{asn_check_constraints()}
function checks the type for various
implicit and explicit constraints. It is recommended to use the
\code{asn_check_constraints()}
function after each decoding and before each encoding.
\section{\label{sec:Printing-the-target}Printing the target structure}
To print out the structure for debugging purposes, use the
\api{sec:asn_fprint}{asn_fprint()} function:
\begin{codesample}
asn_fprint(stdout, &asn_DEF_Rectangle, rect);
\end{codesample}
A practical alternative to this custom format printing is to serialize
the structure into XML. The default BASIC-XER encoder performs reasonable
formatting for the output to be both useful and human readable.
Use the \api{sec:xer_fprint}{xer_fprint()} function:
\begin{codesample}
xer_fprint(stdout, &asn_DEF_Rectangle, rect);
\end{codesample}
See \fref{sec:Encoding-XER} for XML-related details.
\section{\label{sec:Freeing-the-target}Freeing the target structure}
Freeing the structure is slightly more complex than it may seem.
When the ASN.1 structure is freed, all the members of the structure
and their submembers are recursively freed as well.
The ASN\_STRUCT\_FREE() macro helps with that.
But it might not always be feasible to free the whole structure.
In the following example, the application programmer defines a custom
structure with one ASN.1-derived member (rect).
\begin{codesample}
struct my_figure { /* The custom structure */
int flags; /* <some custom member> */
/* The type is generated by the ASN.1 compiler */
Rectangle_t rect;
/* other members of the structure */
};
\end{codesample}
This member is not a reference to the Rectangle\_t, but an in-place inclusion
of the Rectangle\_t structure.
If there's a need to free the \code{rect} member, the usual procedure of
freeing everything must not be applied to the \code{\&rect} pointer itself,
because it does not point to the beginning of memory block allocated by
the memory allocation routine, but instead lies within a block allocated for
the my\_figure structure.
To solve this problem, in addition to ASN\_STRUCT\_FREE() macro, the asn1c
skeletons define the ASN\_STRUCT\_RESET() macro which doesn't free the passed
pointer and instead resets the structure into the clean and safe state.
\begin{codesample}
/* %\textbf{1. Rectangle\_t is defined within my\_figure}% */
struct my_figure {
Rectangle_t rect;
} *mf = ...;
/*
* Freeing the Rectangle_t
* without freeing the mf->rect area.
*/
ASN_STRUCT_RESET(asn_DEF_Rectangle, &mf->rect);
/* %\textbf{2. Rectangle\_t is a stand-alone pointer}% */
Rectangle_t *rect = ...;
/*
* Freeing the Rectangle_t
* and freeing the rect pointer.
*/
ASN_STRUCT_FREE(asn_DEF_Rectangle, rect);
\end{codesample}
It is safe to invoke both macros with the target structure pointer
set to 0 (NULL). In this case, the function will do nothing.
\chapter{\label{chap:Abstract-Syntax-Notation}Abstract Syntax Notation: ASN.1}
\emph{This chapter defines some basic ASN.1 concepts and describes
several most widely used types. It is by no means an authoritative
or complete reference. For more complete ASN.1 description, please
refer to Olivier Dubuisson's book \cite{Dub00} or the ASN.1 body
of standards itself \cite{ITU-T/ASN.1}.}
The Abstract Syntax Notation One is used to formally describe the
data transmitted across the network. Two communicating parties may employ
different formats of their native data types (e.~g., different number
of bits for the native integer type), thus it is important to have
a way to describe the data in a manner which is independent from the
particular machine's representation.
The ASN.1 specifications are used to achieve the following:
\begin{itemize}
\item The specification expressed in the ASN.1 notation is a formal and
precise way to communicate the structure of data to human readers;
\item The ASN.1 specifications may be used as input for automatic compilers
which produce the code for some target language (C, C++, Java, etc)
to encode and decode the data according to some encoding formats.
Several such encoding formats (called Transfer Encoding Rules)
have been defined by the ASN.1 standard.
\end{itemize}
Consider the following example:
\begin{asn}
Rectangle ::= SEQUENCE {
height INTEGER,
width INTEGER
}
\end{asn}
This ASN.1 specification describes a constructed type, \emph{Rectangle},
containing two integer fields. This specification may tell the reader
that there exists this kind of data structure and that some entity
may be prepared to send or receive it. The question on \emph{how}
that entity is going to send or receive the \emph{encoded data} is
outside the scope of ASN.1. For example, this data structure may be
encoded according to some encoding rules and sent to the destination
using the TCP protocol. The ASN.1 specifies several ways of encoding
(or ``serializing'', or ``marshaling'') the data: BER, PER, XER
and others, including CER and DER derivatives from BER.
The complete specification must be wrapped in a module, which looks
like this:
\begin{asn}
RectangleModule1
{ iso org(3) dod(6) internet(1) private(4)
enterprise(1) spelio(9363) software(1)
asn1c(5) docs(2) rectangle(1) 1 }
DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
-- This is a comment which describes nothing.
Rectangle ::= SEQUENCE {
height INTEGER, -- Height of the rectangle
width INTEGER -- Width of the rectangle
}
END
\end{asn}
The module header consists of module name (RectangleModule1), the
module object identifier (\{...\}), a keyword ``DEFINITIONS'', a
set of module flags (AUTOMATIC TAGS) and ``::= BEGIN''. The module
ends with an ``END'' statement.
\section{Some of the ASN.1 Basic Types}
\subsection{The BOOLEAN type}
The BOOLEAN type models the simple binary TRUE/FALSE, YES/NO, ON/OFF
or a similar kind of two-way choice.
\subsection{The INTEGER type}
The INTEGER type is a signed natural number type without any restrictions
on its size. If the automatic checking on INTEGER value bounds are
necessary, the subtype constraints must be used.
\begin{asn}
SimpleInteger ::= INTEGER
-- An integer with a very limited range
SmallPositiveInt ::= INTEGER (0..127)
-- Integer, negative
NegativeInt ::= INTEGER (MIN..0)
\end{asn}
\subsection{The ENUMERATED type}
The ENUMERATED type is semantically equivalent to the INTEGER type
with some integer values explicitly named.
\begin{asn}
FruitId ::= ENUMERATED { apple(1), orange(2) }
-- The numbers in braces are optional,
-- the enumeration can be performed
-- automatically by the compiler
ComputerOSType ::= ENUMERATED {
FreeBSD, -- acquires value 0
Windows, -- acquires value 1
Solaris(5), -- remains 5
Linux, -- becomes 6
MacOS -- becomes 7
}
\end{asn}
\subsection{The OCTET STRING type}
This type models the sequence of 8-bit bytes. This may be used to
transmit some opaque data or data serialized by other types of encoders
(e.~g., video file, photo picture, etc).
\subsection{The OBJECT IDENTIFIER type}
The OBJECT IDENTIFIER is used to represent the unique identifier of
any object, starting from the very root of the registration tree.
If your organization needs to uniquely identify something (a router,
a room, a person, a standard, or whatever), you are encouraged to
get your own identification subtree at \url{http://www.iana.org/protocols/forms.htm}.
For example, the very first ASN.1 module in this Chapter (RectangleModule1)
has the following OBJECT IDENTIFIER: 1 3 6 1 4 1 9363 1 5 2 1 1.
\begin{asn}
ExampleOID ::= OBJECT IDENTIFIER
rectangleModule1-oid ExampleOID
::= { 1 3 6 1 4 1 9363 1 5 2 1 1 }
-- An identifier of the Internet.
internet-id OBJECT IDENTIFIER
::= { iso(1) identified-organization(3)
dod(6) internet(1) }
\end{asn}
As you see, names are optional.
\subsection{The RELATIVE-OID type}
The RELATIVE-OID type has the semantics of a subtree of an OBJECT
IDENTIFIER. There may be no need to repeat the whole sequence of numbers
from the root of the registration tree where the only thing of interest
is some of the tree's subsequence.
\begin{asn}
this-document RELATIVE-OID ::= { docs(2) usage(1) }
this-example RELATIVE-OID ::= {
this-document assorted-examples(0) this-example(1) }
\end{asn}
\section{Some of the ASN.1 String Types}
\subsection{The IA5String type}
This is essentially the ASCII, with 128 character codes available
(7 lower bits of an 8-bit byte).
\subsection{The UTF8String type}
This is the character string which encodes the full Unicode range
(4 bytes) using multibyte character sequences.
\subsection{The NumericString type}
This type represents the character string with the alphabet consisting
of numbers (``0'' to ``9'') and a space.
\subsection{The PrintableString type}
The character string with the following alphabet: space, ``\textbf{'}''
(single quote), ``\textbf{(}'', ``\textbf{)}'', ``\textbf{+}'',
``\textbf{,}'' (comma), ``\textbf{-}'', ``\textbf{.}'', ``\textbf{/}'',
digits (``0'' to ``9''), ``\textbf{:}'', ``\textbf{=}'', ``\textbf{?}'',
upper-case and lower-case letters (``A'' to ``Z'' and ``a''
to ``z'').
\subsection{The VisibleString type}
The character string with the alphabet which is more or less a subset
of ASCII between the space and the ``\textbf{\textasciitilde{}}''
symbol (tilde).
Alternatively, the alphabet may be described as the PrintableString
alphabet presented earlier, plus the following characters: ``\textbf{!}'',
``\textbf{``}'', ``\textbf{\#}'', ``\textbf{\$}'', ``\textbf{\%}'',
``\textbf{\&}'', ``\textbf{*}'', ``\textbf{;}'', ``\textbf{<}'',
``\textbf{>}'', ``\textbf{{[}}'', ``\textbf{\textbackslash{}}'',
``\textbf{{]}}'', ``\textbf{\textasciicircum{}}'', ``\textbf{\_}'',
``\textbf{`}`` (single left quote), ``\textbf{\{}'', ``\textbf{|}'',
``\textbf{\}}'', ``\textbf{\textasciitilde{}}''.
\section{ASN.1 Constructed Types}
\subsection{The SEQUENCE type}
This is an ordered collection of other simple or constructed types.
The SEQUENCE constructed type resembles the C ``struct'' statement.
\begin{asn}
Address ::= SEQUENCE {
-- The apartment number may be omitted
apartmentNumber NumericString OPTIONAL,
streetName PrintableString,
cityName PrintableString,
stateName PrintableString,
-- This one may be omitted too
zipNo NumericString OPTIONAL
}
\end{asn}
\subsection{The SET type}
This is a collection of other simple or constructed types. Ordering
is not important. The data may arrive in the order which is different
from the order of specification. Data is encoded in the order not
necessarily corresponding to the order of specification.
\subsection{The CHOICE type}
This type is just a choice between the subtypes specified in it. The
CHOICE type contains at most one of the subtypes specified, and it
is always implicitly known which choice is being decoded or encoded.
This one resembles the C ``union'' statement.
The following type defines a response code, which may be either an
integer code or a boolean ``true''/``false'' code.
\begin{asn}
ResponseCode ::= CHOICE {
intCode INTEGER,
boolCode BOOLEAN
}
\end{asn}
\subsection{The SEQUENCE OF type}
This one is the list (array) of simple or constructed types:
\begin{asn}
-- Example 1
ManyIntegers ::= SEQUENCE OF INTEGER
-- Example 2
ManyRectangles ::= SEQUENCE OF Rectangle
-- More complex example:
-- an array of structures defined in place.
ManyCircles ::= SEQUENCE OF SEQUENCE {
radius INTEGER
}
\end{asn}
\subsection{The SET OF type}
The SET OF type models the bag of structures. It resembles the SEQUENCE
OF type, but the order is not important. The elements may arrive
in the order which is not necessarily the same as the in-memory order
on the remote machines.
\begin{asn}
-- A set of structures defined elsewhere
SetOfApples :: SET OF Apple
-- Set of integers encoding the kind of a fruit
FruitBag ::= SET OF ENUMERATED { apple, orange }
\end{asn}
\begin{thebibliography}{ITU-T/ASN.1}
\bibitem[ASN1C]{ASN1C}The Open Source ASN.1 Compiler. \url{http://lionet.info/asn1c}
\bibitem[AONL]{AONL}Online ASN.1 Compiler. \url{http://lionet.info/asn1c/asn1c.cgi}
\bibitem[Dub00]{Dub00}Olivier Dubuisson --- \emph{ASN.1 Communication
between heterogeneous systems} --- Morgan Kaufmann Publishers, 2000.
\url{http://asn1.elibel.tm.fr/en/book/}. ISBN:0-12-6333361-0.
\bibitem[ITU-T/ASN.1]{ITU-T/ASN.1}ITU-T Study Group 17 --- Languages
for Telecommunication Systems \url{http://www.itu.int/ITU-T/studygroups/com17/languages/}
\end{thebibliography}
\end{document}