mirror of
https://github.com/inthehand/32feet.git
synced 2026-10-18 22:44:23 +08:00
402 lines
15 KiB
C#
402 lines
15 KiB
C#
// 32feet.NET - Personal Area Networking for .NET
|
|
//
|
|
// InTheHand.Net.BluetoothAddress
|
|
//
|
|
// Copyright (c) 2003-2022 In The Hand Ltd, All rights reserved.
|
|
// This source code is licensed under the MIT License
|
|
|
|
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using System.Net;
|
|
|
|
namespace InTheHand.Net
|
|
{
|
|
/// <summary>
|
|
/// Represents a Bluetooth device address.
|
|
/// </summary>
|
|
public partial class BluetoothAddress : IComparable<BluetoothAddress>, IEquatable<BluetoothAddress>, IFormattable, ICloneable
|
|
{
|
|
private readonly ulong _address;
|
|
|
|
/// <summary>
|
|
/// Provides a null Bluetooth address.
|
|
/// </summary>
|
|
public static readonly BluetoothAddress None = new BluetoothAddress(0UL);
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the BluetoothAddress class with the specified address.
|
|
/// </summary>
|
|
/// <param name="address">Int64 representation of the address.</param>
|
|
[Obsolete("Use unsigned long for widest compatibility", false)]
|
|
public BluetoothAddress(long address)
|
|
{
|
|
_address = (ulong)address;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the BluetoothAddress class with the specified address.
|
|
/// </summary>
|
|
/// <param name="address">UInt64 representation of the address.</param>
|
|
public BluetoothAddress(ulong address)
|
|
{
|
|
_address = address;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the BluetoothAddress class with the specified address.
|
|
/// </summary>
|
|
/// <param name="addressBytes">Address as 6 byte array.</param>
|
|
public BluetoothAddress(byte[] addressBytes)
|
|
{
|
|
byte[] raw = addressBytes;
|
|
|
|
if (addressBytes.Length < 8)
|
|
{
|
|
raw = new byte[8];
|
|
addressBytes.CopyTo(raw, 0);
|
|
}
|
|
|
|
_address = BitConverter.ToUInt64(raw, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Defines an implicit conversion of a BluetoothAddress to a <see cref="ulong"/>,
|
|
/// </summary>
|
|
public static implicit operator ulong(BluetoothAddress address)
|
|
{
|
|
return address._address;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Defines an implicit conversion of a <see cref="ulong"/> to a BluetoothAddress,
|
|
/// </summary>
|
|
public static implicit operator BluetoothAddress(ulong address)
|
|
{
|
|
return new BluetoothAddress(address);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the value as a byte array.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public byte[] ToByteArray()
|
|
{
|
|
return BitConverter.GetBytes(_address);
|
|
}
|
|
|
|
internal byte[] ToSixByteArray()
|
|
{
|
|
byte[] bytes = new byte[6];
|
|
Buffer.BlockCopy(ToByteArray(), 0, bytes, 0, 6);
|
|
return bytes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the Bluetooth address as a long integer.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[Obsolete("Use unsigned long for widest compatibility", false)]
|
|
public long ToInt64()
|
|
{
|
|
return (long)_address;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the Bluetooth address as an unsigned long integer.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public ulong ToUInt64()
|
|
{
|
|
return _address;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares two BluetoothAddress instances for equality.
|
|
/// </summary>
|
|
/// <param name="obj">The BluetoothAddress to compare with the current instance.</param>
|
|
/// <returns>true if obj is a BluetoothAddress and equal to the current instance; otherwise, false.</returns>
|
|
public override bool Equals(object obj)
|
|
{
|
|
BluetoothAddress bta = obj as BluetoothAddress;
|
|
|
|
if (bta != null)
|
|
{
|
|
return _address == bta._address;
|
|
}
|
|
|
|
return base.Equals(obj);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the hash code for this instance.
|
|
/// </summary>
|
|
/// <returns>A hash code for the current object.</returns>
|
|
public override int GetHashCode() => _address.GetHashCode();
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="other"></param>
|
|
/// <returns></returns>
|
|
public int CompareTo(BluetoothAddress other)
|
|
{
|
|
if (other != null)
|
|
{
|
|
return _address.CompareTo(other._address);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a String representation of the value of this BluetoothAddress instance, according to the provided format specifier.
|
|
/// </summary>
|
|
/// <param name="format">A single format specifier that indicates how to format the value of this address.
|
|
/// The format parameter can be "N", "C", or "P".
|
|
/// If format is null or the empty string (""), "N" is used.</param>
|
|
/// <param name="formatProvider">Ignored.</param>
|
|
/// <returns>A String representation of the value of this BluetoothAddress.</returns>
|
|
public string ToString(string format, IFormatProvider formatProvider)
|
|
{
|
|
return ToString(format);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a String representation of the value of this BluetoothAddress instance, according to the provided format specifier.
|
|
/// </summary>
|
|
/// <param name="format">A single format specifier that indicates how to format the value of this address.
|
|
/// The format parameter can be "N", "C", or "P".
|
|
/// If format is null or the empty string (""), "N" is used.</param>
|
|
/// <returns>A String representation of the value of this BluetoothAddress.</returns>
|
|
public string ToString(string format)
|
|
{
|
|
string separator;
|
|
|
|
if (string.IsNullOrEmpty(format))
|
|
{
|
|
separator = string.Empty;
|
|
}
|
|
else
|
|
{
|
|
switch (format.ToUpper(CultureInfo.InvariantCulture))
|
|
{
|
|
case "8":
|
|
case "N":
|
|
separator = string.Empty;
|
|
break;
|
|
case "C":
|
|
separator = ":";
|
|
break;
|
|
case "P":
|
|
separator = ".";
|
|
break;
|
|
default:
|
|
throw new FormatException("Invalid format specified - must be either \"N\", \"C\", \"P\", \"\" or null.");
|
|
}
|
|
}
|
|
|
|
byte[] data = ToByteArray();
|
|
|
|
System.Text.StringBuilder result = new System.Text.StringBuilder(18);
|
|
|
|
if (format == "8")
|
|
{
|
|
result.Append(data[7].ToString("X2") + separator);
|
|
result.Append(data[6].ToString("X2") + separator);
|
|
}
|
|
|
|
result.Append(data[5].ToString("X2") + separator);
|
|
result.Append(data[4].ToString("X2") + separator);
|
|
result.Append(data[3].ToString("X2") + separator);
|
|
result.Append(data[2].ToString("X2") + separator);
|
|
result.Append(data[1].ToString("X2") + separator);
|
|
result.Append(data[0].ToString("X2"));
|
|
|
|
return result.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a default string representation of the BluetoothAddress.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override string ToString()
|
|
{
|
|
return ToString("N");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts the string representation of an address to it's <see cref="BluetoothAddress"/> equivalent.
|
|
/// A return value indicates whether the operation succeeded.
|
|
/// </summary>
|
|
/// <param name="bluetoothString">A string containing an address to convert.</param>
|
|
/// <param name="result">When this method returns, contains the <see cref="BluetoothAddress"/> equivalent to the address contained in s, if the conversion succeeded, or null (Nothing in Visual Basic) if the conversion failed.
|
|
/// The conversion fails if the s parameter is null or is not of the correct format.</param>
|
|
/// <returns>true if s is a valid Bluetooth address; otherwise, false.</returns>
|
|
public static bool TryParse(string bluetoothString, out BluetoothAddress result)
|
|
{
|
|
Exception ex = ParseInternal(bluetoothString, out result);
|
|
if (ex != null) return false;
|
|
else return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts the string representation of a Bluetooth address to a new <see cref="BluetoothAddress"/> instance.
|
|
/// </summary>
|
|
/// <param name="bluetoothString">A string containing an address to convert.</param>
|
|
/// <returns>New <see cref="BluetoothAddress"/> instance.</returns>
|
|
/// <remarks>Address must be specified in hex format optionally separated by the colon or period character e.g. 000000000000, 00:00:00:00:00:00 or 00.00.00.00.00.00.</remarks>
|
|
/// <exception cref="T:System.ArgumentNullException">bluetoothString is null.</exception>
|
|
/// <exception cref="T:System.FormatException">bluetoothString is not a valid Bluetooth address.</exception>
|
|
public static BluetoothAddress Parse(string bluetoothString)
|
|
{
|
|
Exception ex = ParseInternal(bluetoothString, out BluetoothAddress result);
|
|
if (ex != null) throw ex;
|
|
else return result;
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
|
|
Justification = "Returned to caller.")]
|
|
static Exception ParseInternal(string bluetoothString, out BluetoothAddress result)
|
|
{
|
|
const Exception Success = null;
|
|
result = null;
|
|
|
|
if (string.IsNullOrEmpty(bluetoothString))
|
|
{
|
|
return new ArgumentNullException(nameof(bluetoothString));
|
|
}
|
|
|
|
if (bluetoothString.IndexOf(":", StringComparison.Ordinal) > -1)
|
|
{
|
|
// assume address in standard hex format 00:00:00:00:00:00
|
|
|
|
// check length
|
|
if (bluetoothString.Length != 17)
|
|
{
|
|
return new FormatException("bluetoothString is not a valid Bluetooth address.");
|
|
}
|
|
|
|
try
|
|
{
|
|
byte[] babytes = new byte[8];
|
|
// split on colons
|
|
string[] sbytes = bluetoothString.Split(':');
|
|
for (int ibyte = 0; ibyte < 6; ibyte++)
|
|
{
|
|
// parse hex byte in reverse order
|
|
babytes[ibyte] = byte.Parse(sbytes[5 - ibyte], NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
|
}
|
|
result = new BluetoothAddress(babytes);
|
|
return Success;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return ex;
|
|
}
|
|
}
|
|
else if (bluetoothString.IndexOf(".", StringComparison.Ordinal) > -1)
|
|
{
|
|
// assume address in uri hex format 00.00.00.00.00.00
|
|
// check length
|
|
if (bluetoothString.Length != 17)
|
|
{
|
|
return new FormatException("bluetoothString is not a valid Bluetooth address.");
|
|
}
|
|
|
|
try
|
|
{
|
|
byte[] babytes = new byte[8];
|
|
// split on periods
|
|
string[] sbytes = bluetoothString.Split('.');
|
|
for (int ibyte = 0; ibyte < 6; ibyte++)
|
|
{
|
|
// parse hex byte in reverse order
|
|
babytes[ibyte] = byte.Parse(sbytes[5 - ibyte], NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
|
}
|
|
result = new BluetoothAddress(babytes);
|
|
return Success;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return ex;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// assume specified as long integer
|
|
if ((bluetoothString.Length < 12) | (bluetoothString.Length > 16))
|
|
{
|
|
return new FormatException("bluetoothString is not a valid Bluetooth address.");
|
|
}
|
|
try
|
|
{
|
|
result = new BluetoothAddress(ulong.Parse(bluetoothString, NumberStyles.HexNumber, CultureInfo.InvariantCulture));
|
|
return Success;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return ex;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool Equals(BluetoothAddress other)
|
|
{
|
|
if (other is null)
|
|
return false;
|
|
|
|
return _address == other._address;
|
|
}
|
|
|
|
public static bool operator ==(BluetoothAddress x, BluetoothAddress y)
|
|
{
|
|
if ((x is null) && (y is null))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ((x is object) && (y is object))
|
|
{
|
|
if (x._address == y._address)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an indication whether the values of two specified <see cref="BluetoothAddress"/> objects are not equal.
|
|
/// </summary>
|
|
/// -
|
|
/// <param name="x">A <see cref="BluetoothAddress"/> or <see langword="null"/>.</param>
|
|
/// <param name="y">A <see cref="BluetoothAddress"/> or <see langword="null"/>.</param>
|
|
/// -
|
|
/// <returns><c>true</c> if the value of the two instance is different;
|
|
/// otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public static bool operator !=(BluetoothAddress x, BluetoothAddress y)
|
|
{
|
|
return !(x == y);
|
|
}
|
|
|
|
internal static Guid HostToNetworkOrder(Guid hostGuid)
|
|
{
|
|
byte[] guidBytes = hostGuid.ToByteArray();
|
|
|
|
BitConverter.GetBytes(IPAddress.HostToNetworkOrder(BitConverter.ToInt32(guidBytes, 0))).CopyTo(guidBytes, 0);
|
|
BitConverter.GetBytes(IPAddress.HostToNetworkOrder(BitConverter.ToInt16(guidBytes, 4))).CopyTo(guidBytes, 4);
|
|
BitConverter.GetBytes(IPAddress.HostToNetworkOrder(BitConverter.ToInt16(guidBytes, 6))).CopyTo(guidBytes, 6);
|
|
|
|
return new Guid(guidBytes);
|
|
}
|
|
|
|
public object Clone()
|
|
{
|
|
return new BluetoothAddress(_address);
|
|
}
|
|
}
|
|
}
|