1 /******************************************************************************
2  *
3  *  Copyright (C) 2017 The Android Open Source Project
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #include "uuid.h"
20 
21 #include <base/rand_util.h>
22 #include <base/strings/stringprintf.h>
23 #include <string.h>
24 #include <algorithm>
25 
26 namespace bluetooth {
27 
28 static_assert(sizeof(Uuid) == 16, "Uuid must be 16 bytes long!");
29 
30 using UUID128Bit = Uuid::UUID128Bit;
31 
32 const Uuid Uuid::kEmpty = Uuid::From128BitBE(UUID128Bit{{0x00}});
33 
34 namespace {
35 constexpr Uuid kBase = Uuid::From128BitBE(
36     UUID128Bit{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
37                 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}});
38 }  // namespace
39 
GetShortestRepresentationSize() const40 size_t Uuid::GetShortestRepresentationSize() const {
41   if (memcmp(uu.data() + kNumBytes32, kBase.uu.data() + kNumBytes32,
42              kNumBytes128 - kNumBytes32) != 0) {
43     return kNumBytes128;
44   }
45 
46   if (uu[0] == 0 && uu[1] == 0) return kNumBytes16;
47 
48   return kNumBytes32;
49 }
50 
Is16Bit() const51 bool Uuid::Is16Bit() const {
52   return GetShortestRepresentationSize() == kNumBytes16;
53 }
54 
As16Bit() const55 uint16_t Uuid::As16Bit() const { return (((uint16_t)uu[2]) << 8) + uu[3]; }
56 
As32Bit() const57 uint32_t Uuid::As32Bit() const {
58   return (((uint32_t)uu[0]) << 24) + (((uint32_t)uu[1]) << 16) +
59          (((uint32_t)uu[2]) << 8) + uu[3];
60 }
61 
FromString(const std::string & uuid,bool * is_valid)62 Uuid Uuid::FromString(const std::string& uuid, bool* is_valid) {
63   if (is_valid) *is_valid = false;
64   Uuid ret = kBase;
65 
66   if (uuid.empty()) return ret;
67 
68   uint8_t* p = ret.uu.data();
69   if (uuid.size() == kString128BitLen) {
70     if (uuid[8] != '-' || uuid[13] != '-' || uuid[18] != '-' ||
71         uuid[23] != '-') {
72       return ret;
73     }
74 
75     int c;
76     int rc =
77         sscanf(uuid.c_str(),
78                "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx"
79                "-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%n",
80                &p[0], &p[1], &p[2], &p[3], &p[4], &p[5], &p[6], &p[7], &p[8],
81                &p[9], &p[10], &p[11], &p[12], &p[13], &p[14], &p[15], &c);
82     if (rc != 16) return ret;
83     if (c != kString128BitLen) return ret;
84 
85     if (is_valid) *is_valid = true;
86   } else if (uuid.size() == 8) {
87     int c;
88     int rc = sscanf(uuid.c_str(), "%02hhx%02hhx%02hhx%02hhx%n", &p[0], &p[1],
89                     &p[2], &p[3], &c);
90     if (rc != 4) return ret;
91     if (c != 8) return ret;
92 
93     if (is_valid) *is_valid = true;
94   } else if (uuid.size() == 4) {
95     int c;
96     int rc = sscanf(uuid.c_str(), "%02hhx%02hhx%n", &p[2], &p[3], &c);
97     if (rc != 2) return ret;
98     if (c != 4) return ret;
99 
100     if (is_valid) *is_valid = true;
101   }
102 
103   return ret;
104 }
105 
From16Bit(uint16_t uuid16)106 Uuid Uuid::From16Bit(uint16_t uuid16) {
107   Uuid u = kBase;
108 
109   u.uu[2] = (uint8_t)((0xFF00 & uuid16) >> 8);
110   u.uu[3] = (uint8_t)(0x00FF & uuid16);
111   return u;
112 }
113 
From32Bit(uint32_t uuid32)114 Uuid Uuid::From32Bit(uint32_t uuid32) {
115   Uuid u = kBase;
116 
117   u.uu[0] = (uint8_t)((0xFF000000 & uuid32) >> 24);
118   u.uu[1] = (uint8_t)((0x00FF0000 & uuid32) >> 16);
119   u.uu[2] = (uint8_t)((0x0000FF00 & uuid32) >> 8);
120   u.uu[3] = (uint8_t)(0x000000FF & uuid32);
121   return u;
122 }
123 
From128BitBE(const uint8_t * uuid)124 Uuid Uuid::From128BitBE(const uint8_t* uuid) {
125   UUID128Bit tmp;
126   memcpy(tmp.data(), uuid, kNumBytes128);
127   return From128BitBE(tmp);
128 }
129 
From128BitLE(const UUID128Bit & uuid)130 Uuid Uuid::From128BitLE(const UUID128Bit& uuid) {
131   Uuid u;
132   std::reverse_copy(uuid.data(), uuid.data() + kNumBytes128, u.uu.begin());
133   return u;
134 }
135 
From128BitLE(const uint8_t * uuid)136 Uuid Uuid::From128BitLE(const uint8_t* uuid) {
137   UUID128Bit tmp;
138   memcpy(tmp.data(), uuid, kNumBytes128);
139   return From128BitLE(tmp);
140 }
141 
To128BitLE() const142 const UUID128Bit Uuid::To128BitLE() const {
143   UUID128Bit le;
144   std::reverse_copy(uu.data(), uu.data() + kNumBytes128, le.begin());
145   return le;
146 }
147 
To128BitBE() const148 const UUID128Bit& Uuid::To128BitBE() const { return uu; }
149 
GetRandom()150 Uuid Uuid::GetRandom() {
151   Uuid uuid;
152   base::RandBytes(uuid.uu.data(), uuid.uu.size());
153   return uuid;
154 }
155 
IsEmpty() const156 bool Uuid::IsEmpty() const { return *this == kEmpty; }
157 
UpdateUuid(const Uuid & uuid)158 void Uuid::UpdateUuid(const Uuid& uuid) {
159   uu = uuid.uu;
160 }
161 
operator <(const Uuid & rhs) const162 bool Uuid::operator<(const Uuid& rhs) const {
163   return std::lexicographical_compare(uu.begin(), uu.end(), rhs.uu.begin(),
164                                       rhs.uu.end());
165 }
166 
operator ==(const Uuid & rhs) const167 bool Uuid::operator==(const Uuid& rhs) const { return uu == rhs.uu; }
168 
operator !=(const Uuid & rhs) const169 bool Uuid::operator!=(const Uuid& rhs) const { return uu != rhs.uu; }
170 
ToString() const171 std::string Uuid::ToString() const {
172   return base::StringPrintf(
173       "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
174       uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7], uu[8], uu[9],
175       uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
176 }
177 }  // namespace bluetooth
178