/// <summary>
 ///     Adds pure raw data (untagged) that is then encoded using specified tag.
 /// </summary>
 /// <param name="value">
 ///     Value to encode.
 /// </param>
 /// <param name="outerTag">
 ///     Tag number to encode the data with.
 /// </param>
 /// <exception cref="ArgumentNullException">
 ///     <strong>value</strong> parameter is null.
 /// </exception>
 /// <returns>Current instance with added value.</returns>
 public Asn1Builder AddDerData(Byte[] value, Byte outerTag)
 {
     if (value == null)
     {
         throw new ArgumentNullException(nameof(value));
     }
     _rawData.AddRange(Asn1Utils.Encode(value, outerTag));
     return(this);
 }
 /// <summary>
 ///     Adds ASN.1 VideotexString value.
 /// </summary>
 /// <param name="value">
 ///     Value to encode.
 /// </param>
 /// <exception cref="ArgumentNullException">
 ///     <strong>value</strong> parameter is null.
 /// </exception>
 /// <returns>Current instance with added value.</returns>
 public Asn1Builder AddVideotexString(String value)
 {
     if (value == null)
     {
         throw new ArgumentNullException(nameof(value));
     }
     _rawData.AddRange(Asn1Utils.Encode(Encoding.ASCII.GetBytes(value), (Byte)Asn1Type.VideotexString));
     return(this);
 }
        /// <summary>
        /// Adds explicitly tagged type. Explicit (EXPLICIT OPTIONAL) must have at least one primitive or constructed nested type.
        /// </summary>
        /// <param name="explicitTag">
        ///     Explicit tag number. This number equals to tag number in square brackets in ASN module definition of EXPLICIT.
        /// </param>
        /// <param name="selector">Lambda expression to fill nested content.</param>
        /// <exception cref="ArgumentNullException">
        ///     <strong>selector</strong> parameter is null.
        /// </exception>
        /// <returns>Current instance with added value.</returns>
        public Asn1Builder AddExplicit(Byte explicitTag, Func <Asn1Builder, Asn1Builder> selector)
        {
            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }
            Asn1Builder b = selector(new Asn1Builder());

            _rawData.AddRange(Asn1Utils.Encode(b._rawData.ToArray(), (Byte)(0xa0 + explicitTag)));
            return(this);
        }
        /// <summary>
        /// Adds constructed SET.
        /// </summary>
        /// <param name="selector">Lambda expression to fill nested content.</param>
        /// <exception cref="ArgumentNullException">
        ///     <strong>selector</strong> parameter is null.
        /// </exception>
        /// <returns>Current instance with added value.</returns>
        public Asn1Builder AddSet(Func <Asn1Builder, Asn1Builder> selector)
        {
            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }
            Asn1Builder b = selector(new Asn1Builder());

            _rawData.AddRange(Asn1Utils.Encode(b._rawData.ToArray(), 0x31));
            return(this);
        }
        /// <summary>
        /// Adds constructed octet string.
        /// </summary>
        /// <param name="selector">Lambda expression to fill nested content.</param>
        /// <exception cref="ArgumentNullException">
        ///     <strong>selector</strong> parameter is null.
        /// </exception>
        /// <returns>Current instance with added value.</returns>
        /// <remarks>
        ///     In the current implementation, constructed OCTET_STRING is encoded using primitive form.
        /// </remarks>
        public Asn1Builder AddOctetString(Func <Asn1Builder, Asn1Builder> selector)
        {
            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }
            Asn1Builder b = selector(new Asn1Builder());

            _rawData.AddRange(Asn1Utils.Encode(b._rawData.ToArray(), (Byte)Asn1Type.OCTET_STRING));
            return(this);
        }
        /// <summary>
        ///     Adds ASN.1 SET value.
        /// </summary>
        /// <param name="value">
        ///     Value to encode.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <strong>value</strong> parameter is null.
        /// </exception>
        /// <returns>Current instance with added value.</returns>
        /// <remarks>
        ///     In the current implementation, SET is encoded using constructed form only.
        /// </remarks>
        public Asn1Builder AddSet(Byte[] value)
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }
            IEnumerable <Byte> encoded = Asn1Utils.Encode(value, 0x31);
            var asn = new Asn1Reader(value);

            asn.BuildOffsetMap();
            // if we reach this far, most likely, the data is ok.
            _rawData.AddRange(encoded);
            return(this);
        }
 /// <summary>
 /// Adds explicitly tagged type. Explicit (EXPLICIT OPTIONAL) must have at least one primitive or constructed nested type.
 /// </summary>
 /// <param name="explicitTag">
 ///     Explicit tag number. This number equals to tag number in square brackets in ASN module definition of EXPLICIT.
 /// </param>
 /// <param name="value">
 ///     Value to encode.
 /// </param>
 /// <param name="mustEncode">
 ///     Specifies if data in <strong>value</strong> parameter must be encoded or not. See Remarks for more details.
 /// </param>
 /// <exception cref="ArgumentNullException">
 ///     <strong>value</strong> parameter is null.
 /// </exception>
 /// <exception cref="InvalidDataException">
 ///     <strong>value</strong> is not encoded.
 /// </exception>
 /// <returns>Current instance with added value.</returns>
 /// <remarks>
 ///     If <strong>mustEncode</strong> parameter is set to <strong>true</strong>, then data in <strong>value</strong> parameter
 ///     is untagged. If <strong>mustEncode</strong> parameter is set to <strong>false</strong>, then data in <strong>value</strong>
 ///     parameter is explicitly tagged and only tag name change is necessary. Caller must have knowledge in advance if value is tagged or not.
 ///     If <strong>mustEncode</strong> parameter is set to <strong>false</strong> and value passed in <strong>value</strong> parameter
 ///     is untagged, invalid type will be produced.
 /// </remarks>
 public Asn1Builder AddExplicit(Byte explicitTag, Byte[] value, Boolean mustEncode)
 {
     if (value == null)
     {
         throw new ArgumentNullException(nameof(value));
     }
     if (mustEncode)
     {
         _rawData.AddRange(Asn1Utils.Encode(value, (Byte)(0xa0 + explicitTag)));
     }
     else
     {
         var asn = new Asn1Reader(value);
         asn.BuildOffsetMap();
         var valueCopy = value.ToArray();
         valueCopy[0] = (Byte)(0xa0 + explicitTag);
         _rawData.AddRange(valueCopy);
     }
     return(this);
 }
 /// <summary>
 ///     Gets ASN.1-encoded byte array that represents current state of builder wrapped using outer ASN.1 type.
 /// </summary>
 /// <param name="outerTag">
 ///     Outer type to wrap current state of builder. Outer type must not by the type that is used in primitive form only.
 ///     Default outer tag is constructed SEQUENCE (0x30 or decimal 48).
 /// </param>
 /// <returns>
 ///     ASN.1-encoded byte array.
 /// </returns>
 public Byte[] GetEncoded(Byte outerTag = 0x30)
 {
     return(Asn1Utils.Encode(_rawData.ToArray(), outerTag));
 }