From abe0572ea59671d9444b61bf3ad4458518c2805d Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Thu, 1 Aug 2019 15:20:29 +0700 Subject: Misc. ASN.1 updates from bc-java --- crypto/src/asn1/Asn1EncodableVector.cs | 248 ++++++++++++++++++++++----------- 1 file changed, 169 insertions(+), 79 deletions(-) (limited to 'crypto/src/asn1/Asn1EncodableVector.cs') diff --git a/crypto/src/asn1/Asn1EncodableVector.cs b/crypto/src/asn1/Asn1EncodableVector.cs index 8a97e8b4f..987aa5298 100644 --- a/crypto/src/asn1/Asn1EncodableVector.cs +++ b/crypto/src/asn1/Asn1EncodableVector.cs @@ -1,101 +1,191 @@ using System; using System.Collections; -using Org.BouncyCastle.Utilities; - namespace Org.BouncyCastle.Asn1 { + /** + * Mutable class for building ASN.1 constructed objects such as SETs or SEQUENCEs. + */ public class Asn1EncodableVector - : IEnumerable + : IEnumerable { - private IList v = Platform.CreateArrayList(); - - public static Asn1EncodableVector FromEnumerable( - IEnumerable e) - { - Asn1EncodableVector v = new Asn1EncodableVector(); - foreach (Asn1Encodable obj in e) - { - v.Add(obj); - } - return v; - } - -// public Asn1EncodableVector() -// { -// } - - public Asn1EncodableVector( - params Asn1Encodable[] v) - { - Add(v); - } - -// public void Add( -// Asn1Encodable obj) -// { -// v.Add(obj); -// } - - public void Add( - params Asn1Encodable[] objs) - { - foreach (Asn1Encodable obj in objs) - { - v.Add(obj); - } - } - - public void AddOptional( - params Asn1Encodable[] objs) - { - if (objs != null) - { - foreach (Asn1Encodable obj in objs) - { - if (obj != null) - { - v.Add(obj); - } - } - } - } + internal static readonly Asn1Encodable[] EmptyElements = new Asn1Encodable[0]; + + private const int DefaultCapacity = 10; + + private Asn1Encodable[] elements; + private int elementCount; + private bool copyOnWrite; + + public static Asn1EncodableVector FromEnumerable(IEnumerable e) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + foreach (Asn1Encodable obj in e) + { + v.Add(obj); + } + return v; + } + + public Asn1EncodableVector() + : this(DefaultCapacity) + { + } + + public Asn1EncodableVector(int initialCapacity) + { + if (initialCapacity < 0) + throw new ArgumentException("must not be negative", "initialCapacity"); + + this.elements = (initialCapacity == 0) ? EmptyElements : new Asn1Encodable[initialCapacity]; + this.elementCount = 0; + this.copyOnWrite = false; + } + + public Asn1EncodableVector(params Asn1Encodable[] v) + : this() + { + Add(v); + } + + public void Add(Asn1Encodable element) + { + if (null == element) + throw new ArgumentNullException("element"); + + int capacity = elements.Length; + int minCapacity = elementCount + 1; + if ((minCapacity > capacity) | copyOnWrite) + { + Reallocate(minCapacity); + } + + this.elements[elementCount] = element; + this.elementCount = minCapacity; + } + + public void Add(params Asn1Encodable[] objs) + { + foreach (Asn1Encodable obj in objs) + { + Add(obj); + } + } + + public void AddOptional(params Asn1Encodable[] objs) + { + if (objs != null) + { + foreach (Asn1Encodable obj in objs) + { + if (obj != null) + { + Add(obj); + } + } + } + } public void AddOptionalTagged(bool isExplicit, int tagNo, Asn1Encodable obj) { if (null != obj) { - v.Add(new DerTaggedObject(isExplicit, tagNo, obj)); + Add(new DerTaggedObject(isExplicit, tagNo, obj)); } } - public Asn1Encodable this[ - int index] - { - get { return (Asn1Encodable) v[index]; } - } + public void AddAll(Asn1EncodableVector other) + { + if (null == other) + throw new ArgumentNullException("other"); - [Obsolete("Use 'object[index]' syntax instead")] - public Asn1Encodable Get( - int index) + int otherElementCount = other.Count; + if (otherElementCount < 1) + return; + + int capacity = elements.Length; + int minCapacity = elementCount + otherElementCount; + if ((minCapacity > capacity) | copyOnWrite) + { + Reallocate(minCapacity); + } + + int i = 0; + do + { + Asn1Encodable otherElement = other[i]; + if (null == otherElement) + throw new NullReferenceException("'other' elements cannot be null"); + + this.elements[elementCount + i] = otherElement; + } + while (++i < otherElementCount); + + this.elementCount = minCapacity; + } + + public Asn1Encodable this[int index] { - return this[index]; + get + { + if (index >= elementCount) + throw new IndexOutOfRangeException(index + " >= " + elementCount); + + return elements[index]; + } } - [Obsolete("Use 'Count' property instead")] - public int Size - { - get { return v.Count; } - } + public int Count + { + get { return elementCount; } + } - public int Count - { - get { return v.Count; } - } + public IEnumerator GetEnumerator() + { + return CopyElements().GetEnumerator(); + } - public IEnumerator GetEnumerator() - { - return v.GetEnumerator(); - } - } + internal Asn1Encodable[] CopyElements() + { + if (0 == elementCount) + return EmptyElements; + + Asn1Encodable[] copy = new Asn1Encodable[elementCount]; + Array.Copy(elements, 0, copy, 0, elementCount); + return copy; + } + + internal Asn1Encodable[] TakeElements() + { + if (0 == elementCount) + return EmptyElements; + + if (elements.Length == elementCount) + { + this.copyOnWrite = true; + return elements; + } + + Asn1Encodable[] copy = new Asn1Encodable[elementCount]; + Array.Copy(elements, 0, copy, 0, elementCount); + return copy; + } + + private void Reallocate(int minCapacity) + { + int oldCapacity = elements.Length; + int newCapacity = System.Math.Max(oldCapacity, minCapacity + (minCapacity >> 1)); + + Asn1Encodable[] copy = new Asn1Encodable[newCapacity]; + Array.Copy(elements, 0, copy, 0, elementCount); + + this.elements = copy; + this.copyOnWrite = false; + } + + internal static Asn1Encodable[] CloneElements(Asn1Encodable[] elements) + { + return elements.Length < 1 ? EmptyElements : (Asn1Encodable[])elements.Clone(); + } + } } -- cgit 1.4.1