using GostCryptography.Properties; using System; using System.Text; namespace GostCryptography.Asn1.Ber { [Serializable] public class Asn1Real : Asn1Type { private const int MinusInfinity = 0x41; private const int PlusInfinity = 0x40; private const int RealBase2 = 0; private const int RealBase8 = 0x10; private const int RealBase16 = 0x20; private const int RealBaseMask = 0x30; private const int RealBinary = 0x80; private const int RealExplen1 = 0; private const int RealExplen2 = 1; private const int RealExplen3 = 2; private const int RealExplenLong = 3; private const int RealExplenMask = 3; private const int RealFactorMask = 12; private const int RealIso6093Mask = 0x3f; public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, RealTypeCode); [NonSerialized] public double Value; public Asn1Real() { Value = 0.0; } public Asn1Real(double value) { Value = value; } public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength) { var length = explicitTagging ? MatchTag(buffer, Tag) : implicitLength; if (length == 0) { Value = 0.0; } else { var num2 = buffer.ReadByte(); if (length == 1) { switch (num2) { case PlusInfinity: Value = double.PositiveInfinity; return; case MinusInfinity: Value = double.NegativeInfinity; return; } throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount); } length--; if ((num2 & RealBinary) == 0) { var num8 = length; var num9 = 0; var builder = new StringBuilder { Length = num8 }; while (num8 > 0) { var num7 = buffer.Read(); if (num7 == -1) { throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount); } builder[num9++] = (char)num7; num8--; } var num10 = num2 & RealIso6093Mask; var num11 = 0; for (var i = 0; i < builder.Length; i++) { var ch = builder[i]; if ((num10 >= 2) && (ch == ',')) { builder[i] = '.'; num11++; } else if (((num10 >= 1) && (((ch >= '0') && (ch <= '9')) || ((ch == '+') || (ch == '-')))) || (((num10 >= 2) && (ch == '.')) || ((num10 == 3) && ((ch == 'E') || (ch == 'e'))))) { num11++; } else if ((num11 != 0) || (ch != ' ')) { throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount); } } try { Value = double.Parse(builder.ToString()); } catch (FormatException) { throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount); } } else { int num6; int num3; switch ((num2 & RealExplenMask)) { case RealExplen1: num3 = 1; break; case RealExplen2: num3 = 2; break; case RealExplen3: num3 = 3; break; default: num3 = buffer.ReadByte(); length--; break; } var num4 = (int)Asn1RunTime.DecodeIntValue(buffer, num3, true); length -= num3; var num5 = Asn1RunTime.DecodeIntValue(buffer, length, false) * (1L << ((num2 & RealFactorMask) >> 2)); switch ((num2 & RealBaseMask)) { case RealBase2: num6 = 2; break; case RealBase8: num6 = 8; break; case RealBase16: num6 = 16; break; default: throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount); } Value = num5 * Math.Pow(num6, num4); if ((num2 & PlusInfinity) != 0) { Value = -Value; } } buffer.TypeCode = RealTypeCode; } } public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging) { var len = 0; if (double.IsNegativeInfinity(Value)) { len = buffer.EncodeIntValue(MinusInfinity); } else if (double.IsPositiveInfinity(Value)) { len = buffer.EncodeIntValue(PlusInfinity); } else if (Value != 0.0) { var num2 = BitConverter.DoubleToInt64Bits(Value); var num3 = ((num2 >> RealIso6093Mask) == 0L) ? 1 : -1; var num4 = ((int)((num2 >> 0x34) & 0x7ffL)) - 0x433; var w = (num4 == 0) ? ((num2 & 0xfffffffffffffL) << 1) : ((num2 & 0xfffffffffffffL) | 0x10000000000000L); if (w != 0L) { var bits = TrailingZerosCnt(w); w = Asn1Util.UrShift(w, bits); num4 += bits; } len += buffer.EncodeIntValue(w); var num7 = buffer.EncodeIntValue(num4); len += num7; var num8 = RealBinary; if (num3 == -1) { num8 |= PlusInfinity; } switch (num7) { case RealExplen2: break; case RealExplen3: num8 |= 1; break; case RealExplenLong: num8 |= 2; break; default: num8 |= 3; len += buffer.EncodeIntValue(num7); break; } buffer.Copy((byte)num8); len++; } if (explicitTagging) { len += buffer.EncodeTagAndLength(Tag, len); } return len; } public override void Encode(Asn1BerOutputStream outs, bool explicitTagging) { if (explicitTagging) { outs.EncodeTag(Tag); } if (Value == 0.0) { outs.EncodeLength(0); } else if (Value == double.NegativeInfinity) { outs.EncodeIntValue(MinusInfinity, true); } else if (Value == double.PositiveInfinity) { outs.EncodeIntValue(PlusInfinity, true); } else { var len = 1; var num2 = BitConverter.DoubleToInt64Bits(Value); var num3 = ((num2 >> RealIso6093Mask) == 0L) ? 1 : -1; var num4 = ((int)((num2 >> 0x34) & 0x7ffL)) - 0x433; var w = (num4 == 0) ? ((num2 & 0xfffffffffffffL) << 1) : ((num2 & 0xfffffffffffffL) | 0x10000000000000L); if (w != 0L) { var bits = TrailingZerosCnt(w); w = Asn1Util.UrShift(w, bits); num4 += bits; len += Asn1Util.GetUlongBytesCount(w); } else { len++; } var num7 = RealBinary; if (num3 == -1) { num7 |= PlusInfinity; } var bytesCount = Asn1Util.GetBytesCount(num4); len += bytesCount; switch (bytesCount) { case RealExplen2: break; case RealExplen3: num7 |= 1; break; case RealExplenLong: num7 |= 2; break; default: num7 |= 3; len++; break; } outs.EncodeLength(len); outs.WriteByte((byte)num7); if ((num7 & 3) == 3) { outs.EncodeIntValue(bytesCount, false); } outs.EncodeIntValue(num4, false); outs.EncodeIntValue(w, false); } } public virtual bool Equals(double value) { return (Value == value); } public override bool Equals(object value) { var real = value as Asn1Real; if (real == null) { return false; } return (Value == real.Value); } public override int GetHashCode() { return Value.GetHashCode(); } public override string ToString() { return Value.ToString(); } private static int TrailingZerosCnt(long w) { var num = Asn1RunTime.IntTrailingZerosCnt((int)w); if (num >= RealBase16) { return (Asn1RunTime.IntTrailingZerosCnt((int)Asn1Util.UrShift(w, RealBase16)) + RealBase16); } return num; } } }