summary refs log tree commit diff
path: root/crypto/src/asn1
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-02-27 20:00:46 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-02-27 20:00:46 +0700
commitca24841d2e00c51a0a52df522139fcb096e0995f (patch)
treeea5d86bd2127a80ecc64a0b44f8b114f67291aef /crypto/src/asn1
parentBcpg: update signature subpackets (diff)
downloadBouncyCastle.NET-ed25519-ca24841d2e00c51a0a52df522139fcb096e0995f.tar.xz
Use string.Create when available
Diffstat (limited to 'crypto/src/asn1')
-rw-r--r--crypto/src/asn1/Asn1InputStream.cs128
-rw-r--r--crypto/src/asn1/DerBMPString.cs23
2 files changed, 107 insertions, 44 deletions
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
     }
 }