aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--asn1c/enber.126
-rw-r--r--asn1c/enber.c47
-rw-r--r--asn1c/unber.116
-rw-r--r--asn1c/unber.c52
4 files changed, 100 insertions, 41 deletions
diff --git a/asn1c/enber.1 b/asn1c/enber.1
index 8b1f42e1..4a9edfc2 100644
--- a/asn1c/enber.1
+++ b/asn1c/enber.1
@@ -12,16 +12,38 @@
.SH NAME
enber \- Convert the unber XML output back into BER
.SH SYNOPSIS
-enber [\fB-\fR] \fIinfile\fR...
+enber [\fB-n\fR] [\fB-\fR] \fIinfile\fR...
.SH DESCRIPTION
-enber takes the XML-encoded files produced by \fIunber\fR\|(1) and converts
+enber takes the XML-formatted files produced by \fIunber\fR\|(1) and converts
them back into the BER format.
A single dash represents the standard input.
+.SH OPTIONS
+.TP
+\fB\-n\fR
+Disable input validation. By default, enber performs some basic validity checks
+against the XML input. This option disables such checks.
.SH EXAMPLES
Decode the BER sequence and immediately encode it back
.Vb
\& unber \fB-p\fR \fIfilename.ber\fR | enber \fB-\fR > \fIreconstructed.ber\fR
.Ve
+.SH FOOTNOTES
+This program does not attempt to perform full-fledged XML parsing. It is merely
+compatible with \fIunber\fR\|(1)'s output.
+In particular, the XML comments are not supported.
+The following characters after the initial white space indicate
+the start of a comment: "\fB#\fR" (a hash) and "\fB--\fR" (two dashes).
+The whole comment line is ignored completely. Empty lines are ignored as well.
+.P
+The following example demostrates the use of comments:
+.Vb
+\& <C T="[1]" TL="2" V="2">
+\& <I T="[1]" TL="2" V="Indefinite">
+\& -- </I>
+\& # Do not terminate:
+\& # the absence of end-of-content octets is intentional!
+\& </C>
+.Ve
.SH SEE ALSO
.TP
\&\fIunber\fR\|(1), \&\fIasn1c\fR\|(1)
diff --git a/asn1c/enber.c b/asn1c/enber.c
index 45fda434..c6cadf7b 100644
--- a/asn1c/enber.c
+++ b/asn1c/enber.c
@@ -45,7 +45,7 @@
#include <ber_tlv_tag.c>
#include <ber_tlv_length.c>
-static void usage(const char *av0); /* Print the Usage screen and exit */
+static void usage(const char *av0, int);/* Print the Usage screen and exit */
static int process(const char *fname); /* Perform the BER decoding */
static int process_line(const char *fname, char *line, int lineno);
@@ -53,6 +53,8 @@ static int process_line(const char *fname, char *line, int lineno);
#define COPYRIGHT \
"Copyright (c) 2004 Lev Walkin <vlm@lionet.info>\n"
+static int no_validation; /* -n */
+
int
main(int ac, char **av) {
int ch; /* Command line character */
@@ -61,15 +63,20 @@ main(int ac, char **av) {
/*
* Process command-line options.
*/
- while((ch = getopt(ac, av, "hv")) != -1)
+ while((ch = getopt(ac, av, "nhv")) != -1)
switch(ch) {
+ case 'n':
+ no_validation++;
+ break;
case 'v':
- fprintf(stderr, "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT);
+ usage(av[0], 1);
+ fprintf(stderr, "Convert unber(1)'s output back into BER, "
+ "v" VERSION "\n" COPYRIGHT);
exit(0);
break;
case 'h':
default:
- usage(av[0]);
+ usage(av[0], 0);
}
/*
@@ -101,11 +108,15 @@ main(int ac, char **av) {
* Print the usage screen and exit(EX_USAGE).
*/
static void
-usage(const char *av0) {
+usage(const char *av0, int copyright_only) {
+ fprintf(stderr,
+ "Convert unber(1)'s output back into BER, "
+ "v" VERSION "\n" COPYRIGHT);
+ if(copyright_only) exit(0);
fprintf(stderr,
-"Convertor of under(1) output back into BER, v" VERSION "\n" COPYRIGHT
-"Usage: %s [-] [file ...]\n"
- , av0);
+ "Usage: %s [-n] [-] [file ...]\n"
+ "Options:\n"
+ " -n Disable XML input validation\n", av0);
exit(EX_USAGE);
}
@@ -184,9 +195,18 @@ process_line(const char *fname, char *line, int lineno) {
(void)fname;
/* Find a tag opening angle bracket */
- for(; *line == ' '; line++);
+ for(; *line == ' ' || *line == '\t'; line++);
op = line;
- if(*op != '<') {
+ switch(*op) {
+ case '<': /* That's what we want! A tag opening */
+ break;
+ case '-': /* This is a comment (dash-dash) */
+ if(op[1] == *op)
+ case '\r':
+ case '\n':
+ case '#': /* This is a comment */
+ return 0;
+ default:
fprintf(stderr, "%s: Missing '<' after whitespace\n", fname);
exit(EX_DATAERR);
}
@@ -240,10 +260,10 @@ process_line(const char *fname, char *line, int lineno) {
tcl_pos = strstr(op, "T=\"[");
tl_pos = strstr(op, "TL=\"");
v_pos = strstr(op, "V=\"");
- if(!tcl_pos || !tl_pos || !v_pos) {
+ if(!tcl_pos || !tl_pos || (!v_pos && constr != 2)) {
fprintf(stderr,
"%s: Mandatory attribute %s is not found at line %d\n",
- fname, (!tcl_pos)?"T":(v_pos?"V":"TCL"), lineno);
+ fname, (!tcl_pos)?"T":((!v_pos)?"V":"TL"), lineno);
exit(EX_DATAERR);
}
errno = 0;
@@ -368,11 +388,12 @@ process_line(const char *fname, char *line, int lineno) {
fputc(v, stdout);
}
if(len != tlv_len) {
+ if(no_validation) fprintf(stderr, "Warning: ");
fprintf(stderr,
"%s: Could not encode value of %d chars "
"at line %d in %d bytes\n",
fname, len, lineno, tlv_len);
- exit(EX_DATAERR);
+ if(!no_validation) exit(EX_DATAERR);
}
}
diff --git a/asn1c/unber.1 b/asn1c/unber.1
index bfedffa3..a31fabd1 100644
--- a/asn1c/unber.1
+++ b/asn1c/unber.1
@@ -29,7 +29,8 @@ By default, unber continues decoding until the end of file (input stream).
Use the specified number of spaces for output indentation. Default is 4 spaces.
.TP
\fB\-p\fR
-Do \fInot\fR attempt pretty-printing of known ASN.1 types (strings, INTEGER, BOOLEAN, etc).
+Do \fInot\fR attempt pretty-printing of known ASN.1 types (OBJECT IDENTIFIER, INTEGER, BOOLEAN, etc). By default, some ASN.1 types are converted into
+the text representation. This option is required for \&\fIenber\fR\|(1).
.TP
\fB\-t\fR \fIdata-string\fR
Interpret the data-string as a sequence of hexadecimal values representing
@@ -62,7 +63,7 @@ Likely name of the underlying ASN.1 type (for UNIVERSAL tags)
[\fIF\fR]
Indicates that the value was reformatted (pretty-printed)
.P
-Example:
+Sample XML output:
.Vb
\& <I T="[UNIVERSAL 16]" TL="2" V="Indefinite" A="SEQUENCE">
\& <P T="[UNIVERSAL 19]" TL="2" V="2" A="PrintableString">US</P>
@@ -84,10 +85,19 @@ Decode the binary stream taken from the standard input:
.Vb
\& cat \fI...\fR | unber \fB-\fR
.Ve
-Decode the binary stream into the same stream (see \fIenber\fR\|(1)):
+Decode the binary stream into the same stream (see \&\fIenber\fR\|(1)):
.Vb
\& cat \fI...\fR | unber \fB-p\fR \fB-\fR | enber \fB-\fR > filename.ber\fI\fR
.Ve
+.SH FOOTNOTES
+The constructed XML output is not necessarily well-formed.
+.P
+When indefinite length encoding is being used, the BER sequence, which is not
+terminated with the end-of-content octets, will cause the terminating \fB</I>\fR
+XML tag to disappear.
+Thus, the invalid BER framing directly causes invalid XML output.
+.P
+The \&\fIenber\fR\|(1) utility understands this convention correctly.
.SH SEE ALSO
.TP
\&\fIenber\fR\|(1), \&\fIasn1c\fR\|(1)
diff --git a/asn1c/unber.c b/asn1c/unber.c
index c9e7da12..c7ba71c8 100644
--- a/asn1c/unber.c
+++ b/asn1c/unber.c
@@ -158,7 +158,7 @@ typedef enum pd_code {
PD_FINISHED = 0,
PD_EOF = 1,
} pd_code_e;
-static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit);
+static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit, ssize_t *decoded, int expect_eoc);
static void print_TL(int fin, int level, int constr, ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t);
static int print_V(const char *fname, FILE *fp, ber_tlv_tag_t, ber_tlv_len_t);
@@ -169,6 +169,7 @@ static int
process(const char *fname) {
FILE *fp;
pd_code_e pdc;
+ ssize_t decoded = 0;
if(strcmp(fname, "-")) {
fp = fopen(fname, "r");
@@ -184,7 +185,7 @@ process(const char *fname) {
* Fetch out BER-encoded data until EOF or error.
*/
do {
- pdc = process_deeper(fname, fp, 0, -1);
+ pdc = process_deeper(fname, fp, 0, -1, &decoded, 0);
} while(pdc == PD_FINISHED && !single_type_decoding);
if(fp != stdin)
@@ -198,7 +199,7 @@ process(const char *fname) {
/*
* Process the TLV recursively.
*/
-static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit) {
+static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit, ssize_t *decoded, int expect_eoc) {
unsigned char tagbuf[32];
ssize_t tblen = 0;
pd_code_e pdc = PD_FINISHED;
@@ -266,52 +267,57 @@ static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t
continue;
}
- if(tagbuf[0] == '\0' && tagbuf[1] == '\0') {
- /* End of content octets */
- return PD_FINISHED;
- }
-
/* Make sure the T & L decoders took exactly the whole buffer */
assert((t_len + l_len) == tblen);
- print_TL(0, level, constr, tblen, tlv_tag, tlv_len);
+ if(!expect_eoc || tagbuf[0] || tagbuf[1])
+ print_TL(0, level, constr, tblen, tlv_tag, tlv_len);
if(limit != -1) {
/* If limit is set, account for the TL sequence */
limit -= (t_len + l_len);
assert(limit >= 0);
- }
- if(limit != -1) {
if(tlv_len > limit) {
fprintf(stderr,
"%s: Structure advertizes length (%ld) "
"greater than of a parent container (%ld)\n",
fname, (long)tlv_len, (long)limit);
return PD_FAILED;
- } else if(tlv_len != -1) {
- /* Account for the V */
- limit -= tlv_len;
}
}
+ *decoded += t_len + l_len;
+
+ if(expect_eoc && tagbuf[0] == '\0' && tagbuf[1] == '\0') {
+ /* End of content octets */
+ print_TL(1, level - 1, 1, 2, 0, -1);
+ return PD_FINISHED;
+ }
+
if(constr) {
+ ssize_t dec = 0;
/*
* This is a constructed type. Process recursively.
*/
-
- /* Get the new subframe limit from the structure tags */
- if(tlv_len == -1)
- tlv_len = limit;
-
printf(">\n"); /* Close the opening tag */
- pdc = process_deeper(fname, fp, level + 1, tlv_len);
+ pdc = process_deeper(fname, fp, level + 1,
+ tlv_len == -1 ? limit : tlv_len,
+ &dec, tlv_len == -1);
if(pdc == PD_FAILED) return pdc;
+ if(limit != -1) limit -= dec;
+ *decoded += dec;
+ if(tlv_len == -1) {
+ tblen = 0;
+ continue;
+ }
} else {
-
assert(tlv_len >= 0);
if(print_V(fname, fp, tlv_tag, tlv_len))
return PD_FAILED;
+
+ limit -= tlv_len;
+ *decoded += tlv_len;
}
print_TL(1, level, constr, tblen, tlv_tag, tlv_len);
@@ -339,9 +345,9 @@ print_TL(int fin, int level, int constr, ssize_t tlen, ber_tlv_tag_t tlv_tag, be
ber_tlv_tag_fwrite(tlv_tag, stdout);
printf("\"");
- if(!fin) {
+ if(!fin || tlv_len == -1)
printf(" TL=\"%ld\"", (long)tlen);
-
+ if(!fin) {
if(tlv_len == -1)
printf(" V=\"Indefinite\"");
else