summary refs log tree commit diff
path: root/crypto/src/asn1/PrimitiveDerEncodingSuffixed.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1/PrimitiveDerEncodingSuffixed.cs')
-rw-r--r--crypto/src/asn1/PrimitiveDerEncodingSuffixed.cs83
1 files changed, 83 insertions, 0 deletions
diff --git a/crypto/src/asn1/PrimitiveDerEncodingSuffixed.cs b/crypto/src/asn1/PrimitiveDerEncodingSuffixed.cs
new file mode 100644
index 000000000..7f9f38d99
--- /dev/null
+++ b/crypto/src/asn1/PrimitiveDerEncodingSuffixed.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal class PrimitiveDerEncodingSuffixed
+        : DerEncoding
+    {
+        private readonly byte[] m_contentsOctets;
+        private readonly byte m_contentsSuffix;
+
+        internal PrimitiveDerEncodingSuffixed(int tagClass, int tagNo, byte[] contentsOctets, byte contentsSuffix)
+            : base(tagClass, tagNo)
+        {
+            Debug.Assert(contentsOctets != null);
+            Debug.Assert(contentsOctets.Length > 0);
+            m_contentsOctets = contentsOctets;
+            m_contentsSuffix = contentsSuffix;
+        }
+
+        protected internal override int CompareLengthAndContents(DerEncoding other)
+        {
+            if (other is PrimitiveDerEncodingSuffixed suff)
+            {
+                return CompareSuffixed(this.m_contentsOctets, this.m_contentsSuffix,
+                                       suff.m_contentsOctets, suff.m_contentsSuffix);
+            }
+            else if (other is PrimitiveDerEncoding that)
+            {
+                int length = that.m_contentsOctets.Length;
+                if (length == 0)
+                    return this.m_contentsOctets.Length;
+
+                return CompareSuffixed(this.m_contentsOctets, this.m_contentsSuffix,
+                                       that.m_contentsOctets, that.m_contentsOctets[length - 1]);
+            }
+            else
+            {
+                throw new InvalidOperationException();
+            }
+        }
+
+        public override void Encode(Asn1OutputStream asn1Out)
+        {
+            asn1Out.WriteIdentifier(m_tagClass, m_tagNo);
+            asn1Out.WriteDL(m_contentsOctets.Length);
+            asn1Out.Write(m_contentsOctets, 0, m_contentsOctets.Length - 1);
+            asn1Out.WriteByte(m_contentsSuffix);
+        }
+
+        public override int GetLength()
+        {
+            return Asn1OutputStream.GetLengthOfEncodingDL(m_tagNo, m_contentsOctets.Length);
+        }
+
+        private static int CompareSuffixed(byte[] octetsA, byte suffixA, byte[] octetsB, byte suffixB)
+        {
+            Debug.Assert(octetsA.Length > 0);
+            Debug.Assert(octetsB.Length > 0);
+
+            int length = octetsA.Length;
+            if (length != octetsB.Length)
+                return length - octetsB.Length;
+
+            int last = length - 1;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            int c = octetsA.AsSpan(0, last).SequenceCompareTo(
+                    octetsB.AsSpan(0, last));
+            if (c != 0)
+                return c;
+#else
+            for (int i = 0; i < last; i++)
+            {
+                byte ai = octetsA[i], bi = octetsB[i];
+                if (ai != bi)
+                    return ai - bi;
+            }
+#endif
+
+            return suffixA - suffixB;
+        }
+    }
+}