diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs
index 0e772010f..b09322234 100644
--- a/crypto/src/asn1/Asn1InputStream.cs
+++ b/crypto/src/asn1/Asn1InputStream.cs
@@ -359,56 +359,13 @@ namespace Org.BouncyCastle.Asn1
return buf;
}
- private static char[] GetBmpCharBuffer(DefiniteLengthInputStream defIn)
- {
- int remainingBytes = defIn.Remaining;
- if (0 != (remainingBytes & 1))
- throw new IOException("malformed BMPString encoding encountered");
-
- char[] str = new char[remainingBytes / 2];
- int stringPos = 0;
-
- byte[] buf = new byte[8];
- while (remainingBytes >= 8)
- {
- if (Streams.ReadFully(defIn, buf, 0, 8) != 8)
- throw new EndOfStreamException("EOF encountered in middle of BMPString");
-
- str[stringPos ] = (char)((buf[0] << 8) | (buf[1] & 0xFF));
- str[stringPos + 1] = (char)((buf[2] << 8) | (buf[3] & 0xFF));
- str[stringPos + 2] = (char)((buf[4] << 8) | (buf[5] & 0xFF));
- str[stringPos + 3] = (char)((buf[6] << 8) | (buf[7] & 0xFF));
- stringPos += 4;
- remainingBytes -= 8;
- }
- if (remainingBytes > 0)
- {
- if (Streams.ReadFully(defIn, buf, 0, remainingBytes) != remainingBytes)
- throw new EndOfStreamException("EOF encountered in middle of BMPString");
-
- int bufPos = 0;
- do
- {
- int b1 = buf[bufPos++] << 8;
- int b2 = buf[bufPos++] & 0xFF;
- str[stringPos++] = (char)(b1 | b2);
- }
- while (bufPos < remainingBytes);
- }
-
- if (0 != defIn.Remaining || str.Length != stringPos)
- throw new InvalidOperationException();
-
- return str;
- }
-
internal static Asn1Object CreatePrimitiveDerObject(int tagNo, DefiniteLengthInputStream defIn,
byte[][] tmpBuffers)
{
switch (tagNo)
{
case Asn1Tags.BmpString:
- return DerBmpString.CreatePrimitive(GetBmpCharBuffer(defIn));
+ return CreateDerBmpString(defIn);
case Asn1Tags.Boolean:
return DerBoolean.CreatePrimitive(GetBuffer(defIn, tmpBuffers));
case Asn1Tags.Enumerated:
@@ -463,5 +420,88 @@ namespace Org.BouncyCastle.Asn1
throw new IOException("unknown tag " + tagNo + " encountered");
}
}
+
+ private static DerBmpString CreateDerBmpString(DefiniteLengthInputStream defIn)
+ {
+ int remainingBytes = defIn.Remaining;
+ if (0 != (remainingBytes & 1))
+ throw new IOException("malformed BMPString encoding encountered");
+
+ int length = remainingBytes / 2;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DerBmpString.CreatePrimitive(length, defIn, (str, defIn) =>
+ {
+ int stringPos = 0;
+
+ Span<byte> buf = stackalloc byte[8];
+ while (remainingBytes >= 8)
+ {
+ if (Streams.ReadFully(defIn, buf) != 8)
+ throw new EndOfStreamException("EOF encountered in middle of BMPString");
+
+ str[stringPos ] = (char)((buf[0] << 8) | (buf[1] & 0xFF));
+ str[stringPos + 1] = (char)((buf[2] << 8) | (buf[3] & 0xFF));
+ str[stringPos + 2] = (char)((buf[4] << 8) | (buf[5] & 0xFF));
+ str[stringPos + 3] = (char)((buf[6] << 8) | (buf[7] & 0xFF));
+ stringPos += 4;
+ remainingBytes -= 8;
+ }
+ if (remainingBytes > 0)
+ {
+ if (Streams.ReadFully(defIn, buf) != remainingBytes)
+ throw new EndOfStreamException("EOF encountered in middle of BMPString");
+
+ int bufPos = 0;
+ do
+ {
+ int b1 = buf[bufPos++] << 8;
+ int b2 = buf[bufPos++] & 0xFF;
+ str[stringPos++] = (char)(b1 | b2);
+ }
+ while (bufPos < remainingBytes);
+ }
+
+ if (0 != defIn.Remaining || str.Length != stringPos)
+ throw new InvalidOperationException();
+ });
+#else
+ char[] str = new char[length];
+ int stringPos = 0;
+
+ byte[] buf = new byte[8];
+ while (remainingBytes >= 8)
+ {
+ if (Streams.ReadFully(defIn, buf, 0, 8) != 8)
+ throw new EndOfStreamException("EOF encountered in middle of BMPString");
+
+ str[stringPos ] = (char)((buf[0] << 8) | (buf[1] & 0xFF));
+ str[stringPos + 1] = (char)((buf[2] << 8) | (buf[3] & 0xFF));
+ str[stringPos + 2] = (char)((buf[4] << 8) | (buf[5] & 0xFF));
+ str[stringPos + 3] = (char)((buf[6] << 8) | (buf[7] & 0xFF));
+ stringPos += 4;
+ remainingBytes -= 8;
+ }
+ if (remainingBytes > 0)
+ {
+ if (Streams.ReadFully(defIn, buf, 0, remainingBytes) != remainingBytes)
+ throw new EndOfStreamException("EOF encountered in middle of BMPString");
+
+ int bufPos = 0;
+ do
+ {
+ int b1 = buf[bufPos++] << 8;
+ int b2 = buf[bufPos++] & 0xFF;
+ str[stringPos++] = (char)(b1 | b2);
+ }
+ while (bufPos < remainingBytes);
+ }
+
+ if (0 != defIn.Remaining || str.Length != stringPos)
+ throw new InvalidOperationException();
+
+ return DerBmpString.CreatePrimitive(str);
+#endif
+ }
}
}
diff --git a/crypto/src/asn1/DerBMPString.cs b/crypto/src/asn1/DerBMPString.cs
index 284a4b830..bf21fa424 100644
--- a/crypto/src/asn1/DerBMPString.cs
+++ b/crypto/src/asn1/DerBMPString.cs
@@ -1,4 +1,7 @@
using System;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+using System.Buffers;
+#endif
using System.IO;
using Org.BouncyCastle.Utilities;
@@ -82,6 +85,16 @@ namespace Org.BouncyCastle.Asn1
throw new ArgumentException("malformed BMPString encoding encountered", "contents");
int charLen = byteLen / 2;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ m_str = string.Create(charLen, contents, (chars, bytes) =>
+ {
+ for (int i = 0; i < chars.Length; ++i)
+ {
+ chars[i] = (char)((bytes[2 * i] << 8) | (bytes[2 * i + 1] & 0xff));
+ }
+ });
+#else
char[] cs = new char[charLen];
for (int i = 0; i != charLen; i++)
@@ -90,8 +103,10 @@ namespace Org.BouncyCastle.Asn1
}
m_str = new string(cs);
+#endif
}
+#if !(NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER)
internal DerBmpString(char[] str)
{
if (str == null)
@@ -99,6 +114,7 @@ namespace Org.BouncyCastle.Asn1
m_str = new string(str);
}
+#endif
/**
* basic constructor
@@ -157,10 +173,17 @@ namespace Org.BouncyCastle.Asn1
return new DerBmpString(contents);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal static DerBmpString CreatePrimitive<TState>(int length, TState state, SpanAction<char, TState> action)
+ {
+ return new DerBmpString(string.Create(length, state, action));
+ }
+#else
internal static DerBmpString CreatePrimitive(char[] str)
{
// TODO[asn1] Asn1InputStream has a validator/converter that should be unified in this class somehow
return new DerBmpString(str);
}
+#endif
}
}
|