xref: /aosp_15_r20/external/cronet/base/uuid.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/uuid.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
8*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include <ostream>
11*6777b538SAndroid Build Coastguard Worker #include <string_view>
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/hash/hash.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/types/pass_key.h"
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker namespace base {
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker namespace {
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker template <typename Char>
IsLowerHexDigit(Char c)25*6777b538SAndroid Build Coastguard Worker constexpr bool IsLowerHexDigit(Char c) {
26*6777b538SAndroid Build Coastguard Worker   return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
27*6777b538SAndroid Build Coastguard Worker }
28*6777b538SAndroid Build Coastguard Worker 
IsHyphenPosition(size_t i)29*6777b538SAndroid Build Coastguard Worker constexpr bool IsHyphenPosition(size_t i) {
30*6777b538SAndroid Build Coastguard Worker   return i == 8 || i == 13 || i == 18 || i == 23;
31*6777b538SAndroid Build Coastguard Worker }
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker // Returns a canonical Uuid string given that `input` is validly formatted
34*6777b538SAndroid Build Coastguard Worker // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, such that x is a hexadecimal digit.
35*6777b538SAndroid Build Coastguard Worker // If `strict`, x must be a lower-case hexadecimal digit.
36*6777b538SAndroid Build Coastguard Worker template <typename StringPieceType>
GetCanonicalUuidInternal(StringPieceType input,bool strict)37*6777b538SAndroid Build Coastguard Worker std::string GetCanonicalUuidInternal(StringPieceType input, bool strict) {
38*6777b538SAndroid Build Coastguard Worker   using CharType = typename StringPieceType::value_type;
39*6777b538SAndroid Build Coastguard Worker 
40*6777b538SAndroid Build Coastguard Worker   constexpr size_t kUuidLength = 36;
41*6777b538SAndroid Build Coastguard Worker   if (input.length() != kUuidLength) {
42*6777b538SAndroid Build Coastguard Worker     return std::string();
43*6777b538SAndroid Build Coastguard Worker   }
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker   std::string lowercase_;
46*6777b538SAndroid Build Coastguard Worker   lowercase_.resize(kUuidLength);
47*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < input.length(); ++i) {
48*6777b538SAndroid Build Coastguard Worker     CharType current = input[i];
49*6777b538SAndroid Build Coastguard Worker     if (IsHyphenPosition(i)) {
50*6777b538SAndroid Build Coastguard Worker       if (current != '-') {
51*6777b538SAndroid Build Coastguard Worker         return std::string();
52*6777b538SAndroid Build Coastguard Worker       }
53*6777b538SAndroid Build Coastguard Worker       lowercase_[i] = '-';
54*6777b538SAndroid Build Coastguard Worker     } else {
55*6777b538SAndroid Build Coastguard Worker       if (strict ? !IsLowerHexDigit(current) : !IsHexDigit(current)) {
56*6777b538SAndroid Build Coastguard Worker         return std::string();
57*6777b538SAndroid Build Coastguard Worker       }
58*6777b538SAndroid Build Coastguard Worker       lowercase_[i] = static_cast<char>(ToLowerASCII(current));
59*6777b538SAndroid Build Coastguard Worker     }
60*6777b538SAndroid Build Coastguard Worker   }
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker   return lowercase_;
63*6777b538SAndroid Build Coastguard Worker }
64*6777b538SAndroid Build Coastguard Worker 
65*6777b538SAndroid Build Coastguard Worker }  // namespace
66*6777b538SAndroid Build Coastguard Worker 
67*6777b538SAndroid Build Coastguard Worker // static
GenerateRandomV4()68*6777b538SAndroid Build Coastguard Worker Uuid Uuid::GenerateRandomV4() {
69*6777b538SAndroid Build Coastguard Worker   uint8_t sixteen_bytes[kGuidV4InputLength];
70*6777b538SAndroid Build Coastguard Worker   // Use base::RandBytes instead of crypto::RandBytes, because crypto calls the
71*6777b538SAndroid Build Coastguard Worker   // base version directly, and to prevent the dependency from base/ to crypto/.
72*6777b538SAndroid Build Coastguard Worker   RandBytes(sixteen_bytes);
73*6777b538SAndroid Build Coastguard Worker   return FormatRandomDataAsV4Impl(sixteen_bytes);
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker // static
FormatRandomDataAsV4(base::span<const uint8_t,16> input,base::PassKey<content::FileSystemAccessManagerImpl>)77*6777b538SAndroid Build Coastguard Worker Uuid Uuid::FormatRandomDataAsV4(
78*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t, 16> input,
79*6777b538SAndroid Build Coastguard Worker     base::PassKey<content::FileSystemAccessManagerImpl> /*pass_key*/) {
80*6777b538SAndroid Build Coastguard Worker   return FormatRandomDataAsV4Impl(input);
81*6777b538SAndroid Build Coastguard Worker }
82*6777b538SAndroid Build Coastguard Worker 
83*6777b538SAndroid Build Coastguard Worker // static
FormatRandomDataAsV4ForTesting(base::span<const uint8_t,16> input)84*6777b538SAndroid Build Coastguard Worker Uuid Uuid::FormatRandomDataAsV4ForTesting(base::span<const uint8_t, 16> input) {
85*6777b538SAndroid Build Coastguard Worker   return FormatRandomDataAsV4Impl(input);
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker // static
FormatRandomDataAsV4Impl(base::span<const uint8_t,16> input)89*6777b538SAndroid Build Coastguard Worker Uuid Uuid::FormatRandomDataAsV4Impl(base::span<const uint8_t, 16> input) {
90*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(input.size_bytes(), kGuidV4InputLength);
91*6777b538SAndroid Build Coastguard Worker 
92*6777b538SAndroid Build Coastguard Worker   uint64_t sixteen_bytes[2];
93*6777b538SAndroid Build Coastguard Worker   memcpy(&sixteen_bytes, input.data(), sizeof(sixteen_bytes));
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker   // Set the Uuid to version 4 as described in RFC 4122, section 4.4.
96*6777b538SAndroid Build Coastguard Worker   // The format of Uuid version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
97*6777b538SAndroid Build Coastguard Worker   // where y is one of [8, 9, a, b].
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker   // Clear the version bits and set the version to 4:
100*6777b538SAndroid Build Coastguard Worker   sixteen_bytes[0] &= 0xffffffff'ffff0fffULL;
101*6777b538SAndroid Build Coastguard Worker   sixteen_bytes[0] |= 0x00000000'00004000ULL;
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker   // Set the two most significant bits (bits 6 and 7) of the
104*6777b538SAndroid Build Coastguard Worker   // clock_seq_hi_and_reserved to zero and one, respectively:
105*6777b538SAndroid Build Coastguard Worker   sixteen_bytes[1] &= 0x3fffffff'ffffffffULL;
106*6777b538SAndroid Build Coastguard Worker   sixteen_bytes[1] |= 0x80000000'00000000ULL;
107*6777b538SAndroid Build Coastguard Worker 
108*6777b538SAndroid Build Coastguard Worker   Uuid uuid;
109*6777b538SAndroid Build Coastguard Worker   uuid.lowercase_ =
110*6777b538SAndroid Build Coastguard Worker       StringPrintf("%08x-%04x-%04x-%04x-%012llx",
111*6777b538SAndroid Build Coastguard Worker                    static_cast<uint32_t>(sixteen_bytes[0] >> 32),
112*6777b538SAndroid Build Coastguard Worker                    static_cast<uint32_t>((sixteen_bytes[0] >> 16) & 0x0000ffff),
113*6777b538SAndroid Build Coastguard Worker                    static_cast<uint32_t>(sixteen_bytes[0] & 0x0000ffff),
114*6777b538SAndroid Build Coastguard Worker                    static_cast<uint32_t>(sixteen_bytes[1] >> 48),
115*6777b538SAndroid Build Coastguard Worker                    sixteen_bytes[1] & 0x0000ffff'ffffffffULL);
116*6777b538SAndroid Build Coastguard Worker   return uuid;
117*6777b538SAndroid Build Coastguard Worker }
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker // static
ParseCaseInsensitive(std::string_view input)120*6777b538SAndroid Build Coastguard Worker Uuid Uuid::ParseCaseInsensitive(std::string_view input) {
121*6777b538SAndroid Build Coastguard Worker   Uuid uuid;
122*6777b538SAndroid Build Coastguard Worker   uuid.lowercase_ = GetCanonicalUuidInternal(input, /*strict=*/false);
123*6777b538SAndroid Build Coastguard Worker   return uuid;
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker // static
ParseCaseInsensitive(std::u16string_view input)127*6777b538SAndroid Build Coastguard Worker Uuid Uuid::ParseCaseInsensitive(std::u16string_view input) {
128*6777b538SAndroid Build Coastguard Worker   Uuid uuid;
129*6777b538SAndroid Build Coastguard Worker   uuid.lowercase_ = GetCanonicalUuidInternal(input, /*strict=*/false);
130*6777b538SAndroid Build Coastguard Worker   return uuid;
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker // static
ParseLowercase(std::string_view input)134*6777b538SAndroid Build Coastguard Worker Uuid Uuid::ParseLowercase(std::string_view input) {
135*6777b538SAndroid Build Coastguard Worker   Uuid uuid;
136*6777b538SAndroid Build Coastguard Worker   uuid.lowercase_ = GetCanonicalUuidInternal(input, /*strict=*/true);
137*6777b538SAndroid Build Coastguard Worker   return uuid;
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker // static
ParseLowercase(std::u16string_view input)141*6777b538SAndroid Build Coastguard Worker Uuid Uuid::ParseLowercase(std::u16string_view input) {
142*6777b538SAndroid Build Coastguard Worker   Uuid uuid;
143*6777b538SAndroid Build Coastguard Worker   uuid.lowercase_ = GetCanonicalUuidInternal(input, /*strict=*/true);
144*6777b538SAndroid Build Coastguard Worker   return uuid;
145*6777b538SAndroid Build Coastguard Worker }
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker Uuid::Uuid() = default;
148*6777b538SAndroid Build Coastguard Worker 
149*6777b538SAndroid Build Coastguard Worker Uuid::Uuid(const Uuid& other) = default;
150*6777b538SAndroid Build Coastguard Worker 
151*6777b538SAndroid Build Coastguard Worker Uuid& Uuid::operator=(const Uuid& other) = default;
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker Uuid::Uuid(Uuid&& other) = default;
154*6777b538SAndroid Build Coastguard Worker 
155*6777b538SAndroid Build Coastguard Worker Uuid& Uuid::operator=(Uuid&& other) = default;
156*6777b538SAndroid Build Coastguard Worker 
AsLowercaseString() const157*6777b538SAndroid Build Coastguard Worker const std::string& Uuid::AsLowercaseString() const {
158*6777b538SAndroid Build Coastguard Worker   return lowercase_;
159*6777b538SAndroid Build Coastguard Worker }
160*6777b538SAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const Uuid & uuid)161*6777b538SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const Uuid& uuid) {
162*6777b538SAndroid Build Coastguard Worker   return out << uuid.AsLowercaseString();
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker 
operator ()(const Uuid & uuid) const165*6777b538SAndroid Build Coastguard Worker size_t UuidHash::operator()(const Uuid& uuid) const {
166*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1026195): Avoid converting to string to take the hash when
167*6777b538SAndroid Build Coastguard Worker   // the internal type is migrated to a non-string type.
168*6777b538SAndroid Build Coastguard Worker   return FastHash(uuid.AsLowercaseString());
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker }  // namespace base
172