offset printing


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@904 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/asn1c/enber.1 b/asn1c/enber.1
index 4a9edfc..365bc46 100644
--- a/asn1c/enber.1
+++ b/asn1c/enber.1
@@ -12,7 +12,7 @@
 .SH NAME
 enber \- Convert the unber XML output back into BER
 .SH SYNOPSIS
-enber [\fB-n\fR] [\fB-\fR] \fIinfile\fR...
+enber [\fB-n\fR] [\fB-\fR] [\fIinfile\fR...]
 .SH DESCRIPTION
 enber takes the XML-formatted files produced by \fIunber\fR\|(1) and converts
 them back into the BER format.
@@ -39,9 +39,9 @@
 .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!
+\&		\fB--\fR </I>
+\&		\fB#\fR Do not terminate:
+\&		\fB#\fR the absence of end-of-content octets is intentional!
 \&	</C>
 .Ve
 .SH SEE ALSO
diff --git a/asn1c/enber.c b/asn1c/enber.c
index 1ecef6f..12dae96 100644
--- a/asn1c/enber.c
+++ b/asn1c/enber.c
@@ -179,8 +179,10 @@
 	ssize_t ret;
 	(void)fname;
 
-	/* Find a tag opening angle bracket */
+	/* Skip the whitespace */
 	for(; *line == ' ' || *line == '\t'; line++);
+
+	/* Find a tag opening angle bracket */
 	op = line;
 	switch(*op) {
 	case '<':	/* That's what we want! A tag opening */
@@ -192,7 +194,9 @@
 	case '#':	/* This is a comment */
 			return 0;
 	default:
-		fprintf(stderr, "%s: Missing '<' after whitespace at line %d\n", fname, lineno);
+		fprintf(stderr,
+			"%s: Missing '<' after whitespace at line %d\n",
+			fname, lineno);
 		exit(EX_DATAERR);
 	}
 
diff --git a/asn1c/unber.1 b/asn1c/unber.1
index a31fabd..7f203d0 100644
--- a/asn1c/unber.1
+++ b/asn1c/unber.1
@@ -12,7 +12,7 @@
 .SH NAME
 unber \- ASN.1 BER Decoder
 .SH SYNOPSIS
-unber [\fB-1\fR] [\fB-i\fRindent] [\fB-p\fR] [\fB\-t\fR\fIdata-string\fR] [\fB-\fR] \fIinfile\fR...
+unber [\fB-1\fR] [\fB-i\fRindent] [\fB-p\fR] [\fB\-t\fR\fIdata-string\fR] [\fB-\fR] [\fIinfile\fR...]
 .SH DESCRIPTION
 unber takes the BER-encoded files and dumps their internal structure as human readable text.
 A single dash represents the standard input.
@@ -41,36 +41,39 @@
 .P
 The XML opening tag format is as follows:
 .Vb
-\&    <\fItform\fR T="\fItag\fR" TL="\fItl_len\fR" V="{Indefinite|\fIv_len\fR}" [A="\fItype\fR"] [\fIF\fR]>
+\&<\fBtform\fR O="\fBoff\fR" T="\fBtag\fR" TL="\fBtl_len\fR" V="{Indefinite|\fBv_len\fR}" [A="\fBtype\fR"] [\fBF\fR]>
 .Ve
 Where:
 .TP
-\fItform\fR
+\fBtform\fR
 Which form the value is in: primitive ("P") or constructed ("C") or constructed with indefinite length ("I")
 .TP
-\fItag\fR
-The tag class and value
+\fBoff\fR
+Offset of the encoded element in the unber input stream.
 .TP
-\fItl_len\fR
-The length of the TL (BER Tag and Length) encoding
+\fBtag\fR
+The tag class and value in human readable form.
 .TP
-\fIv_len\fR
-The length of the value (V, encoded by the L), may be "Indefinite"
+\fBtl_len\fR
+The length of the TL (BER Tag and Length) encoding.
 .TP
-\fItype\fR
-Likely name of the underlying ASN.1 type (for UNIVERSAL tags)
+\fBv_len\fR
+The length of the value (V, encoded by the L), may be "Indefinite".
 .TP
-[\fIF\fR]
-Indicates that the value was reformatted (pretty-printed)
+\fBtype\fR
+Likely name of the underlying ASN.1 type (for UNIVERSAL tags).
+.TP
+[\fBF\fR]
+Indicates that the value was reformatted (pretty-printed). This may only appear in the output as long \fB-p\fR command line option is \fInot\fR specified.
 .P
 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>
-\&      <C T="[UNIVERSAL 16]" TL="2" V="11" A="SEQUENCE">
-\&          <P T="[UNIVERSAL 2]" TL="2" V="4" A="INTEGER" F>832970823</P>
-\&      </C T="[UNIVERSAL 16]" A="SEQUENCE">
-\&  </I T="[UNIVERSAL 16]" A="SEQUENCE">
+\&<I O="0" T="[UNIVERSAL 16]" TL="2" V="Indefinite" A="SEQUENCE">
+\&  <P O="2" T="[UNIVERSAL 19]" TL="2" V="2" A="PrintableString">US</P>
+\&  <C O="6" T="[UNIVERSAL 16]" TL="2" V="11" A="SEQUENCE">
+\&    <P O="8" T="[UNIVERSAL 2]" TL="2" V="4" A="INTEGER" F>832970823</P>
+\&  </C T="[UNIVERSAL 16]" A="SEQUENCE">
+\&</I T="[UNIVERSAL 16]" A="SEQUENCE">
 .Ve
 .SH EXAMPLES
 Decode the given Tag/Length sequence given in hexadecimal form:
@@ -87,7 +90,7 @@
 .Ve
 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
+\&    cat \fI...\fR | unber \fB-p\fR \fB-\fR | enber \fB-\fR > \fIfilename.ber\fR
 .Ve
 .SH FOOTNOTES
 The constructed XML output is not necessarily well-formed.
diff --git a/asn1c/unber.c b/asn1c/unber.c
index 4a68c68..db00157 100644
--- a/asn1c/unber.c
+++ b/asn1c/unber.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -38,7 +38,7 @@
 
 #undef  COPYRIGHT
 #define COPYRIGHT       \
-	"Copyright (c) 2004 Lev Walkin <vlm@lionet.info>\n"
+	"Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>\n"
 
 static void usage(const char *av0);	/* Print the Usage screen and exit */
 static int process(const char *fname);	/* Perform the BER decoding */
@@ -128,10 +128,11 @@
 "  -t <data-string>   Decode the given tag[/length] sequence (e.g. -t \"bf20\")\n"
 "\n"
 "The XML opening tag format is as follows:\n"
-"  <tform T=\"tag\" TL=\"tl_len\" V=\"{Indefinite|v_len}\" [A=\"type\"] [F]>\n"
+"  <tform O=\"off\" T=\"tag\" TL=\"tl_len\" V=\"{Indefinite|v_len}\" [A=\"type\"] [F]>\n"
 "Where:\n"
 "  tform    Which form the value is in: constructed (\"C\", \"I\") or primitive (\"P\")\n"
-"  tag      The tag class and value\n"
+"  off      Offset of the encoded element in the unber input stream\n"
+"  tag      The tag class and value in human readable form\n"
 "  tl_len   The length of the TL (BER Tag and Length) encoding\n"
 "  v_len    The length of the value (V, encoded by the L), may be \"Indefinite\"\n"
 "  type     Likely name of the underlying ASN.1 type (for [UNIVERSAL n] tags)\n"
@@ -146,8 +147,8 @@
 	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, 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 pd_code_e process_deeper(const char *fname, FILE *fp, asn1c_integer_t *offset, int level, ssize_t limit, ssize_t *frame_size, int expect_eoc);
+static void print_TL(int fin, asn1c_integer_t offset, 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);
 
 /*
@@ -157,7 +158,8 @@
 process(const char *fname) {
 	FILE *fp;
 	pd_code_e pdc;
-	ssize_t decoded = 0;
+	asn1c_integer_t offset = 0;	/* Stream decoding position */
+	ssize_t frame_size = 0;		/* Single frame size */
 
 	if(strcmp(fname, "-")) {
 		fp = fopen(fname, "r");
@@ -173,7 +175,7 @@
 	 * Fetch out BER-encoded data until EOF or error.
 	 */
 	do {
-		pdc = process_deeper(fname, fp, 0, -1, &decoded, 0);
+		pdc = process_deeper(fname, fp, &offset, 0, -1, &frame_size, 0);
 	} while(pdc == PD_FINISHED && !single_type_decoding);
 
 	if(fp != stdin)
@@ -187,7 +189,7 @@
 /*
  * Process the TLV recursively.
  */
-static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit, ssize_t *decoded, int expect_eoc) {
+static pd_code_e process_deeper(const char *fname, FILE *fp, asn1c_integer_t *offset, int level, ssize_t limit, ssize_t *frame_size, int expect_eoc) {
 	unsigned char tagbuf[32];
 	ssize_t tblen = 0;
 	pd_code_e pdc = PD_FINISHED;
@@ -205,18 +207,21 @@
 
 		if(limit >= 0 && tblen >= limit) {
 			fprintf(stderr,
-				"%s: Too long TL sequence (%ld >= %ld). "
-					"Dangerous file\n",
-				fname, (long)tblen, (long)limit);
+				"%s: Too long TL sequence (%ld >= %ld)"
+				" at %" PRIdASN ". "
+				"Broken or maliciously constructed file\n",
+				fname, (long)tblen, (long)limit, *offset);
 			return PD_FAILED;
 		}
 
+		/* Get the next byte from the input stream */
 		ch = fgetc(fp);
 		if(ch == -1) {
-			if(tblen) {
+			if(tblen || limit) {
 				fprintf(stderr,
-					"%s: Unexpected end of file (TL)\n",
-					fname);
+					"%s: Unexpected end of file (TL)"
+					" at %" PRIdASN "\n",
+					fname, *offset);
 				return PD_FAILED;
 			} else {
 				return PD_EOF;
@@ -231,8 +236,9 @@
 		t_len = ber_fetch_tag(tagbuf, tblen, &tlv_tag);
 		switch(t_len) {
 		case -1:
-			fprintf(stderr, "%s: Fatal error deciphering tag\n",
-				fname);
+			fprintf(stderr, "%s: Fatal error decoding tag"
+				" at %" PRIdASN "+%ld\n",
+				fname, *offset, (long)tblen);
 			return PD_FAILED;
 		case 0:
 			/* More data expected */
@@ -247,8 +253,10 @@
 				tagbuf + t_len, tblen - t_len, &tlv_len);
 		switch(l_len) {
 		case -1:
-			fprintf(stderr, "%s: Fatal error deciphering length\n",
-				fname);
+			fprintf(stderr,
+				"%s: Fatal error decoding value length"
+				" at %" PRIdASN "\n",
+				fname, *offset + t_len);
 			return PD_FAILED;
 		case 0:
 			/* More data expected */
@@ -259,7 +267,7 @@
 		assert((t_len + l_len) == tblen);
 
 		if(!expect_eoc || tagbuf[0] || tagbuf[1])
-			print_TL(0, level, constr, tblen, tlv_tag, tlv_len);
+			print_TL(0, *offset, level, constr, tblen, tlv_tag, tlv_len);
 
 		if(limit != -1) {
 			/* If limit is set, account for the TL sequence */
@@ -275,11 +283,12 @@
 			}
 		}
 
-		*decoded += t_len + l_len;
+		*offset += t_len + l_len;
+		*frame_size += 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);
+			print_TL(1, *offset, level - 1, 1, 2, 0, -1);
 			return PD_FINISHED;
 		}
 
@@ -292,7 +301,7 @@
 			if(tlv_len != -1 && limit != -1) {
 				assert(limit >= tlv_len);
 			}
-			pdc = process_deeper(fname, fp, level + 1,
+			pdc = process_deeper(fname, fp, offset, level + 1,
 				tlv_len == -1 ? limit : tlv_len,
 				&dec, tlv_len == -1);
 			if(pdc == PD_FAILED) return pdc;
@@ -300,7 +309,7 @@
 				assert(limit >= dec);
 				limit -= dec;
 			}
-			*decoded += dec;
+			*frame_size += dec;
 			if(tlv_len == -1) {
 				tblen = 0;
 				continue;
@@ -314,10 +323,11 @@
 				assert(limit >= tlv_len);
 				limit -= tlv_len;
 			}
-			*decoded += tlv_len;
+			*offset += tlv_len;
+			*frame_size += tlv_len;
 		}
 
-		print_TL(1, level, constr, tblen, tlv_tag, tlv_len);
+		print_TL(1, *offset, level, constr, tblen, tlv_tag, tlv_len);
 
 		tblen = 0;
 	} while(1);
@@ -326,7 +336,7 @@
 }
 
 static void
-print_TL(int fin, int level, int constr, ssize_t tlen, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len) {
+print_TL(int fin, asn1c_integer_t offset, int level, int constr, ssize_t tlen, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len) {
 
 	if(fin && !constr) {
 		printf("</P>\n");
@@ -338,6 +348,10 @@
 
 	printf(constr ? ((tlv_len == -1) ? "I" : "C") : "P");
 
+	/* In case of <P>, <C>, <I>, </I> print out the offset */
+	if(fin == 0 || tlv_len == -1)
+		printf(" O=\"%" PRIdASN "\"", offset);
+
 	printf(" T=\"");
 	ber_tlv_tag_fwrite(tlv_tag, stdout);
 	printf("\"");
@@ -645,7 +659,7 @@
 	len = ber_fetch_tag(data, dsize, &tlv_tag);
 	switch(len) {
 	case -1:
-		fprintf(stderr, "TAG: Fatal error deciphering tag\n");
+		fprintf(stderr, "TAG: Fatal error decoding tag\n");
 		return -1;
 	case 0:
 		fprintf(stderr, "TAG: More data expected\n");
@@ -675,7 +689,7 @@
 		switch(len) {
 		case -1:
 			fprintf(stderr,
-				"LEN: Fatal error deciphering length\n");
+				"LEN: Fatal error decoding length\n");
 			return -1;
 		case 0:
 			fprintf(stderr, "LEN: More data expected\n");