1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #if !defined(__STDC_FORMAT_MACROS)
16 #define __STDC_FORMAT_MACROS
17 #endif
18 
19 #include "util/misc/uuid.h"
20 
21 #include <inttypes.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include <type_traits>
27 
28 #include "base/rand_util.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "base/sys_byteorder.h"
32 
33 #if defined(OS_APPLE)
34 #include <uuid/uuid.h>
35 #endif  // OS_APPLE
36 
37 namespace crashpad {
38 
39 static_assert(sizeof(UUID) == 16, "UUID must be 16 bytes");
40 static_assert(std::is_pod<UUID>::value, "UUID must be POD");
41 
operator ==(const UUID & that) const42 bool UUID::operator==(const UUID& that) const {
43   return memcmp(this, &that, sizeof(*this)) == 0;
44 }
45 
InitializeToZero()46 void UUID::InitializeToZero() {
47   memset(this, 0, sizeof(*this));
48 }
49 
InitializeFromBytes(const uint8_t * bytes)50 void UUID::InitializeFromBytes(const uint8_t* bytes) {
51   memcpy(this, bytes, sizeof(*this));
52   data_1 = base::NetToHost32(data_1);
53   data_2 = base::NetToHost16(data_2);
54   data_3 = base::NetToHost16(data_3);
55 }
56 
InitializeFromString(const base::StringPiece & string)57 bool UUID::InitializeFromString(const base::StringPiece& string) {
58   if (string.length() != 36)
59     return false;
60 
61   UUID temp;
62   static constexpr char kScanFormat[] =
63       "%08" SCNx32 "-%04" SCNx16 "-%04" SCNx16
64       "-%02" SCNx8 "%02" SCNx8
65       "-%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8;
66   int rv = sscanf(string.data(),
67                   kScanFormat,
68                   &temp.data_1,
69                   &temp.data_2,
70                   &temp.data_3,
71                   &temp.data_4[0],
72                   &temp.data_4[1],
73                   &temp.data_5[0],
74                   &temp.data_5[1],
75                   &temp.data_5[2],
76                   &temp.data_5[3],
77                   &temp.data_5[4],
78                   &temp.data_5[5]);
79   if (rv != 11)
80     return false;
81 
82   *this = temp;
83   return true;
84 }
85 
86 #if defined(OS_WIN)
InitializeFromString(const base::WStringPiece & string)87 bool UUID::InitializeFromString(const base::WStringPiece& string) {
88   return InitializeFromString(WideToUTF8(string));
89 }
90 #endif
91 
InitializeWithNew()92 bool UUID::InitializeWithNew() {
93 #if defined(OS_APPLE)
94   uuid_t uuid;
95   uuid_generate(uuid);
96   InitializeFromBytes(uuid);
97   return true;
98 #elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
99     defined(OS_ANDROID) || defined(OS_FUCHSIA)
100   // Linux, Android, and Fuchsia do not provide a UUID generator in a
101   // widely-available system library. On Linux and Android, uuid_generate()
102   // from libuuid is not available everywhere.
103   // On Windows, do not use UuidCreate() to avoid a dependency on rpcrt4, so
104   // that this function is usable early in DllMain().
105   base::RandBytes(this, sizeof(*this));
106 
107   // Set six bits per RFC 4122 §4.4 to identify this as a pseudo-random UUID.
108   data_3 = (4 << 12) | (data_3 & 0x0fff);  // §4.1.3
109   data_4[0] = 0x80 | (data_4[0] & 0x3f);  // §4.1.1
110 
111   return true;
112 #else
113 #error Port.
114 #endif  // OS_APPLE
115 }
116 
117 #if defined(OS_WIN)
InitializeFromSystemUUID(const::UUID * system_uuid)118 void UUID::InitializeFromSystemUUID(const ::UUID* system_uuid) {
119   static_assert(sizeof(::UUID) == sizeof(UUID),
120                 "unexpected system uuid size");
121   static_assert(offsetof(::UUID, Data1) == offsetof(UUID, data_1),
122                 "unexpected system uuid layout");
123   memcpy(this, system_uuid, sizeof(*this));
124 }
125 #endif  // OS_WIN
126 
ToString() const127 std::string UUID::ToString() const {
128   return base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
129                             data_1,
130                             data_2,
131                             data_3,
132                             data_4[0],
133                             data_4[1],
134                             data_5[0],
135                             data_5[1],
136                             data_5[2],
137                             data_5[3],
138                             data_5[4],
139                             data_5[5]);
140 }
141 
142 #if defined(OS_WIN)
ToWString() const143 std::wstring UUID::ToWString() const {
144   return base::UTF8ToWide(ToString());
145 }
146 #endif  // OS_WIN
147 
148 }  // namespace crashpad
149