1
2 // Copyright 2024 The Pigweed Authors
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 // use this file except in compliance with the License. You may obtain a copy of
6 // the License at
7 //
8 // https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 // License for the specific language governing permissions and limitations under
14 // the License.
15
16 #include <cinttypes>
17
18 #include "pw_bluetooth_sapphire/internal/host/common/uint128.h"
19 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
20
21 #ifndef SCNx8
22 #define SCNx8 "hhx"
23 #endif
24
25 namespace bt {
26 namespace {
27
28 // Format string that can be passed to sscanf. This allows sscanf to convert
29 // each octet into a uint8_t.
30 constexpr char kScanUuidFormatString[] =
31 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8
32 "-"
33 "%2" SCNx8 "%2" SCNx8
34 "-"
35 "%2" SCNx8 "%2" SCNx8
36 "-"
37 "%2" SCNx8 "%2" SCNx8
38 "-"
39 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8;
40
41 // Parses the contents of a |uuid_string| and returns the result in |out_bytes|.
42 // Returns false if |uuid_string| does not represent a valid UUID.
43 // TODO(armansito): After having used UUID in camel-case words all over the
44 // place, I've decided that it sucks. I'm explicitly naming this using the
45 // "Uuid" style as a reminder to fix style elsewhere.
ParseUuidString(const std::string & uuid_string,UInt128 * out_bytes)46 bool ParseUuidString(const std::string& uuid_string, UInt128* out_bytes) {
47 PW_DCHECK(out_bytes);
48
49 if (uuid_string.length() == 4) {
50 // Possibly a 16-bit short UUID, parse it in context of the Base UUID.
51 return ParseUuidString(
52 "0000" + uuid_string + "-0000-1000-8000-00805F9B34FB", out_bytes);
53 }
54
55 // This is a 36 character string, including 4 "-" characters and two
56 // characters for each of the 16-octets that form the 128-bit UUID.
57 if (uuid_string.length() != 36)
58 return false;
59
60 int result = std::sscanf(uuid_string.c_str(),
61 kScanUuidFormatString,
62 out_bytes->data() + 15,
63 out_bytes->data() + 14,
64 out_bytes->data() + 13,
65 out_bytes->data() + 12,
66 out_bytes->data() + 11,
67 out_bytes->data() + 10,
68 out_bytes->data() + 9,
69 out_bytes->data() + 8,
70 out_bytes->data() + 7,
71 out_bytes->data() + 6,
72 out_bytes->data() + 5,
73 out_bytes->data() + 4,
74 out_bytes->data() + 3,
75 out_bytes->data() + 2,
76 out_bytes->data() + 1,
77 out_bytes->data());
78
79 return (result > 0) && (static_cast<size_t>(result) == out_bytes->size());
80 }
81
82 } // namespace
83
IsStringValidUuid(const std::string & uuid_string)84 bool IsStringValidUuid(const std::string& uuid_string) {
85 UInt128 bytes;
86 return ParseUuidString(uuid_string, &bytes);
87 }
88
StringToUuid(const std::string & uuid_string,UUID * out_uuid)89 bool StringToUuid(const std::string& uuid_string, UUID* out_uuid) {
90 PW_DCHECK(out_uuid);
91
92 UInt128 bytes;
93 if (!ParseUuidString(uuid_string, &bytes)) {
94 return false;
95 }
96
97 *out_uuid = UUID(bytes);
98 return true;
99 }
100
101 } // namespace bt
102