123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- #include "guid.h"
- #include "ylimits.h"
- #include "string.h"
- #include <util/string/ascii.h>
- #include <util/string/builder.h>
- #include <util/stream/format.h>
- #include <util/system/unaligned_mem.h>
- #include <util/random/easy.h>
- namespace {
- inline void LowerCaseHex(TString& s) {
- for (auto&& c : s) {
- c = AsciiToLower(c);
- }
- }
- } // namespace
- TString TGUID::AsGuidString() const {
- TStringBuilder s;
- s.reserve(50);
- s << Hex(dw[0], 0) << '-' << Hex(dw[1], 0) << '-' << Hex(dw[2], 0) << '-' << Hex(dw[3], 0);
- LowerCaseHex(s);
- return std::move(s);
- }
- TString TGUID::AsUuidString() const {
- TStringBuilder s;
- s.reserve(50);
- s << Hex(dw[0], HF_FULL) << '-';
- s << Hex(static_cast<ui16>(dw[1] >> 16), HF_FULL) << '-' << Hex(static_cast<ui16>(dw[1]), HF_FULL) << '-';
- s << Hex(static_cast<ui16>(dw[2] >> 16), HF_FULL) << '-' << Hex(static_cast<ui16>(dw[2]), HF_FULL);
- s << Hex(dw[3], HF_FULL);
- LowerCaseHex(s);
- return std::move(s);
- }
- TGUID TGUID::Create() {
- TGUID result;
- CreateGuid(&result);
- return result;
- }
- void CreateGuid(TGUID* res) {
- ui64* dw = reinterpret_cast<ui64*>(res->dw);
- WriteUnaligned<ui64>(&dw[0], RandomNumber<ui64>());
- WriteUnaligned<ui64>(&dw[1], RandomNumber<ui64>());
- }
- TGUID TGUID::CreateTimebased() {
- TGUID result;
- // GUID_EPOCH_OFFSET is the number of 100-ns intervals between the
- // UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
- constexpr ui64 GUID_EPOCH_OFFSET = 0x01b21dd213814000;
- const ui64 timestamp = Now().NanoSeconds() / 100 + GUID_EPOCH_OFFSET;
- result.dw[0] = ui32(timestamp & 0xffffffff); // time low
- const ui32 timeMid = ui32((timestamp >> 32) & 0xffff);
- constexpr ui32 UUID_VERSION = 1;
- const ui32 timeHighAndVersion = ui16((timestamp >> 48) & 0x0fff) | (UUID_VERSION << 12);
- result.dw[1] = (timeMid << 16) | timeHighAndVersion;
- const ui32 clockSeq = RandomNumber<ui32>(0x3fff) | 0x8000;
- result.dw[2] = (clockSeq << 16) | RandomNumber<ui16>();
- result.dw[3] = RandomNumber<ui32>() | (1 << 24);
- return result;
- }
- TString GetGuidAsString(const TGUID& g) {
- return g.AsGuidString();
- }
- TString CreateGuidAsString() {
- return TGUID::Create().AsGuidString();
- }
- static bool GetDigit(const char c, ui32& digit) {
- digit = 0;
- if ('0' <= c && c <= '9') {
- digit = c - '0';
- } else if ('a' <= c && c <= 'f') {
- digit = c - 'a' + 10;
- } else if ('A' <= c && c <= 'F') {
- digit = c - 'A' + 10;
- } else {
- return false; // non-hex character
- }
- return true;
- }
- bool GetGuid(const TStringBuf s, TGUID& result) {
- size_t partId = 0;
- ui64 partValue = 0;
- bool isEmptyPart = true;
- for (size_t i = 0; i != s.size(); ++i) {
- const char c = s[i];
- if (c == '-') {
- if (isEmptyPart || partId == 3) { // x-y--z, -x-y-z or x-y-z-m-...
- return false;
- }
- result.dw[partId] = static_cast<ui32>(partValue);
- ++partId;
- partValue = 0;
- isEmptyPart = true;
- continue;
- }
- ui32 digit = 0;
- if (!GetDigit(c, digit)) {
- return false;
- }
- partValue = partValue * 16 + digit;
- isEmptyPart = false;
- // overflow check
- if (partValue > Max<ui32>()) {
- return false;
- }
- }
- if (partId != 3 || isEmptyPart) { // x-y or x-y-z-
- return false;
- }
- result.dw[partId] = static_cast<ui32>(partValue);
- return true;
- }
- // Parses GUID from s and checks that it's valid.
- // In case of error returns TGUID().
- TGUID GetGuid(const TStringBuf s) {
- TGUID result;
- if (GetGuid(s, result)) {
- return result;
- }
- return TGUID();
- }
- bool GetUuid(const TStringBuf s, TGUID& result) {
- if (s.size() != 36) {
- return false;
- }
- size_t partId = 0;
- ui64 partValue = 0;
- size_t digitCount = 0;
- for (size_t i = 0; i < s.size(); ++i) {
- const char c = s[i];
- if (c == '-') {
- if (i != 8 && i != 13 && i != 18 && i != 23) {
- return false;
- }
- continue;
- }
- ui32 digit = 0;
- if (!GetDigit(c, digit)) {
- return false;
- }
- partValue = partValue * 16 + digit;
- if (++digitCount == 8) {
- result.dw[partId++] = partValue;
- digitCount = 0;
- }
- }
- return true;
- }
- // Parses GUID from uuid and checks that it's valid.
- // In case of error returns TGUID().
- TGUID GetUuid(const TStringBuf s) {
- TGUID result;
- if (GetUuid(s, result)) {
- return result;
- }
- return TGUID();
- }
|