diff --git a/internal/platform/uuid.cc b/internal/platform/uuid.cc index a22ab7df..c0e46ba4 100644 --- a/internal/platform/uuid.cc +++ b/internal/platform/uuid.cc @@ -14,11 +14,20 @@ #include "internal/platform/uuid.h" +#include +#include #include +#include +#include +#include #include #include +#include -#include "absl/strings/escaping.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" #include "internal/platform/implementation/crypto.h" namespace nearby { @@ -32,6 +41,49 @@ std::ostream& write_hex(std::ostream& os, absl::string_view data) { } } // namespace +// Based on the Java implementation +// http://androidxref.com/8.0.0_r4/xref/libcore/ojluni/src/main/java/java/util/UUID.java#191 +std::optional Uuid::FromString(absl::string_view data) { + std::vector components = absl::StrSplit(data, '-'); + if (components.size() != 5) { + return std::nullopt; + } + + for (std::string& component : components) { + component = absl::StrCat("0x", component); + } + + int64_t most_sig_bits = 0L; + int64_t least_sig_bits = 0L; + int64_t temp; + if (!absl::SimpleHexAtoi(components[0], &temp)) { + return std::nullopt; + } + most_sig_bits = temp; + most_sig_bits <<= 16; + if (!absl::SimpleHexAtoi(components[1], &temp)) { + return std::nullopt; + } + most_sig_bits |= temp; + most_sig_bits <<= 16; + if (!absl::SimpleHexAtoi(components[2], &temp)) { + return std::nullopt; + } + most_sig_bits |= temp; + + if (!absl::SimpleHexAtoi(components[3], &temp)) { + return std::nullopt; + } + least_sig_bits = temp; + least_sig_bits <<= 48; + if (!absl::SimpleHexAtoi(components[4], &temp)) { + return std::nullopt; + } + least_sig_bits |= temp; + + return Uuid(most_sig_bits, least_sig_bits); +} + Uuid::Uuid(absl::string_view data) { // Based on the Java counterpart at // http://androidxref.com/8.0.0_r4/xref/libcore/ojluni/src/main/java/java/util/UUID.java#162. diff --git a/internal/platform/uuid.h b/internal/platform/uuid.h index ad3d896d..230e2f29 100644 --- a/internal/platform/uuid.h +++ b/internal/platform/uuid.h @@ -17,6 +17,7 @@ #include #include +#include #include #include "absl/strings/string_view.h" @@ -32,6 +33,10 @@ class Uuid final { public: Uuid() = default; + // Constructs a UUID from the canonical string format as + // xxxxxABCD-xxxx-xxxx-xxxxxxxxxxxxxx + static std::optional FromString(absl::string_view data); + // Constructs a type 3 (name based) UUID based on the input string. explicit Uuid(absl::string_view data); // Constructs a new UUID using the specified most_sig_bits for the most diff --git a/internal/platform/uuid_test.cc b/internal/platform/uuid_test.cc index 909b68bf..136ef90e 100644 --- a/internal/platform/uuid_test.cc +++ b/internal/platform/uuid_test.cc @@ -14,11 +14,15 @@ #include "internal/platform/uuid.h" +#include +#include +#include #include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/strings/string_view.h" #include "internal/platform/crypto.h" #include "internal/platform/logging.h" @@ -131,5 +135,13 @@ TEST(UuidTest, OperatorGreaterThan) { EXPECT_TRUE(a < b); } +TEST(UuidTest, ConstructUuidFromString) { + std::optional a = + Uuid::FromString("12345678-1234-1234-1234-123456789012"); + + ASSERT_TRUE(a.has_value()); + EXPECT_EQ(std::string(*a), "12345678-1234-1234-1234-123456789012"); +} + } // namespace } // namespace nearby