//****************************************************************************************************** // GuidExtensions.cs - Gbtc // // Copyright © 2014, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 05/07/2014 - Steven E. Chisholm // Generated original version of source code. // //****************************************************************************************************** using System; using System.ComponentModel; using System.Runtime.CompilerServices; namespace GSF { /// /// Extension methods for . /// public static unsafe class GuidExtensions { #region [ Big Endian Based Encoding (ie RFC 4122) ] /// /// Encodes a following RFC 4122. /// /// The to serialize. /// Destination buffer to hold serialized . /// Starting index in . public static int ToRfcBytes(this Guid guid, byte[] buffer, int startingIndex) { // Since Microsoft is not very clear how Guid.ToByteArray() performs on big endian processors // we are assuming that the internal structure of a Guid will always be the same. Reviewing // mono source code the internal structure is also the same. buffer.ValidateParameters(startingIndex, 16); byte* src = (byte*)&guid; fixed (byte* dst = &buffer[startingIndex]) { if (BitConverter.IsLittleEndian) { // Guid._a (int) dst[0] = src[3]; dst[1] = src[2]; dst[2] = src[1]; dst[3] = src[0]; // Guid._b (short) dst[4] = src[5]; dst[5] = src[4]; // Guid._c (short) dst[6] = src[7]; dst[7] = src[6]; // Guid._d - Guid._k (8 bytes) // Since already encoded as big endian, just copy the data *(long*)(dst + 8) = *(long*)(src + 8); } else { // All fields are encoded big-endian, just copy *(long*)(dst + 0) = *(long*)(src + 0); *(long*)(dst + 8) = *(long*)(src + 8); } } return 16; } /// /// Encodes a following RFC 4122. /// /// The to serialize. /// Destination buffer to hold serialized . public static int ToRfcBytes(this Guid guid, byte* buffer) { byte* src = (byte*)&guid; if (BitConverter.IsLittleEndian) { // Guid._a (int) buffer[0] = src[3]; buffer[1] = src[2]; buffer[2] = src[1]; buffer[3] = src[0]; // Guid._b (short) buffer[4] = src[5]; buffer[5] = src[4]; // Guid._c (short) buffer[6] = src[7]; buffer[7] = src[6]; // Guid._d - Guid._k (8 bytes) // Since already encoded as big endian, just copy the data *(long*)(buffer + 8) = *(long*)(src + 8); } else { // All fields are encoded big-endian, just copy *(long*)(buffer + 0) = *(long*)(src + 0); *(long*)(buffer + 8) = *(long*)(src + 8); } return 16; } /// /// Encodes a following RFC 4122. /// /// to serialize. /// A array that represents a big-endian encoded . public static byte[] ToRfcBytes(this Guid guid) { byte[] rv = new byte[16]; guid.ToRfcBytes(rv, 0); return rv; } /// /// Decodes a following RFC 4122 /// /// Buffer containing a serialized big-endian encoded . /// deserialized from . public static Guid ToRfcGuid(this byte[] buffer) { return buffer.ToRfcGuid(0); } /// /// Decodes a following RFC 4122 /// /// Buffer containing a serialized big-endian encoded . /// deserialized from . public static Guid ToRfcGuid(byte* buffer) { // Since Microsoft is not very clear how Guid.ToByteArray() performs on big endian processors // we are assuming that the internal structure of a Guid will always be the same. Reviewing // mono source code the internal structure is also the same. Guid rv; byte* dst = (byte*)&rv; if (BitConverter.IsLittleEndian) { // Guid._a (int) dst[0] = buffer[3]; dst[1] = buffer[2]; dst[2] = buffer[1]; dst[3] = buffer[0]; // Guid._b (short) dst[4] = buffer[5]; dst[5] = buffer[4]; // Guid._c (short) dst[6] = buffer[7]; dst[7] = buffer[6]; // Guid._d - Guid._k (8 bytes) // Since already encoded as big endian, just copy the data *(long*)(dst + 8) = *(long*)(buffer + 8); } else { // All fields are encoded big-endian, just copy *(long*)(dst + 0) = *(long*)(buffer + 0); *(long*)(dst + 8) = *(long*)(buffer + 8); } return rv; } /// /// Decodes a following RFC 4122 /// /// Buffer containing a serialized big-endian encoded . /// Starting index in . /// deserialized from . public static Guid ToRfcGuid(this byte[] buffer, int startingIndex) { buffer.ValidateParameters(startingIndex, 16); // Since Microsoft is not very clear how Guid.ToByteArray() performs on big endian processors // we are assuming that the internal structure of a Guid will always be the same. Reviewing // mono source code the internal structure is also the same. Guid rv; byte* dst = (byte*)&rv; fixed (byte* src = &buffer[startingIndex]) { if (BitConverter.IsLittleEndian) { // Guid._a (int) dst[0] = src[3]; dst[1] = src[2]; dst[2] = src[1]; dst[3] = src[0]; // Guid._b (short) dst[4] = src[5]; dst[5] = src[4]; // Guid._c (short) dst[6] = src[7]; dst[7] = src[6]; // Guid._d - Guid._k (8 bytes) // Since already encoded as big endian, just copy the data *(long*)(dst + 8) = *(long*)(src + 8); } else { // All fields are encoded big-endian, just copy *(long*)(dst + 0) = *(long*)(src + 0); *(long*)(dst + 8) = *(long*)(src + 8); } return rv; } } #endregion #region [ Little Endian Encoding ] //--------------------------------------------------------------------------------------------------------- // To encourage the use of RFCBytes, these methods will not be extension methods. //--------------------------------------------------------------------------------------------------------- /// /// Gets the little endian encoded bytes. /// /// the to serialize /// A [] that represents a big endian encoded Guid. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] ToLittleEndianBytes(Guid guid) { byte[] rv = new byte[16]; CopyLittleEndianBytes(guid, rv, 0); return rv; } /// /// Writes a Guid in Little Endian byte order. /// /// the to serialize /// where to store the /// the starting index in [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int CopyLittleEndianBytes(Guid guid, byte[] buffer, int startingIndex) { buffer.ValidateParameters(startingIndex, 16); fixed (byte* dst = &buffer[startingIndex]) return CopyLittleEndianBytes(guid, dst); } /// /// Writes a Guid in Little Endian byte order. /// /// the to serialize /// where to store the public static int CopyLittleEndianBytes(Guid guid, byte* buffer) { byte* src = (byte*)&guid; if (BitConverter.IsLittleEndian) { //just copy the data *(long*)(buffer + 0) = *(long*)(src + 0); *(long*)(buffer + 8) = *(long*)(src + 8); } else { //Guid._a (int) //swap endian buffer[0] = src[3]; buffer[1] = src[2]; buffer[2] = src[1]; buffer[3] = src[0]; //Guid._b (short) //swap endian buffer[4] = src[5]; buffer[5] = src[4]; //Guid._c (short) //swap endian buffer[6] = src[7]; buffer[7] = src[6]; //Guid._d - Guid._k (8 bytes) *(long*)(buffer + 8) = *(long*)(src + 8); } return 16; } /// /// Reads a Guid in Little Endian byte order. /// /// where to read the . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Guid ToLittleEndianGuid(byte[] buffer) { buffer.ValidateParameters(0, 16); fixed (byte* src = buffer) return ToLittleEndianGuid(src); } /// /// Mimicks the encoding that was present in LittleEndianOrder on a Little Endian CPU. /// /// where to read the . /// the starting index in /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Guid ToLittleEndianGuid(byte[] buffer, int startingIndex) { buffer.ValidateParameters(startingIndex, 16); fixed (byte* src = &buffer[startingIndex]) return ToLittleEndianGuid(src); } /// /// Reads a Guid in Little Endian byte order. /// /// where to read the . /// public static Guid ToLittleEndianGuid(byte* buffer) { Guid rv; byte* dst = (byte*)&rv; if (BitConverter.IsLittleEndian) { //internal stucture is correct, just copy *(long*)(dst + 0) = *(long*)(buffer + 0); *(long*)(dst + 8) = *(long*)(buffer + 8); } else { //Guid._a (int) //swap endian dst[0] = buffer[3]; dst[1] = buffer[2]; dst[2] = buffer[1]; dst[3] = buffer[0]; //Guid._b (short) //swap endian dst[4] = buffer[5]; dst[5] = buffer[4]; //Guid._c (short) //swap endian dst[6] = buffer[7]; dst[7] = buffer[6]; //Guid._d - Guid._k (8 bytes) *(long*)(dst + 8) = *(long*)(buffer + 8); } return rv; } #endregion //--------------------------------------------------------------------------------------------------------- // Obsolete methods for compatibility with incorrectly implemented old code in EndianOrder's Guid methods // EndianOrder's encoding methods were not architecture independent. Therefore, the little endian // Architecture was assumed and these methods were deprecated //--------------------------------------------------------------------------------------------------------- /// /// Mimicks the encoding that was present in BigEndianOrder. /// /// the to serialize /// A [] that represents a big endian encoded Guid. [Obsolete("This method is for backwards compatibility only. Use ToRfcBytes from now on.", false)] [EditorBrowsable(EditorBrowsableState.Never)] public static byte[] __ToBigEndianOrderBytes(Guid guid) { byte[] rv = new byte[16]; __ToBigEndianOrderBytes(guid, rv, 0); return rv; } /// /// Mimicks the encoding that was present in BigEndianOrder. /// /// the to serialize /// where to store the /// the starting index in [Obsolete("This method is for backwards compatibility only. Use ToRfcBytes from now on.", false)] [EditorBrowsable(EditorBrowsableState.Never)] public static int __ToBigEndianOrderBytes(Guid guid, byte[] buffer, int startingIndex) { buffer.ValidateParameters(startingIndex, 16); byte* src = (byte*)&guid; fixed (byte* dst = &buffer[startingIndex]) { if (BitConverter.IsLittleEndian) { dst[15] = src[0]; dst[14] = src[1]; dst[13] = src[2]; dst[12] = src[3]; dst[11] = src[4]; dst[10] = src[5]; dst[9] = src[6]; dst[8] = src[7]; dst[7] = src[8]; dst[6] = src[9]; dst[5] = src[10]; dst[4] = src[11]; dst[3] = src[12]; dst[2] = src[13]; dst[1] = src[14]; dst[0] = src[15]; } else { //Guid._a (int) //swap endian dst[15] = src[3]; dst[14] = src[2]; dst[13] = src[1]; dst[12] = src[0]; //Guid._b (short) //swap endian dst[11] = src[5]; dst[10] = src[4]; //Guid._c (short) //swap endian dst[9] = src[7]; dst[8] = src[6]; //Guid._d - Guid._k (8 bytes) dst[7] = src[8]; dst[6] = src[9]; dst[5] = src[10]; dst[4] = src[11]; dst[3] = src[12]; dst[2] = src[13]; dst[1] = src[14]; dst[0] = src[15]; } } return 16; } /// /// Mimicks the encoding that was present in BigEndianOrder. /// /// where to read the . /// [Obsolete("This method is for backwards compatibility only. Use ToRfcGuid from now on.", false)] [EditorBrowsable(EditorBrowsableState.Never)] public static Guid __ToBigEndianOrderGuid(byte[] buffer) { return __ToBigEndianOrderGuid(buffer, 0); } /// /// Mimicks the encoding that was present in BigEndianOrder. /// /// where to read the . /// the starting index in /// [Obsolete("This method is for backwards compatibility only. Use ToRfcGuid from now on.", false)] [EditorBrowsable(EditorBrowsableState.Never)] public static Guid __ToBigEndianOrderGuid(byte[] buffer, int startingIndex) { buffer.ValidateParameters(startingIndex, 16); Guid rv; byte* dst = (byte*)&rv; fixed (byte* src = &buffer[startingIndex]) { if (BitConverter.IsLittleEndian) { dst[15] = src[0]; dst[14] = src[1]; dst[13] = src[2]; dst[12] = src[3]; dst[11] = src[4]; dst[10] = src[5]; dst[9] = src[6]; dst[8] = src[7]; dst[7] = src[8]; dst[6] = src[9]; dst[5] = src[10]; dst[4] = src[11]; dst[3] = src[12]; dst[2] = src[13]; dst[1] = src[14]; dst[0] = src[15]; } else { //ToDo: Test this on a big endian architecture. //Guid._a (int) //swap endian dst[15] = src[3]; dst[14] = src[2]; dst[13] = src[1]; dst[12] = src[0]; //Guid._b (short) //swap endian dst[11] = src[5]; dst[10] = src[4]; //Guid._c (short) //swap endian dst[9] = src[7]; dst[8] = src[6]; //Guid._d - Guid._k (8 bytes) dst[7] = src[8]; dst[6] = src[9]; dst[5] = src[10]; dst[4] = src[11]; dst[3] = src[12]; dst[2] = src[13]; dst[1] = src[14]; dst[0] = src[15]; } return rv; } } } }