summary refs log tree commit diff
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
parentBcpg: update signature subpackets (diff)
downloadBouncyCastle.NET-ed25519-ca24841d2e00c51a0a52df522139fcb096e0995f.tar.xz
Use string.Create when available
-rw-r--r--crypto/src/asn1/Asn1InputStream.cs128
-rw-r--r--crypto/src/asn1/DerBMPString.cs23
-rw-r--r--crypto/src/math/ec/abc/SimpleBigDecimal.cs9
-rw-r--r--crypto/src/openpgp/SXprUtilities.cs10
-rw-r--r--crypto/src/util/Strings.cs10
5 files changed, 131 insertions, 49 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
     }
 }
diff --git a/crypto/src/math/ec/abc/SimpleBigDecimal.cs b/crypto/src/math/ec/abc/SimpleBigDecimal.cs
index d5664dbfd..c69d02f0c 100644
--- a/crypto/src/math/ec/abc/SimpleBigDecimal.cs
+++ b/crypto/src/math/ec/abc/SimpleBigDecimal.cs
@@ -196,19 +196,18 @@ namespace Org.BouncyCastle.Math.EC.Abc
 			}
 			string leftOfPoint = floorBigInt.ToString();
 
-			char[] fractCharArr = new char[scale];
-				string fractStr = fract.ToString(2);
+			char[] rightOfPoint = new char[scale];
+			string fractStr = fract.ToString(2);
 			int fractLen = fractStr.Length;
 			int zeroes = scale - fractLen;
 			for (int i = 0; i < zeroes; i++)
 			{
-				fractCharArr[i] = '0';
+				rightOfPoint[i] = '0';
 			}
 			for (int j = 0; j < fractLen; j++)
 			{
-				fractCharArr[zeroes + j] = fractStr[j];
+				rightOfPoint[zeroes + j] = fractStr[j];
 			}
-			string rightOfPoint = new string(fractCharArr);
 
 			StringBuilder sb = new StringBuilder(leftOfPoint);
 			sb.Append(".");
diff --git a/crypto/src/openpgp/SXprUtilities.cs b/crypto/src/openpgp/SXprUtilities.cs
index d7969813f..835d3c347 100644
--- a/crypto/src/openpgp/SXprUtilities.cs
+++ b/crypto/src/openpgp/SXprUtilities.cs
@@ -34,6 +34,15 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         {
             int len = ReadLength(input, ch);
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return string.Create(len, input, (chars, input) =>
+            {
+                for (int i = 0; i < chars.Length; ++i)
+                {
+                    chars[i] = Convert.ToChar(input.ReadByte());
+                }
+            });
+#else
             char[] chars = new char[len];
 
             for (int i = 0; i != chars.Length; i++)
@@ -42,6 +51,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
 
             return new string(chars);
+#endif
         }
 
         internal static byte[] ReadBytes(Stream input, int ch)
diff --git a/crypto/src/util/Strings.cs b/crypto/src/util/Strings.cs
index b1a63a3a1..147b6d349 100644
--- a/crypto/src/util/Strings.cs
+++ b/crypto/src/util/Strings.cs
@@ -18,12 +18,22 @@ namespace Org.BouncyCastle.Utilities
 
         public static string FromByteArray(byte[] bs)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return string.Create(bs.Length, bs, (chars, bytes) =>
+            {
+                for (int i = 0; i < chars.Length; ++i)
+                {
+                    chars[i] = Convert.ToChar(bytes[i]);
+                }
+            });
+#else
             char[] cs = new char[bs.Length];
             for (int i = 0; i < cs.Length; ++i)
             {
                 cs[i] = Convert.ToChar(bs[i]);
             }
             return new string(cs);
+#endif
         }
 
         public static byte[] ToByteArray(char[] cs)