/// This class is used to encapsulate an ASN.1 Identifier.
/// An Asn1Identifier is composed of three parts:
/// a class type, a form, and a tag.
/// The class type is defined as:
///
/// bit 8 7 TAG CLASS
/// ------- -----------
/// 0 0 UNIVERSAL
/// 0 1 APPLICATION
/// 1 0 CONTEXT
/// 1 1 PRIVATE
///
/// The form is defined as:
///
/// bit 6 FORM
/// ----- --------
/// 0 PRIMITIVE
/// 1 CONSTRUCTED
///
/// Note: CONSTRUCTED types are made up of other CONSTRUCTED or PRIMITIVE
/// types.
/// The tag is defined as:.
///
/// bit 5 4 3 2 1 TAG
/// ------------- ---------------------------------------------
/// 0 0 0 0 0
/// . . . . .
/// 1 1 1 1 0 (0-30) single octet tag
/// 1 1 1 1 1 (> 30) multiple octet tag, more octets follow
///
internal sealed class Asn1Identifier
{
public Asn1Identifier(Asn1IdentifierTag tagClass, bool constructed, int tag)
{
Asn1Class = tagClass;
Constructed = constructed;
Tag = tag;
}
public Asn1Identifier(LdapOperation tag)
: this(Asn1IdentifierTag.Application, true, (int) tag)
{
}
public Asn1Identifier(int contextTag, bool constructed = false)
: this(Asn1IdentifierTag.Context, constructed, contextTag)
{
}
public Asn1Identifier(Stream stream)
{
var r = stream.ReadByte();
EncodedLength++;
if (r < 0)
throw new EndOfStreamException("BERDecoder: decode: EOF in Identifier");
Asn1Class = (Asn1IdentifierTag) (r >> 6);
Constructed = (r & 0x20) != 0;
Tag = r & 0x1F; // if tag < 30 then its a single octet identifier.
if (Tag == 0x1F)
{
// if true, its a multiple octet identifier.
Tag = DecodeTagNumber(stream);
}
}
public Asn1IdentifierTag Asn1Class { get; }
public bool Constructed { get; }
public int Tag { get; }
public int EncodedLength { get; private set; }
public bool Universal => Asn1Class == Asn1IdentifierTag.Universal;
public object Clone() => MemberwiseClone();
private int DecodeTagNumber(Stream stream)
{
var n = 0;
while (true)
{
var r = stream.ReadByte();
EncodedLength++;
if (r < 0)
throw new EndOfStreamException("BERDecoder: decode: EOF in tag number");
n = (n << 7) + (r & 0x7F);
if ((r & 0x80) == 0) break;
}
return n;
}
}
///