2022-04-26 00:55:56 +02:00
/*
* 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-14 21:54:27 +02:00
// 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]}} { }
2022-04-26 00:55:56 +02:00
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-14 21:54:27 +02:00
// 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; };
2022-04-26 00:55:56 +02:00
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 ) ; }
2022-05-14 21:54:27 +02:00
void setNull ( ) { Data1 = 0 ; * this = GUID ( ) ; }
2022-04-26 00:55:56 +02:00
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_ */