/// 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, Boolean constructed, Int32 tag) {
this.Asn1Class = tagClass;
this.Constructed = constructed;
this.Tag = tag;
}
public Asn1Identifier(LdapOperation tag)
: this(Asn1IdentifierTag.Application, true, (Int32)tag) {
}
public Asn1Identifier(Int32 contextTag, Boolean constructed = false)
: this(Asn1IdentifierTag.Context, constructed, contextTag) {
}
public Asn1Identifier(Stream stream) {
Int32 r = stream.ReadByte();
this.EncodedLength++;
if(r < 0) {
throw new EndOfStreamException("BERDecoder: decode: EOF in Identifier");
}
this.Asn1Class = (Asn1IdentifierTag)(r >> 6);
this.Constructed = (r & 0x20) != 0;
this.Tag = r & 0x1F; // if tag < 30 then its a single octet identifier.
if(this.Tag == 0x1F) {
// if true, its a multiple octet identifier.
this.Tag = this.DecodeTagNumber(stream);
}
}
public Asn1IdentifierTag Asn1Class {
get;
}
public Boolean Constructed {
get;
}
public Int32 Tag {
get;
}
public Int32 EncodedLength {
get; private set;
}
public Boolean Universal => this.Asn1Class == Asn1IdentifierTag.Universal;
public Object Clone() => this.MemberwiseClone();
private Int32 DecodeTagNumber(Stream stream) {
Int32 n = 0;
while(true) {
Int32 r = stream.ReadByte();
this.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;
}
}
///