/// <summary> /// Decodes the data from the buffer and stores the data in this object. /// </summary> /// <param name="buffer">A buffer that stores a BER encoding result.</param> /// <param name="length">The length of the encoding result of the data in the given buffer.</param> /// <returns>The number of the bytes consumed in the buffer to decode the data.</returns> /// <remarks> /// For the TLV (Tag, Length, Value) triple in the encoding result, /// this method provides the functionality of decoding Value. /// The decoding for Tag and Length will be done in Asn1Object::BerDecode method. /// </remarks> protected override int ValueBerDecode(IAsn1DecodingBuffer buffer, int length) { int consumedLen = 0; Asn1Tag tag = null; //The current decoded tag. int tagLen = 0; //The consumed length of the bytes in the buffer when decoding the current tag. bool tagUsed = true; int curFieldIndex = 0;//The index of the field that currently is trying to decode. Asn1Object[] tempFields = FieldsTypeInstances; while (consumedLen < length) { if (curFieldIndex >= tempFields.Length) { throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData); } if (tagUsed) { tagLen = TagBerDecode(buffer, out tag); //The decoded tag may be context , application or universal tag. } if (fieldsMetaData[curFieldIndex].Optional == false) { //Current field is mandatory. if (fieldsMetaData[curFieldIndex].AttachedTag != null) { //Current field has a context class tag. //The decoded tag must be the context class tag of the field. if (tag.Equals(fieldsMetaData[curFieldIndex].AttachedTag)) { consumedLen += tagLen; int lengthAfterCtxTag; consumedLen += LengthBerDecode(buffer, out lengthAfterCtxTag); //Decodes this field by Asn1Object::BerDecode when the if-else statement for fieldOptionalFlags ends. } else { throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData + " Context Tag Decode fail."); } } else { //Current field doesn't have a context class tag. //The decoded tag must be the application or universal class tag of the field. //Retreat the buffer since the decoding of application or universal class is part of Asn1Object::BerDecode. buffer.SeekBytePosition(-tagLen); //Decode this field by Asn1Object::BerDecode when the if-else statement for fieldOptionalFlags ends. } } else { //Current field is optional. if (fieldsMetaData[curFieldIndex].AttachedTag != null) { //Current field has a context class tag. //Check whether it is the encoding result of this field by the context-specific class tag. if (tag.Equals(fieldsMetaData[curFieldIndex].AttachedTag)) { //Yes consumedLen += tagLen; int lengthAfterCtxTag; consumedLen += LengthBerDecode(buffer, out lengthAfterCtxTag); //Decode this field by Asn1Object::BerDecode when the if-else statement for OptionalFlags ends. } else { //No tagUsed = false; tempFields[curFieldIndex] = null; curFieldIndex++; //Check the next field. continue; } } else { //Current field doesn't have a context class tag. //Check whether it is the encoding result of this field by the top most class tag. if (tag.Equals(tempFields[curFieldIndex].TopTag)) { //Yes buffer.SeekBytePosition(-tagLen); //Decode this field by Asn1Object::BerDecode when the if-else statement for OptionalFlags ends. } else { //No tagUsed = false; tempFields[curFieldIndex] = null; curFieldIndex++; //Check the next field. continue; } } } consumedLen += tempFields[curFieldIndex].BerDecode(buffer); tagUsed = true; curFieldIndex++; } //Ensure consumedLen equals to length. if (consumedLen > length) { throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData); } //Stores the decoded fields in this object. if (tempFields.Length != fieldsMetaData.Length) { throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData); } for (int i = 0; i < curFieldIndex; i++) { if (fieldsMetaData[i].MemberInfo.MemberType == MemberTypes.Property) { (fieldsMetaData[i].MemberInfo as PropertyInfo).SetValue(this, tempFields[i], null); } else if (fieldsMetaData[i].MemberInfo.MemberType == MemberTypes.Field) { (fieldsMetaData[i].MemberInfo as FieldInfo).SetValue(this, tempFields[i]); } else { //Unreachable. Ensured by the AttributeUsage of Asn1Field. throw new Asn1UserDefinedTypeInconsistent(ExceptionMessages.UserDefinedTypeInconsistent + " Asn1Field property could only be used in properties or fields."); } } return(consumedLen); }