mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-01 12:53:27 +01:00
406 lines
15 KiB
C++
406 lines
15 KiB
C++
/*
|
|
* guid.h
|
|
*
|
|
* Created on: 16 Apr 2020
|
|
* Author: jief
|
|
*/
|
|
|
|
#ifndef GUID_PLUS_PLUS_H_
|
|
#define GUID_PLUS_PLUS_H_
|
|
|
|
extern "C++"
|
|
{
|
|
|
|
//typedef int GUID;
|
|
#define GUID_PLUSPLUS_DEFINED
|
|
class GUID;
|
|
typedef GUID EFI_GUID;
|
|
#define CONST_EFI_GUID_PTR_T const EFI_GUID&
|
|
#define JCONST_EFI_GUID_PTR_T const EFI_GUID&
|
|
|
|
extern "C" {
|
|
#include <Uefi/UefiBaseType.h>
|
|
}
|
|
|
|
#include <stddef.h>
|
|
#include "../cpp_foundation/XToolsCommon.h"
|
|
#include "../cpp_foundation/XString.h"
|
|
|
|
|
|
constexpr EFI_GUID operator "" _guid(const char *str, size_t N);
|
|
|
|
/*
|
|
* Class to replace struct EFI_GUID to bring some syntaxic sugar : initialisation at construction, assignment, == operator, etc.
|
|
*/
|
|
|
|
// This class is just to enable static assignment of form : EFI_GUID guid = {0xF913C2C2, 0x5351, 0x4FDB, {0x93, 0x44, 0x70, 0xFF, 0xED, 0xB8, 0x42, 0x25}}
|
|
class GUID_Data4
|
|
{
|
|
public:
|
|
UINT8 i0;
|
|
UINT8 i1;
|
|
UINT8 i2;
|
|
UINT8 i3;
|
|
UINT8 i4;
|
|
UINT8 i5;
|
|
UINT8 i6;
|
|
UINT8 i7;
|
|
};
|
|
|
|
|
|
class GUID
|
|
{
|
|
public:
|
|
UINT32 Data1;
|
|
UINT16 Data2;
|
|
UINT16 Data3;
|
|
UINT8 Data4[8];
|
|
|
|
constexpr GUID() : Data1(0), Data2(0), Data3(0), Data4{0,0,0,0,0,0,0,0} {}
|
|
|
|
// 2022-05 : defining a copy ctor force to define a copy assignment.
|
|
//constexpr GUID(const GUID& other) : GUID{other.Data1, other.Data2, other.Data3, {other.Data4[0], other.Data4[1], other.Data4[2], other.Data4[3], other.Data4[4], other.Data4[5], other.Data4[6], other.Data4[7]}} { }
|
|
constexpr GUID(UINT32 _data1, UINT16 _data2, UINT16 _data3, const GUID_Data4& _data4) : Data1(_data1), Data2(_data2), Data3(_data3), Data4{_data4.i0, _data4.i1, _data4.i2, _data4.i3, _data4.i4, _data4.i5, _data4.i6, _data4.i7} { }
|
|
|
|
// 2022-05 : I don't know how to define a constexpr copy assignment. The compiler does it for me.
|
|
// constexpr const GUID& operator = (const GUID& other) { return /*(void)(Data1 = other.Data1), static_cast<void>(Data2 = other.Data2), (void)(Data3 = other.Data3), (void)(Data4[0] = other.Data4[0]), (void)(Data4[1] = other.Data4[1]), (void)(Data4[2] = other.Data4[2]), (void)(Data4[3] = other.Data4[3]), (void)(Data4[4] = other.Data4[4]), (void)(Data4[5] = other.Data4[5]), (void)(Data4[6] = other.Data4[6]), (void)(Data4[7] = other.Data4[7]), */*this; };
|
|
|
|
constexpr bool operator == (const GUID& other) const {
|
|
return Data1 == other.Data1 && Data2 == other.Data2 && Data3 == other.Data3 && Data4[0] == other.Data4[0] && Data4[1] == other.Data4[1] && Data4[2] == other.Data4[2] && Data4[3] == other.Data4[3] && Data4[4] == other.Data4[4] && Data4[5] == other.Data4[5] && Data4[6] == other.Data4[6] && Data4[7] == other.Data4[7];
|
|
}
|
|
constexpr bool operator != (const GUID& other) const { return ! (*this == other); }
|
|
|
|
void setNull() { Data1 = 0; *this = GUID(); }
|
|
constexpr bool isNull() const { return Data1 == 0 && Data2 == 0 && Data3 == 0 && Data4[0] == 0 && Data4[1] == 0 && Data4[2] == 0 && Data4[3] == 0 && Data4[4] == 0 && Data4[5] == 0 && Data4[6] == 0 && Data4[7] == 0; }
|
|
constexpr bool notNull() const { return !isNull(); }
|
|
|
|
int getVariant() const {
|
|
if ( Data4[0] < 0x80 ) return 0;
|
|
if ( Data4[0] < 0xC0 ) return 1;
|
|
if ( Data4[0] < 0xE0 ) return 2;
|
|
return 3;
|
|
}
|
|
|
|
private:
|
|
// Helper function for _guid litteral operator. They are private because they are not made to be called directly.
|
|
// Conversion from litteral comes from https://github.com/tobias-loew/constexpr-GUID-cpp-11
|
|
static constexpr const size_t short_guid_form_length = 36; // XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
|
static constexpr const size_t long_guid_form_length = 38; // {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
|
|
|
|
static int parse_guid_error() { panic("Incorrect format for guid operator."); return 0; } // IMPORTANT : not constexpr
|
|
static EFI_GUID parse_guid_error2() { panic("Incorrect format for guid operator."); return GUID(); } // IMPORTANT : not constexpr
|
|
|
|
|
|
static constexpr bool is_hex_digit(const char c)
|
|
{
|
|
return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
|
|
}
|
|
|
|
template <typename T, enable_if( is_char(T) ) >
|
|
static constexpr uint8_t parse_hex_digit(const T c)
|
|
{
|
|
return
|
|
('0' <= c && c <= '9')
|
|
? c - '0'
|
|
: ('a' <= c && c <= 'f')
|
|
? 10 + c - 'a'
|
|
: ('A' <= c && c <= 'F')
|
|
? 10 + c - 'A'
|
|
: parse_guid_error();
|
|
// : throw "invalid character in GUID"; // throw doesn't compile with -fno-exception.
|
|
}
|
|
|
|
template <typename T, enable_if( is_char(T) ) >
|
|
static constexpr uint8_t parse_hex_uint8_t(const T *ptr)
|
|
{
|
|
return (parse_hex_digit(ptr[0]) << 4) + parse_hex_digit(ptr[1]);
|
|
}
|
|
|
|
template <typename T, enable_if( is_char(T) ) >
|
|
static constexpr uint16_t parse_hex_uint16_t(const T *ptr)
|
|
{
|
|
return (parse_hex_uint8_t(ptr) << 8) + parse_hex_uint8_t(ptr + 2);
|
|
}
|
|
|
|
template <typename T, enable_if( is_char(T) ) >
|
|
static constexpr uint32_t parse_hex_uint32_t(const T* ptr)
|
|
{
|
|
return (parse_hex_uint16_t(ptr) << 16) + parse_hex_uint16_t(ptr + 4);
|
|
}
|
|
|
|
static constexpr uint16_t parse_hex_uint16_t_be(const char *ptr)
|
|
{
|
|
return (parse_hex_uint8_t(ptr + 2) << 8) + parse_hex_uint8_t(ptr);
|
|
}
|
|
|
|
static constexpr uint32_t parse_hex_uint32_t_be(const char *ptr)
|
|
{
|
|
return (parse_hex_uint16_t_be(ptr + 4) << 16) + parse_hex_uint16_t_be(ptr);
|
|
}
|
|
|
|
|
|
// This function call parse_guid_error2(). That's a way to get a compile error.
|
|
// Therefore, if called fron non-constexpr, it panics.
|
|
static constexpr GUID parse_guid(const char *begin)
|
|
{
|
|
return
|
|
begin[8] != '-'
|
|
|| begin[13] != '-'
|
|
|| begin[18] != '-'
|
|
|| begin[23] != '-'
|
|
? parse_guid_error2()
|
|
: GUID{
|
|
parse_hex_uint32_t(begin),
|
|
parse_hex_uint16_t(begin + 8 + 1),
|
|
parse_hex_uint16_t(begin + 8 + 1 + 4 + 1),
|
|
{
|
|
parse_hex_uint8_t(begin + 8 + 1 + 4 + 1 + 4 + 1),
|
|
parse_hex_uint8_t(begin + 8 + 1 + 4 + 1 + 4 + 1 + 2),
|
|
parse_hex_uint8_t(begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1),
|
|
parse_hex_uint8_t(begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2),
|
|
parse_hex_uint8_t(begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2),
|
|
parse_hex_uint8_t(begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2),
|
|
parse_hex_uint8_t(begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2 + 2),
|
|
parse_hex_uint8_t(begin + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2 + 2 + 2)
|
|
}
|
|
};
|
|
}
|
|
|
|
friend constexpr GUID operator "" _guid(const char *str, size_t N);
|
|
|
|
public:
|
|
|
|
/** Returns true is Str is ascii Guid in format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */
|
|
template <typename T, typename IntegralType, enable_if( is_char(T) && is_integral(IntegralType) ) >
|
|
static constexpr bool IsValidGuidString(const T* s, IntegralType n)
|
|
{
|
|
return
|
|
(
|
|
( n == 36
|
|
&& is_hex_digit(s[0])
|
|
&& is_hex_digit(s[1])
|
|
&& is_hex_digit(s[2])
|
|
&& is_hex_digit(s[3])
|
|
&& is_hex_digit(s[4])
|
|
&& is_hex_digit(s[5])
|
|
&& is_hex_digit(s[6])
|
|
&& is_hex_digit(s[7])
|
|
&& s[8] == '-'
|
|
&& is_hex_digit(s[9])
|
|
&& is_hex_digit(s[10])
|
|
&& is_hex_digit(s[11])
|
|
&& is_hex_digit(s[12])
|
|
&& s[13] == '-'
|
|
&& is_hex_digit(s[14])
|
|
&& is_hex_digit(s[15])
|
|
&& is_hex_digit(s[16])
|
|
&& is_hex_digit(s[17])
|
|
&& s[18] == '-'
|
|
&& is_hex_digit(s[19])
|
|
&& is_hex_digit(s[20])
|
|
&& is_hex_digit(s[21])
|
|
&& is_hex_digit(s[22])
|
|
&& s[23] == '-'
|
|
&& is_hex_digit(s[24])
|
|
&& is_hex_digit(s[25])
|
|
&& is_hex_digit(s[26])
|
|
&& is_hex_digit(s[27])
|
|
&& is_hex_digit(s[28])
|
|
&& is_hex_digit(s[29])
|
|
&& is_hex_digit(s[30])
|
|
&& is_hex_digit(s[31])
|
|
&& is_hex_digit(s[32])
|
|
&& is_hex_digit(s[33])
|
|
&& is_hex_digit(s[34])
|
|
&& is_hex_digit(s[35])
|
|
)
|
|
||
|
|
( n == 38
|
|
&& s[0] == '{'
|
|
&& is_hex_digit(s[1])
|
|
&& is_hex_digit(s[2])
|
|
&& is_hex_digit(s[3])
|
|
&& is_hex_digit(s[4])
|
|
&& is_hex_digit(s[5])
|
|
&& is_hex_digit(s[6])
|
|
&& is_hex_digit(s[7])
|
|
&& is_hex_digit(s[8])
|
|
&& s[9] == '-'
|
|
&& is_hex_digit(s[10])
|
|
&& is_hex_digit(s[11])
|
|
&& is_hex_digit(s[12])
|
|
&& is_hex_digit(s[13])
|
|
&& s[14] == '-'
|
|
&& is_hex_digit(s[15])
|
|
&& is_hex_digit(s[16])
|
|
&& is_hex_digit(s[17])
|
|
&& is_hex_digit(s[18])
|
|
&& s[19] == '-'
|
|
&& is_hex_digit(s[20])
|
|
&& is_hex_digit(s[21])
|
|
&& is_hex_digit(s[22])
|
|
&& is_hex_digit(s[23])
|
|
&& s[24] == '-'
|
|
&& is_hex_digit(s[25])
|
|
&& is_hex_digit(s[26])
|
|
&& is_hex_digit(s[27])
|
|
&& is_hex_digit(s[28])
|
|
&& is_hex_digit(s[29])
|
|
&& is_hex_digit(s[30])
|
|
&& is_hex_digit(s[31])
|
|
&& is_hex_digit(s[32])
|
|
&& is_hex_digit(s[33])
|
|
&& is_hex_digit(s[34])
|
|
&& is_hex_digit(s[35])
|
|
&& is_hex_digit(s[36])
|
|
&& s[37] == '}'
|
|
)
|
|
);
|
|
}
|
|
|
|
template <typename T, typename IntegralType, enable_if( is_char(T) && is_integral(IntegralType) ) >
|
|
GUID& takeValueFrom(const T* s, IntegralType n)
|
|
{
|
|
if ( !IsValidGuidString(s, n) ) { setNull(); return *this; }
|
|
|
|
// if ( parse_hex_digit(s[19]) == 0x0C || parse_hex_digit(s[19]) == 0x0D ) // Check variant. It's not clear in Clover if we follow that.
|
|
// That's why there is 2 methods : LE/BE selection is manual
|
|
// LE binary storage
|
|
if ( s[0] == '{' ) s += 1;
|
|
*this = GUID{
|
|
parse_hex_uint32_t(s),
|
|
parse_hex_uint16_t(s + 8 + 1),
|
|
parse_hex_uint16_t(s + 8 + 1 + 4 + 1),
|
|
{
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2 + 2 + 2)
|
|
}
|
|
};
|
|
return *this;
|
|
}
|
|
|
|
template <typename T, typename IntegralType, enable_if( is_char(T) && is_integral(IntegralType) ) >
|
|
GUID& takeValueFromBE(const T* s, IntegralType n)
|
|
{
|
|
if ( !IsValidGuidString(s, n) ) { setNull(); return *this; }
|
|
|
|
// if ( parse_hex_digit(s[19]) == 0x0C || parse_hex_digit(s[19]) == 0x0D ) // Check variant. It's not clear in Clover if we follow that.
|
|
// That's why there is 2 methods : LE/BE selection is manual
|
|
if ( s[0] == '{' ) s += 1;
|
|
*this = GUID{
|
|
parse_hex_uint32_t_be(s),
|
|
parse_hex_uint16_t_be(s + 8 + 1),
|
|
parse_hex_uint16_t_be(s + 8 + 1 + 4 + 1),
|
|
{
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2 + 2),
|
|
parse_hex_uint8_t(s + 8 + 1 + 4 + 1 + 4 + 1 + 2 + 2 + 1 + 2 + 2 + 2 + 2 + 2)
|
|
}
|
|
};
|
|
return *this;
|
|
}
|
|
|
|
template <typename T, enable_if( is___String(T) )>
|
|
GUID& takeValueFrom(const T& Str)
|
|
{
|
|
if ( Str.isEmpty() ) { setNull(); return *this; }
|
|
return takeValueFrom(Str.data(), Str.length());
|
|
}
|
|
|
|
template <typename T, enable_if( is___String(T) )>
|
|
GUID& takeValueFromBE(const T& Str)
|
|
{
|
|
if ( Str.isEmpty() ) { setNull(); return *this; }
|
|
return takeValueFromBE(Str.data(), Str.length());
|
|
}
|
|
|
|
|
|
// Creating a ctor (which allow assignement) from a string is a bit dangerous.
|
|
// You might endup writing guid1 = guid2, expecting this assignement to always work.
|
|
// But if guid2 is a XString it can fails.
|
|
// Assignement is such a basic operator that no one can guess it could fail.
|
|
// By being forced to use takeValueFrom, it's clearer that it can fail and that you have to check.
|
|
// template <typename T, enable_if( is___String(T) )>
|
|
// GUID(const T& Str) {
|
|
// takeValueFrom(Str);
|
|
// }
|
|
|
|
|
|
|
|
XString8 toXString8(bool be = false) const
|
|
{
|
|
XString8 returnValue;
|
|
// if ( getVariant() == 2 ) {
|
|
if ( !be ) {
|
|
returnValue.S8Printf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
|
Data1, Data2, Data3, Data4[0], Data4[1],
|
|
Data4[2], Data4[3], Data4[4], Data4[5], Data4[6], Data4[7]);
|
|
}else{
|
|
UINT8 *GuidData = (UINT8 *)this;
|
|
returnValue.S8Printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
|
GuidData[0], GuidData[1], GuidData[2], GuidData[3],
|
|
GuidData[4], GuidData[5],
|
|
GuidData[6], GuidData[7],
|
|
GuidData[8], GuidData[9], GuidData[10], GuidData[11],
|
|
GuidData[12], GuidData[13], GuidData[14], GuidData[15]);
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
XString8 toXStringW(bool be = false) const
|
|
{
|
|
XStringW returnValue;
|
|
// if ( getVariant() == 2 ) {
|
|
if ( !be ) {
|
|
returnValue.SWPrintf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
|
Data1, Data2, Data3, Data4[0], Data4[1],
|
|
Data4[2], Data4[3], Data4[4], Data4[5], Data4[6], Data4[7]);
|
|
}else{
|
|
UINT8 *GuidData = (UINT8 *)this;
|
|
returnValue.SWPrintf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
|
GuidData[0], GuidData[1], GuidData[2], GuidData[3],
|
|
GuidData[4], GuidData[5],
|
|
GuidData[6], GuidData[7],
|
|
GuidData[8], GuidData[9], GuidData[10], GuidData[11],
|
|
GuidData[12], GuidData[13], GuidData[14], GuidData[15]);
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
|
|
/** Returns true is Str is ascii Guid in format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */
|
|
template <typename T, enable_if( is___String(T) )>
|
|
static bool IsValidGuidString(const T& Str)
|
|
{
|
|
return IsValidGuidString(Str.data(), Str.length());
|
|
}
|
|
|
|
};
|
|
|
|
|
|
constexpr GUID operator "" _guid(const char *str, size_t N)
|
|
{
|
|
return (!(N == GUID::long_guid_form_length || N == GUID::short_guid_form_length))
|
|
? GUID::parse_guid_error2()
|
|
: (N == GUID::long_guid_form_length && (str[0] != '{' || str[GUID::long_guid_form_length - 1] != '}'))
|
|
? GUID::parse_guid_error2()
|
|
: GUID::parse_guid(str + (N == GUID::long_guid_form_length ? 1 : 0));
|
|
}
|
|
|
|
constexpr const GUID nullGuid;
|
|
|
|
} // extern C++
|
|
|
|
#endif /* NEWGUID_H_ */
|