/*
* Copyright (c) 2006-2014, openmetaverse.org
* All rights reserved.
*
* - Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Neither the name of the openmetaverse.org nor the names
* of its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
using System;
namespace OpenMetaverse
{
///
/// A 128-bit Universally Unique Identifier, used throughout the Second
/// Life networking protocol
///
[Serializable]
public struct UUID : IComparable, IEquatable
{
/// The System.Guid object this struct wraps around
public Guid Guid;
#region Constructors
///
/// Constructor that takes a string UUID representation
///
/// A string representation of a UUID, case
/// insensitive and can either be hyphenated or non-hyphenated
/// UUID("11f8aa9c-b071-4242-836b-13b7abe0d489")
public UUID(string val)
{
if (String.IsNullOrEmpty(val))
Guid = new Guid();
else
Guid = new Guid(val);
}
///
/// Constructor that takes a System.Guid object
///
/// A Guid object that contains the unique identifier
/// to be represented by this UUID
public UUID(Guid val)
{
Guid = val;
}
///
/// Constructor that takes a byte array containing a UUID
///
/// Byte array containing a 16 byte UUID
/// Beginning offset in the array
public UUID(byte[] source, int pos)
{
Guid = UUID.Zero.Guid;
FromBytes(source, pos);
}
///
/// Constructor that takes an unsigned 64-bit unsigned integer to
/// convert to a UUID
///
/// 64-bit unsigned integer to convert to a UUID
public UUID(ulong val)
{
byte[] end = BitConverter.GetBytes(val);
if (!BitConverter.IsLittleEndian)
Array.Reverse(end);
Guid = new Guid(0, 0, 0, end);
}
///
/// Copy constructor
///
/// UUID to copy
public UUID(UUID val)
{
Guid = val.Guid;
}
#endregion Constructors
#region Public Methods
///
/// IComparable.CompareTo implementation
///
public int CompareTo(UUID id)
{
return Guid.CompareTo(id.Guid);
}
///
/// Assigns this UUID from 16 bytes out of a byte array
///
/// Byte array containing the UUID to assign this UUID to
/// Starting position of the UUID in the byte array
public void FromBytes(byte[] source, int pos)
{
int a = (source[pos + 0] << 24) | (source[pos + 1] << 16) | (source[pos + 2] << 8) | source[pos + 3];
short b = (short)((source[pos + 4] << 8) | source[pos + 5]);
short c = (short)((source[pos + 6] << 8) | source[pos + 7]);
Guid = new Guid(a, b, c, source[pos + 8], source[pos + 9], source[pos + 10], source[pos + 11],
source[pos + 12], source[pos + 13], source[pos + 14], source[pos + 15]);
}
///
/// Returns a copy of the raw bytes for this UUID
///
/// A 16 byte array containing this UUID
public byte[] GetBytes()
{
byte[] output = new byte[16];
ToBytes(output, 0);
return output;
}
///
/// Writes the raw bytes for this UUID to a byte array
///
/// Destination byte array
/// Position in the destination array to start
/// writing. Must be at least 16 bytes before the end of the array
public void ToBytes(byte[] dest, int pos)
{
byte[] bytes = Guid.ToByteArray();
dest[pos + 0] = bytes[3];
dest[pos + 1] = bytes[2];
dest[pos + 2] = bytes[1];
dest[pos + 3] = bytes[0];
dest[pos + 4] = bytes[5];
dest[pos + 5] = bytes[4];
dest[pos + 6] = bytes[7];
dest[pos + 7] = bytes[6];
Buffer.BlockCopy(bytes, 8, dest, pos + 8, 8);
}
///
/// Calculate an LLCRC (cyclic redundancy check) for this UUID
///
/// The CRC checksum for this UUID
public uint CRC()
{
uint retval = 0;
byte[] bytes = GetBytes();
retval += (uint)((bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0]);
retval += (uint)((bytes[7] << 24) + (bytes[6] << 16) + (bytes[5] << 8) + bytes[4]);
retval += (uint)((bytes[11] << 24) + (bytes[10] << 16) + (bytes[9] << 8) + bytes[8]);
retval += (uint)((bytes[15] << 24) + (bytes[14] << 16) + (bytes[13] << 8) + bytes[12]);
return retval;
}
///
/// Create a 64-bit integer representation from the second half of this UUID
///
/// An integer created from the last eight bytes of this UUID
public ulong GetULong()
{
byte[] bytes = Guid.ToByteArray();
return (ulong)
((ulong)bytes[8] +
((ulong)bytes[9] << 8) +
((ulong)bytes[10] << 16) +
((ulong)bytes[12] << 24) +
((ulong)bytes[13] << 32) +
((ulong)bytes[13] << 40) +
((ulong)bytes[14] << 48) +
((ulong)bytes[15] << 56));
}
#endregion Public Methods
#region Static Methods
///
/// Generate a UUID from a string
///
/// A string representation of a UUID, case
/// insensitive and can either be hyphenated or non-hyphenated
/// UUID.Parse("11f8aa9c-b071-4242-836b-13b7abe0d489")
public static UUID Parse(string val)
{
return new UUID(val);
}
///
/// Generate a UUID from a string
///
/// A string representation of a UUID, case
/// insensitive and can either be hyphenated or non-hyphenated
/// Will contain the parsed UUID if successful,
/// otherwise null
/// True if the string was successfully parse, otherwise false
/// UUID.TryParse("11f8aa9c-b071-4242-836b-13b7abe0d489", result)
public static bool TryParse(string val, out UUID result)
{
if (String.IsNullOrEmpty(val) ||
(val[0] == '{' && val.Length != 38) ||
(val.Length != 36 && val.Length != 32))
{
result = UUID.Zero;
return false;
}
try
{
result = Parse(val);
return true;
}
catch (Exception)
{
result = UUID.Zero;
return false;
}
}
///
/// Combine two UUIDs together by taking the MD5 hash of a byte array
/// containing both UUIDs
///
/// First UUID to combine
/// Second UUID to combine
/// The UUID product of the combination
public static UUID Combine(UUID first, UUID second)
{
// Construct the buffer that MD5ed
byte[] input = new byte[32];
Buffer.BlockCopy(first.GetBytes(), 0, input, 0, 16);
Buffer.BlockCopy(second.GetBytes(), 0, input, 16, 16);
return new UUID(Utils.MD5(input), 0);
}
///
///
///
///
public static UUID Random()
{
return new UUID(Guid.NewGuid());
}
#endregion Static Methods
#region Overrides
///
/// Return a hash code for this UUID, used by .NET for hash tables
///
/// An integer composed of all the UUID bytes XORed together
public override int GetHashCode()
{
return Guid.GetHashCode();
}
///
/// Comparison function
///
/// An object to compare to this UUID
/// True if the object is a UUID and both UUIDs are equal
public override bool Equals(object o)
{
if (!(o is UUID)) return false;
UUID uuid = (UUID)o;
return Guid == uuid.Guid;
}
///
/// Comparison function
///
/// UUID to compare to
/// True if the UUIDs are equal, otherwise false
public bool Equals(UUID uuid)
{
return Guid == uuid.Guid;
}
///
/// Get a hyphenated string representation of this UUID
///
/// A string representation of this UUID, lowercase and
/// with hyphens
/// 11f8aa9c-b071-4242-836b-13b7abe0d489
public override string ToString()
{
if (Guid == Guid.Empty)
return ZeroString;
else
return Guid.ToString();
}
#endregion Overrides
#region Operators
///
/// Equals operator
///
/// First UUID for comparison
/// Second UUID for comparison
/// True if the UUIDs are byte for byte equal, otherwise false
public static bool operator ==(UUID lhs, UUID rhs)
{
return lhs.Guid == rhs.Guid;
}
///
/// Not equals operator
///
/// First UUID for comparison
/// Second UUID for comparison
/// True if the UUIDs are not equal, otherwise true
public static bool operator !=(UUID lhs, UUID rhs)
{
return !(lhs == rhs);
}
///
/// XOR operator
///
/// First UUID
/// Second UUID
/// A UUID that is a XOR combination of the two input UUIDs
public static UUID operator ^(UUID lhs, UUID rhs)
{
byte[] lhsbytes = lhs.GetBytes();
byte[] rhsbytes = rhs.GetBytes();
byte[] output = new byte[16];
for (int i = 0; i < 16; i++)
{
output[i] = (byte)(lhsbytes[i] ^ rhsbytes[i]);
}
return new UUID(output, 0);
}
///
/// String typecasting operator
///
/// A UUID in string form. Case insensitive,
/// hyphenated or non-hyphenated
/// A UUID built from the string representation
public static explicit operator UUID(string val)
{
return new UUID(val);
}
#endregion Operators
/// An UUID with a value of all zeroes
public static readonly UUID Zero = new UUID();
/// A cache of UUID.Zero as a string to optimize a common path
private static readonly string ZeroString = Guid.Empty.ToString();
}
}