Skip to content

Commit f4ec318

Browse files
committed
updated AsnFormatter by using Span<T> and added new BinaryToString overload.
1 parent 6718204 commit f4ec318

2 files changed

Lines changed: 86 additions & 70 deletions

File tree

Asn1Parser/AsnFormatter.cs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,52 @@ public static class AsnFormatter {
3838
/// </list>
3939
/// </remarks>
4040
public static String BinaryToString(Byte[] rawData, EncodingType encoding = EncodingType.HexRaw, EncodingFormat format = EncodingFormat.CRLF, Int32 start = 0, Int32 count = 0, Boolean forceUpperCase = false) {
41+
Span<Byte> slice = count == 0 ? rawData.AsSpan() : rawData.AsSpan().Slice(start, count);
42+
return BinaryToString(slice, encoding, format, forceUpperCase);
43+
}
44+
/// <summary>
45+
/// Converts and formats byte array to a string. See <see cref="EncodingType"/> for encoding examples.
46+
/// </summary>
47+
/// <param name="rawData">Byte array to format.</param>
48+
/// <param name="encoding">Specifies the encoding for formatting. Default is <strong>HexRaw</strong></param>
49+
/// <param name="format">
50+
/// Specifies the encoding options. The default behavior is to use a carriage return/line feed
51+
/// (CR/LF) pair (0x0D/0x0A) to represent a new line.
52+
/// </param>
53+
/// <param name="forceUpperCase">
54+
/// Specifies whether the force hex octet representation in upper case. Default is lower case.
55+
/// <para>
56+
/// This parameter has effect only when hex encoding is selected in the <strong>encoding</strong> parameter:
57+
/// <strong>Hex</strong>, <strong>HexRaw</strong>, <strong>HexAddress</strong>, <strong>HexAscii</strong>
58+
/// and <strong>HexAsciiAddress</strong>. For other values, this parameter is silently ignored.
59+
/// </para>
60+
/// </param>
61+
/// <exception cref="ArgumentException">An invalid encoding type was specified.</exception>
62+
/// <returns>Encoded and formatted string.</returns>
63+
/// <remarks>
64+
/// This method do not support the following encoding types:
65+
/// <list type="bullet">
66+
/// <item><description>Binary</description></item>
67+
/// <item><description>Base64Any</description></item>
68+
/// <item><description>StringAny</description></item>
69+
/// <item><description>HexAny</description></item>
70+
/// </list>
71+
/// </remarks>
72+
public static String BinaryToString(ReadOnlySpan<Byte> rawData, EncodingType encoding = EncodingType.HexRaw, EncodingFormat format = EncodingFormat.CRLF, Boolean forceUpperCase = false) {
4173
if (rawData == null || rawData.Length == 0) {
4274
return String.Empty;
4375
}
4476
if (PemHeader.ContainsEncoding(encoding)) {
45-
return BinaryToStringFormatter.ToBase64(rawData, encoding, format, start, count);
77+
return BinaryToStringFormatter.ToBase64(rawData, encoding, format);
4678
}
4779

4880
return encoding switch {
49-
EncodingType.Base64 => BinaryToStringFormatter.ToBase64(rawData, encoding, format, start, count),
50-
EncodingType.Hex => BinaryToStringFormatter.ToHex(rawData, format, start, count, forceUpperCase),
51-
EncodingType.HexAddress => BinaryToStringFormatter.ToHexAddress(rawData, format, start, count, forceUpperCase),
52-
EncodingType.HexAscii => BinaryToStringFormatter.ToHexAscii(rawData, format, start, count, forceUpperCase),
53-
EncodingType.HexAsciiAddress => BinaryToStringFormatter.ToHexAddressAndAscii(rawData, format, start, count, forceUpperCase),
54-
EncodingType.HexRaw => BinaryToStringFormatter.ToHexRaw(rawData, start, count, forceUpperCase),
81+
EncodingType.Base64 => BinaryToStringFormatter.ToBase64(rawData, encoding, format),
82+
EncodingType.Hex => BinaryToStringFormatter.ToHex(rawData, format, forceUpperCase),
83+
EncodingType.HexAddress => BinaryToStringFormatter.ToHexAddress(rawData, format, forceUpperCase),
84+
EncodingType.HexAscii => BinaryToStringFormatter.ToHexAscii(rawData, format, forceUpperCase),
85+
EncodingType.HexAsciiAddress => BinaryToStringFormatter.ToHexAddressAndAscii(rawData, format, forceUpperCase),
86+
EncodingType.HexRaw => BinaryToStringFormatter.ToHexRaw(rawData, forceUpperCase),
5587
_ => throw new ArgumentException("Specified encoding is invalid.")
5688
};
5789
}
@@ -91,19 +123,19 @@ public static String BinaryToString(Asn1Reader asn, EncodingType encoding = Enco
91123
return String.Empty;
92124
}
93125
if ((Int32)encoding > 20 && (Int32)encoding < 45) {
94-
return BinaryToStringFormatter.ToBase64(asn.GetRawData(), encoding, format, asn.PayloadStartOffset, asn.PayloadLength);
126+
return BinaryToStringFormatter.ToBase64(asn.GetRawDataAsSpan(), encoding, format);
95127
}
96128
if (PemHeader.ContainsEncoding(encoding)) {
97-
return BinaryToStringFormatter.ToBase64(asn.GetRawData(), encoding, format, asn.PayloadStartOffset, asn.PayloadLength);
129+
return BinaryToStringFormatter.ToBase64(asn.GetRawDataAsSpan(), encoding, format);
98130
}
99131

100132
return encoding switch {
101-
EncodingType.Base64 => BinaryToStringFormatter.ToBase64(asn.GetRawData(), encoding, format, asn.PayloadStartOffset, asn.PayloadLength),
102-
EncodingType.Hex => BinaryToStringFormatter.ToHex(asn.GetRawData(), format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase),
103-
EncodingType.HexAddress => BinaryToStringFormatter.ToHexAddress(asn.GetRawData(), format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase),
104-
EncodingType.HexAscii => BinaryToStringFormatter.ToHexAscii(asn.GetRawData(), format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase),
105-
EncodingType.HexAsciiAddress => BinaryToStringFormatter.ToHexAddressAndAscii(asn.GetRawData(), format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase),
106-
EncodingType.HexRaw => BinaryToStringFormatter.ToHexRaw(asn.GetRawData(), asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase),
133+
EncodingType.Base64 => BinaryToStringFormatter.ToBase64(asn.GetRawDataAsSpan(), encoding, format),
134+
EncodingType.Hex => BinaryToStringFormatter.ToHex(asn.GetRawDataAsSpan(), format, forceUpperCase),
135+
EncodingType.HexAddress => BinaryToStringFormatter.ToHexAddress(asn.GetRawDataAsSpan(), format, forceUpperCase),
136+
EncodingType.HexAscii => BinaryToStringFormatter.ToHexAscii(asn.GetRawDataAsSpan(), format, forceUpperCase),
137+
EncodingType.HexAsciiAddress => BinaryToStringFormatter.ToHexAddressAndAscii(asn.GetRawDataAsSpan(), format, forceUpperCase),
138+
EncodingType.HexRaw => BinaryToStringFormatter.ToHexRaw(asn.GetRawDataAsSpan(), forceUpperCase),
107139
_ => throw new ArgumentException("Specified encoding is invalid.")
108140
};
109141
}

Asn1Parser/BinaryToStringFormatter.cs

Lines changed: 39 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,27 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
42
using System.Text;
53

64
namespace SysadminsLV.Asn1Parser;
75

86
static class BinaryToStringFormatter {
9-
public static String ToHexRaw(IReadOnlyList<Byte> rawData, Int32 start, Int32 count, Boolean forceUpperCase) {
10-
count = getCount(rawData.Count, start, count);
7+
public static String ToHexRaw(ReadOnlySpan<Byte> rawData, Boolean forceUpperCase) {
118
var SB = new StringBuilder();
12-
for (Int32 i = start; i < start + count; i++) {
13-
byteToHexOctet(SB, rawData[i], forceUpperCase);
9+
foreach (Byte b in rawData) {
10+
byteToHexOctet(SB, b, forceUpperCase);
1411
}
12+
1513
return SB.ToString();
1614
}
17-
public static String ToHex(IReadOnlyList<Byte> rawData, EncodingFormat format, Int32 start, Int32 count, Boolean forceUpperCase) {
18-
count = getCount(rawData.Count, start, count);
15+
public static String ToHex(ReadOnlySpan<Byte> rawData, EncodingFormat format, Boolean forceUpperCase) {
1916
var sb = new StringBuilder();
20-
Int32 n = 0;
21-
for (Int32 index = start; index < start + count; index++) {
22-
n++;
17+
for (Int32 index = 0; index < rawData.Length; index++) {
2318
byteToHexOctet(sb, rawData[index], forceUpperCase);
24-
if (index == start) {
19+
if (index == 0) {
2520
sb.Append(" ");
2621
continue;
2722
}
28-
if (n % 16 == 0) {
23+
if ((index + 1) % 16 == 0) {
24+
// if current octet is the last octet in a row, append EOL format
2925
switch (format) {
3026
case EncodingFormat.NOCRLF:
3127
sb.Append(" ");
@@ -35,7 +31,7 @@ public static String ToHex(IReadOnlyList<Byte> rawData, EncodingFormat format, I
3531
case EncodingFormat.NOCR:
3632
sb.Append("\n"); break;
3733
}
38-
} else if (n % 8 == 0 && format != EncodingFormat.NOCRLF) {
34+
} else if ((index + 1) % 8 == 0 && format != EncodingFormat.NOCRLF) {
3935
sb.Append(" ");
4036
} else {
4137
sb.Append(" ");
@@ -44,13 +40,12 @@ public static String ToHex(IReadOnlyList<Byte> rawData, EncodingFormat format, I
4440

4541
return finalizeBinaryToString(sb, format);
4642
}
47-
public static String ToHexAddress(IReadOnlyList<Byte> rawData, EncodingFormat format, Int32 start, Int32 count, Boolean forceUpperCase) {
48-
count = getCount(rawData.Count, start, count);
43+
public static String ToHexAddress(ReadOnlySpan<Byte> rawData, EncodingFormat format, Boolean forceUpperCase) {
4944
var sb = new StringBuilder();
50-
Int32 rowCount = 0, n = 0;
51-
Int32 addrLength = getAddrLength(rawData.Count);
52-
for (Int32 index = start; index < start + count; index++) {
53-
if (n % 16 == 0) {
45+
Int32 rowCount = 0;
46+
Int32 addrLength = getAddrLength(rawData.Length);
47+
for (Int32 index = 0; index < rawData.Length; index++) {
48+
if (index % 16 == 0) {
5449
String hexAddress = Convert.ToString(rowCount, 16).PadLeft(addrLength, '0');
5550
if (forceUpperCase) {
5651
hexAddress = hexAddress.ToUpper();
@@ -60,66 +55,64 @@ public static String ToHexAddress(IReadOnlyList<Byte> rawData, EncodingFormat fo
6055
rowCount += 16;
6156
}
6257
byteToHexOctet(sb, rawData[index], forceUpperCase);
63-
if (index == start) {
58+
if (index == 0) {
6459
sb.Append(" ");
65-
n++;
6660
continue;
6761
}
68-
if ((n + 1) % 16 == 0) {
62+
63+
if ((index + 1) % 16 == 0) {
64+
// if current octet is the last octet in a row, append EOL format
6965
sb.Append(format == EncodingFormat.NOCR ? "\n" : "\r\n");
70-
} else if ((n + 1) % 8 == 0) {
66+
} else if ((index + 1) % 8 == 0) {
67+
// if current octet is center octet in a row, append extra space
7168
sb.Append(" ");
7269
} else {
7370
sb.Append(" ");
7471
}
75-
n++;
7672
}
7773

7874
return finalizeBinaryToString(sb, format);
7975
}
80-
public static String ToHexAscii(Byte[] rawData, EncodingFormat format, Int32 start, Int32 count, Boolean forceUpperCase) {
81-
count = getCount(rawData.Length, start, count);
76+
public static String ToHexAscii(ReadOnlySpan<Byte> rawData, EncodingFormat format, Boolean forceUpperCase) {
8277
var sb = new StringBuilder();
8378
var ascii = new StringBuilder(8);
84-
Int32 n = 0;
85-
for (Int32 index = 0; index < start + count; index++) {
86-
n++;
79+
for (Int32 index = 0; index < rawData.Length; index++) {
8780
byteToHexOctet(sb, rawData[index], forceUpperCase);
8881
Char c = rawData[index] < 32 || rawData[index] > 126
8982
? '.'
9083
: (Char)rawData[index];
9184
ascii.Append(c);
92-
if (index == start) {
85+
if (index == 0) {
9386
sb.Append(" ");
9487
continue;
9588
}
96-
if (n % 16 == 0) {
89+
if ((index + 1) % 16 == 0) {
9790
sb.Append(" ");
9891
sb.Append(ascii);
9992
ascii.Clear();
93+
// if current octet is the last octet in a row, append EOL format
10094
sb.Append(format == EncodingFormat.NOCR ? "\n" : "\r\n");
101-
} else if (n % 8 == 0) {
95+
} else if ((index + 1) % 8 == 0) {
10296
sb.Append(" ");
10397
} else {
10498
sb.Append(" ");
10599
}
106100
// handle last byte to complete partial ASCII panel.
107-
if (n == count) {
108-
sb.Append(getAsciiPadding(n));
101+
if (index + 1 == rawData.Length) {
102+
sb.Append(getAsciiPadding(index + 1));
109103
sb.Append(ascii);
110104
}
111105
}
112106

113107
return finalizeBinaryToString(sb, format);
114108
}
115-
public static String ToHexAddressAndAscii(IReadOnlyList<Byte> rawData, EncodingFormat format, Int32 start, Int32 count, Boolean forceUpperCase) {
116-
count = getCount(rawData.Count, start, count);
109+
public static String ToHexAddressAndAscii(ReadOnlySpan<Byte> rawData, EncodingFormat format, Boolean forceUpperCase) {
117110
var sb = new StringBuilder();
118111
var ascii = new StringBuilder(8);
119-
Int32 addrLength = getAddrLength(rawData.Count);
120-
Int32 rowCount = 0, n = 0;
121-
for (Int32 index = 0; index < start + count; index++) {
122-
if (n % 16 == 0) {
112+
Int32 addrLength = getAddrLength(rawData.Length);
113+
Int32 rowCount = 0;
114+
for (Int32 index = 0; index < rawData.Length; index++) {
115+
if (index % 16 == 0) {
123116
String hexAddress = Convert.ToString(rowCount, 16).PadLeft(addrLength, '0');
124117
if (forceUpperCase) {
125118
hexAddress = hexAddress.ToUpper();
@@ -135,32 +128,29 @@ public static String ToHexAddressAndAscii(IReadOnlyList<Byte> rawData, EncodingF
135128
ascii.Append(c);
136129
if (index == 0) {
137130
sb.Append(" ");
138-
n++;
139131
continue;
140132
}
141-
if ((n + 1) % 16 == 0) {
133+
if ((index + 1) % 16 == 0) {
142134
sb.Append(" ");
143135
sb.Append(ascii);
144136
ascii.Clear();
145137
sb.Append(format == EncodingFormat.NOCR ? "\n" : "\r\n");
146-
} else if ((n + 1) % 8 == 0) {
138+
} else if ((index + 1) % 8 == 0) {
147139
sb.Append(" ");
148140
} else {
149141
sb.Append(" ");
150142
}
151143
// handle last byte to complete partial ASCII panel.
152-
if (n + 1 == count) {
144+
if (index + 1 == rawData.Length) {
153145
sb.Append(getAsciiPadding(index + 1));
154146
sb.Append(ascii);
155147
}
156-
n++;
157148
}
158149

159150
return finalizeBinaryToString(sb, format);
160151
}
161-
public static String ToBase64(IReadOnlyCollection<Byte> rawData, EncodingType encoding, EncodingFormat format, Int32 start, Int32 count) {
162-
count = getCount(rawData.Count, start, count);
163-
var sb = new StringBuilder(Convert.ToBase64String(rawData.Skip(start).Take(count).ToArray()));
152+
public static String ToBase64(ReadOnlySpan<Byte> rawData, EncodingType encoding, EncodingFormat format) {
153+
var sb = new StringBuilder(Convert.ToBase64String(rawData.ToArray()));
164154
String splitter;
165155
switch (format) {
166156
case EncodingFormat.NOCR:
@@ -229,12 +219,6 @@ static String getAsciiPadding(Int32 index) {
229219

230220
return new String(' ', (17 - remainder) * 3);
231221
}
232-
static Int32 getCount(Int32 size, Int32 start, Int32 count) {
233-
if (start < 0 || start >= size) {
234-
throw new OverflowException();
235-
}
236-
return count == 0 || start + count > size ? size - start : count;
237-
}
238222
static Int32 getAddrLength(Int32 size) {
239223
Int32 div = size / 16;
240224
if (size % 16 > 0) { div++; }

0 commit comments

Comments
 (0)