xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/common/uuid_string_util.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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