BigIntegerExt.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Numerics;
  4. using System.Text;
  5. namespace Emby.Server.Implementations.Networking.IPNetwork
  6. {
  7. /// <summary>
  8. /// Extension methods to convert <see cref="BigInteger"/>
  9. /// instances to hexadecimal, octal, and binary strings.
  10. /// </summary>
  11. public static class BigIntegerExtensions
  12. {
  13. /// <summary>
  14. /// Converts a <see cref="BigInteger"/> to a binary string.
  15. /// </summary>
  16. /// <param name="bigint">A <see cref="BigInteger"/>.</param>
  17. /// <returns>
  18. /// A <see cref="string"/> containing a binary
  19. /// representation of the supplied <see cref="BigInteger"/>.
  20. /// </returns>
  21. public static string ToBinaryString(this BigInteger bigint)
  22. {
  23. var bytes = bigint.ToByteArray();
  24. var idx = bytes.Length - 1;
  25. // Create a StringBuilder having appropriate capacity.
  26. var base2 = new StringBuilder(bytes.Length * 8);
  27. // Convert first byte to binary.
  28. var binary = Convert.ToString(bytes[idx], 2);
  29. // Ensure leading zero exists if value is positive.
  30. if (binary[0] != '0' && bigint.Sign == 1)
  31. {
  32. base2.Append('0');
  33. }
  34. // Append binary string to StringBuilder.
  35. base2.Append(binary);
  36. // Convert remaining bytes adding leading zeros.
  37. for (idx--; idx >= 0; idx--)
  38. {
  39. base2.Append(Convert.ToString(bytes[idx], 2).PadLeft(8, '0'));
  40. }
  41. return base2.ToString();
  42. }
  43. /// <summary>
  44. /// Converts a <see cref="BigInteger"/> to a hexadecimal string.
  45. /// </summary>
  46. /// <param name="bigint">A <see cref="BigInteger"/>.</param>
  47. /// <returns>
  48. /// A <see cref="string"/> containing a hexadecimal
  49. /// representation of the supplied <see cref="BigInteger"/>.
  50. /// </returns>
  51. public static string ToHexadecimalString(this BigInteger bigint)
  52. {
  53. return bigint.ToString("X");
  54. }
  55. /// <summary>
  56. /// Converts a <see cref="BigInteger"/> to a octal string.
  57. /// </summary>
  58. /// <param name="bigint">A <see cref="BigInteger"/>.</param>
  59. /// <returns>
  60. /// A <see cref="string"/> containing an octal
  61. /// representation of the supplied <see cref="BigInteger"/>.
  62. /// </returns>
  63. public static string ToOctalString(this BigInteger bigint)
  64. {
  65. var bytes = bigint.ToByteArray();
  66. var idx = bytes.Length - 1;
  67. // Create a StringBuilder having appropriate capacity.
  68. var base8 = new StringBuilder(((bytes.Length / 3) + 1) * 8);
  69. // Calculate how many bytes are extra when byte array is split
  70. // into three-byte (24-bit) chunks.
  71. var extra = bytes.Length % 3;
  72. // If no bytes are extra, use three bytes for first chunk.
  73. if (extra == 0)
  74. {
  75. extra = 3;
  76. }
  77. // Convert first chunk (24-bits) to integer value.
  78. int int24 = 0;
  79. for (; extra != 0; extra--)
  80. {
  81. int24 <<= 8;
  82. int24 += bytes[idx--];
  83. }
  84. // Convert 24-bit integer to octal without adding leading zeros.
  85. var octal = Convert.ToString(int24, 8);
  86. // Ensure leading zero exists if value is positive.
  87. if (octal[0] != '0')
  88. {
  89. if (bigint.Sign == 1)
  90. {
  91. base8.Append('0');
  92. }
  93. }
  94. // Append first converted chunk to StringBuilder.
  95. base8.Append(octal);
  96. // Convert remaining 24-bit chunks, adding leading zeros.
  97. for (; idx >= 0; idx -= 3)
  98. {
  99. int24 = (bytes[idx] << 16) + (bytes[idx - 1] << 8) + bytes[idx - 2];
  100. base8.Append(Convert.ToString(int24, 8).PadLeft(8, '0'));
  101. }
  102. return base8.ToString();
  103. }
  104. /// <summary>
  105. ///
  106. /// Reverse a Positive BigInteger ONLY
  107. /// Bitwise ~ operator
  108. ///
  109. /// Input : FF FF FF FF
  110. /// Width : 4
  111. /// Result : 00 00 00 00
  112. ///
  113. ///
  114. /// Input : 00 00 00 00
  115. /// Width : 4
  116. /// Result : FF FF FF FF
  117. ///
  118. /// Input : FF FF FF FF
  119. /// Width : 8
  120. /// Result : FF FF FF FF 00 00 00 00
  121. ///
  122. ///
  123. /// Input : 00 00 00 00
  124. /// Width : 8
  125. /// Result : FF FF FF FF FF FF FF FF
  126. ///
  127. /// </summary>
  128. /// <param name="input"></param>
  129. /// <param name="width"></param>
  130. /// <returns></returns>
  131. public static BigInteger PositiveReverse(this BigInteger input, int width)
  132. {
  133. var result = new List<byte>();
  134. var bytes = input.ToByteArray();
  135. var work = new byte[width];
  136. Array.Copy(bytes, 0, work, 0, bytes.Length - 1); // Length -1 : positive BigInteger
  137. for (int i = 0; i < work.Length; i++)
  138. {
  139. result.Add((byte)(~work[i]));
  140. }
  141. result.Add(0); // positive BigInteger
  142. return new BigInteger(result.ToArray());
  143. }
  144. }
  145. }