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