• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <pw_assert/check.h>
17 
18 #include <cinttypes>
19 
20 #include "pw_bluetooth_sapphire/internal/host/common/uint128.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
22 
23 #ifndef SCNx8
24 #define SCNx8 "hhx"
25 #endif
26 
27 namespace bt {
28 namespace {
29 
30 // Format string that can be passed to sscanf. This allows sscanf to convert
31 // each octet into a uint8_t.
32 constexpr char kScanUuidFormatString[] =
33     "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8
34     "-"
35     "%2" SCNx8 "%2" SCNx8
36     "-"
37     "%2" SCNx8 "%2" SCNx8
38     "-"
39     "%2" SCNx8 "%2" SCNx8
40     "-"
41     "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8;
42 
43 // Parses the contents of a |uuid_string| and returns the result in |out_bytes|.
44 // Returns false if |uuid_string| does not represent a valid UUID.
45 // TODO(armansito): After having used UUID in camel-case words all over the
46 // place, I've decided that it sucks. I'm explicitly naming this using the
47 // "Uuid" style as a reminder to fix style elsewhere.
ParseUuidString(const std::string & uuid_string,UInt128 * out_bytes)48 bool ParseUuidString(const std::string& uuid_string, UInt128* out_bytes) {
49   PW_DCHECK(out_bytes);
50 
51   if (uuid_string.length() == 4) {
52     // Possibly a 16-bit short UUID, parse it in context of the Base UUID.
53     return ParseUuidString(
54         "0000" + uuid_string + "-0000-1000-8000-00805F9B34FB", out_bytes);
55   }
56 
57   // This is a 36 character string, including 4 "-" characters and two
58   // characters for each of the 16-octets that form the 128-bit UUID.
59   if (uuid_string.length() != 36)
60     return false;
61 
62   int result = std::sscanf(uuid_string.c_str(),
63                            kScanUuidFormatString,
64                            out_bytes->data() + 15,
65                            out_bytes->data() + 14,
66                            out_bytes->data() + 13,
67                            out_bytes->data() + 12,
68                            out_bytes->data() + 11,
69                            out_bytes->data() + 10,
70                            out_bytes->data() + 9,
71                            out_bytes->data() + 8,
72                            out_bytes->data() + 7,
73                            out_bytes->data() + 6,
74                            out_bytes->data() + 5,
75                            out_bytes->data() + 4,
76                            out_bytes->data() + 3,
77                            out_bytes->data() + 2,
78                            out_bytes->data() + 1,
79                            out_bytes->data());
80 
81   return (result > 0) && (static_cast<size_t>(result) == out_bytes->size());
82 }
83 
84 }  // namespace
85 
IsStringValidUuid(const std::string & uuid_string)86 bool IsStringValidUuid(const std::string& uuid_string) {
87   UInt128 bytes;
88   return ParseUuidString(uuid_string, &bytes);
89 }
90 
StringToUuid(const std::string & uuid_string,UUID * out_uuid)91 bool StringToUuid(const std::string& uuid_string, UUID* out_uuid) {
92   PW_DCHECK(out_uuid);
93 
94   UInt128 bytes;
95   if (!ParseUuidString(uuid_string, &bytes)) {
96     return false;
97   }
98 
99   *out_uuid = UUID(bytes);
100   return true;
101 }
102 
103 }  // namespace bt
104