Add int AsnWriter.Encode(Span)
authorJeremy Barton <jbarton@microsoft.com>
Wed, 17 Jun 2020 20:55:28 +0000 (13:55 -0700)
committerGitHub <noreply@github.com>
Wed, 17 Jun 2020 20:55:28 +0000 (13:55 -0700)
src/libraries/System.Formats.Asn1/ref/System.Formats.Asn1.cs
src/libraries/System.Formats.Asn1/src/Resources/Strings.resx
src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/Asn1Tag.cs
src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnWriter.cs
src/libraries/System.Formats.Asn1/tests/Writer/Asn1WriterTests.cs

index 921b832..788ad2f 100644 (file)
@@ -148,6 +148,7 @@ namespace System.Formats.Asn1
         public System.Formats.Asn1.AsnEncodingRules RuleSet { get { throw null; } }
         public void CopyTo(System.Formats.Asn1.AsnWriter destination) { }
         public byte[] Encode() { throw null; }
+        public int Encode(System.Span<byte> destination) { throw null; }
         public bool EncodedValueEquals(System.Formats.Asn1.AsnWriter other) { throw null; }
         public bool EncodedValueEquals(System.ReadOnlySpan<byte> other) { throw null; }
         public int GetEncodedLength() { throw null; }
index 18ac1f4..1057192 100644 (file)
@@ -57,8 +57,8 @@
   <resheader name="writer">
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <data name="Argument_EncodeDestinationTooSmall" xml:space="preserve">
-    <value>The destination is too small to hold the encoded value.</value>
+  <data name="Argument_DestinationTooShort" xml:space="preserve">
+    <value>Destination is too short.</value>
   </data>
   <data name="Argument_EnumeratedValueRequiresNonFlagsEnum" xml:space="preserve">
     <value>ASN.1 Enumerated values only apply to enum types without the [Flags] attribute.</value>
index 3ecf79d..4143cc4 100644 (file)
@@ -366,7 +366,7 @@ namespace System.Formats.Asn1
                 return bytesWritten;
             }
 
-            throw new ArgumentException(SR.Argument_EncodeDestinationTooSmall, nameof(destination));
+            throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
         }
 
         /// <summary>
index dcd7ead..e7f7a60 100644 (file)
@@ -85,7 +85,7 @@ namespace System.Formats.Asn1
         }
 
         /// <summary>
-        ///   Write the encoded representation of the data to <paramref name="destination"/>.
+        ///   Attempts to write the encoded representation of the data to <paramref name="destination"/>.
         /// </summary>
         /// <param name="destination">The buffer in which to write.</param>
         /// <param name="bytesWritten">
@@ -124,6 +124,30 @@ namespace System.Formats.Asn1
         }
 
         /// <summary>
+        ///   Writes the encoded representation of the data to <paramref name="destination"/>.
+        /// </summary>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <returns>
+        ///   The number of bytes written to <paramref name="destination" />.
+        /// </returns>
+        /// <exception cref="InvalidOperationException">
+        ///   A <see cref="PushSequence"/> or <see cref="PushSetOf"/> has not been closed via
+        ///   <see cref="PopSequence"/> or <see cref="PopSetOf"/>.
+        /// </exception>
+        public int Encode(Span<byte> destination)
+        {
+            // Since TryEncode doesn't have any side effects on the return false paths, just
+            // call it from here and do argument validation late.
+            if (!TryEncode(destination, out int bytesWritten))
+            {
+                throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+            }
+
+            Debug.Assert(bytesWritten == _offset);
+            return bytesWritten;
+        }
+
+        /// <summary>
         ///   Return a new array containing the encoded value.
         /// </summary>
         /// <returns>
@@ -168,7 +192,7 @@ namespace System.Formats.Asn1
         }
 
         /// <summary>
-        ///   Determines if <see cref="Encode"/> would produce an output identical to
+        ///   Determines if <see cref="Encode()"/> would produce an output identical to
         ///   <paramref name="other"/>.
         /// </summary>
         /// <returns>
@@ -185,7 +209,7 @@ namespace System.Formats.Asn1
         }
 
         /// <summary>
-        ///   Determines if <see cref="Encode"/> would produce an output identical to
+        ///   Determines if <see cref="Encode()"/> would produce an output identical to
         ///   <paramref name="other"/>.
         /// </summary>
         /// <returns>
index c20633d..8953885 100644 (file)
@@ -25,13 +25,17 @@ namespace System.Formats.Asn1.Tests.Writer
             Span<byte> dest = encoded2.AsSpan(0, encoded.Length - 1);
             Assert.False(writer.TryEncode(dest, out int bytesWritten), "writer.TryEncode (too small)");
             Assert.Equal(0, bytesWritten);
+            AssertExtensions.Throws<ArgumentException>("destination", () => writer.Encode(encoded2.AsSpan(0, encoded.Length - 1)));
             Assert.Equal(255, encoded2[0]);
             Assert.Equal(254, encoded2[encoded.Length]);
 
             dest = encoded2.AsSpan(0, encoded.Length);
             Assert.True(writer.TryEncode(dest, out bytesWritten), "writer.TryEncode (exact length)");
             Assert.Equal(encoded.Length, bytesWritten);
-            Assert.True(dest.SequenceEqual(encoded), "dest.SequenceEqual(encoded2) (exact length)");
+            Assert.True(dest.SequenceEqual(encoded), "dest.SequenceEqual(encoded2) (exact length) from TryEncode");
+            dest.Clear();
+            Assert.Equal(encoded.Length, writer.Encode(dest));
+            Assert.True(dest.SequenceEqual(encoded), "dest.SequenceEqual(encoded2) (exact length) from Encode");
             Assert.Equal(254, encoded2[encoded.Length]);
 
             // Start marker was obliterated, but the stop marker is still intact.  Keep it there.
@@ -40,7 +44,10 @@ namespace System.Formats.Asn1.Tests.Writer
             dest = encoded2.AsSpan();
             Assert.True(writer.TryEncode(dest, out bytesWritten), "writer.TryEncode (overly big)");
             Assert.Equal(encoded.Length, bytesWritten);
-            Assert.True(dest.Slice(0, bytesWritten).SequenceEqual(encoded), "dest.SequenceEqual(encoded2) (overly big)");
+            Assert.True(dest.Slice(0, bytesWritten).SequenceEqual(encoded), "dest.SequenceEqual(encoded2) (overly big) from TryEncode");
+            dest.Slice(0, bytesWritten).Clear();
+            Assert.Equal(encoded.Length, writer.Encode(dest));
+            Assert.True(dest.Slice(0, bytesWritten).SequenceEqual(encoded), "dest.SequenceEqual(encoded2) (overly big) from Encode");
             Assert.Equal(254, encoded2[encoded.Length]);
 
             Assert.True(writer.EncodedValueEquals(encoded));