/* * Copyright (c) 2018-2020 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include namespace ams::util { namespace { struct UuidImpl { util::BitPack32 data[4]; using TimeLow = util::BitPack32::Field<0, BITSIZEOF(u32), u32>; using TimeMid = util::BitPack32::Field<0, BITSIZEOF(u16), u16>; using TimeHighAndVersion = util::BitPack32::Field; using Version = util::BitPack32::Field; static_assert(TimeHighAndVersion::Next == Version::Next); using ClockSeqHiAndReserved = util::BitPack32::Field<0, BITSIZEOF(u8), u8>; using Reserved = util::BitPack32::Field<6, 2, u8>; using ClockSeqLow = util::BitPack32::Field; using NodeLow = util::BitPack32::Field; static_assert(ClockSeqHiAndReserved::Next == Reserved::Next); using NodeHigh = util::BitPack32::Field<0, BITSIZEOF(u32), u32>; inline Uuid Convert() const { /* Convert the fields from native endian to big endian. */ util::BitPack32 converted[4] = {util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}}; converted[0].Set(util::ConvertToBigEndian(this->data[0].Get())); converted[1].Set(util::ConvertToBigEndian(this->data[1].Get())); converted[1].Set(util::ConvertToBigEndian(this->data[1].Get())); converted[2].Set(util::ConvertToBigEndian(this->data[2].Get())); converted[2].Set(util::ConvertToBigEndian(this->data[2].Get())); u64 node_lo = static_cast(this->data[2].Get()); u64 node_hi = static_cast(this->data[3].Get()); u64 node = util::ConvertToBigEndian48(static_cast((node_hi << BITSIZEOF(u16)) | (node_lo))); constexpr u64 NodeLoMask = (UINT64_C(1) << BITSIZEOF(u16)) - 1u; constexpr u64 NodeHiMask = (UINT64_C(1) << BITSIZEOF(u32)) - 1u; converted[2].Set(static_cast(node & NodeLoMask)); converted[3].Set(static_cast((node >> BITSIZEOF(u16)) & NodeHiMask)); Uuid uuid; std::memcpy(uuid.data, converted, sizeof(uuid.data)); return uuid; } }; static_assert(sizeof(UuidImpl) == sizeof(Uuid)); ALWAYS_INLINE Uuid GenerateUuidVersion4() { constexpr u16 Version = 0x4; constexpr u8 Reserved = 0x1; /* Generate a random uuid. */ UuidImpl uuid = {util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}}; os::GenerateRandomBytes(uuid.data, sizeof(uuid.data)); /* Set version and reserved. */ uuid.data[1].Set(Version); uuid.data[2].Set(Reserved); /* Return the uuid. */ return uuid.Convert(); } } Uuid GenerateUuid() { return GenerateUuidVersion4(); } Uuid GenerateUuidVersion5(const void *sha1_hash) { constexpr u16 Version = 0x5; constexpr u8 Reserved = 0x1; /* Generate a uuid from a SHA1 hash. */ UuidImpl uuid = {util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}}; std::memcpy(uuid.data, sha1_hash, sizeof(uuid.data)); /* Set version and reserved. */ uuid.data[1].Set(Version); uuid.data[2].Set(Reserved); /* Return the uuid. */ return uuid.Convert(); } }