Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
uuid.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#include <jau/debug.hpp>
27
28#include <jau/uuid.hpp>
29
30
31using namespace jau;
32
33// BASE_UUID '00000000-0000-1000-8000-00805F9B34FB'
34static uint8_t bt_base_uuid_be[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
35 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
37
38std::string uuid_t::getTypeSizeString(const TypeSize v) noexcept {
39 switch( static_cast<TypeSize>(v) ) {
40 case TypeSize::UUID16_SZ: return "uuid16";
41 case TypeSize::UUID32_SZ: return "uuid32";
42 case TypeSize::UUID128_SZ: return "uuid128";
43 default: return "uuid_t unsupported size "+std::to_string(number(v));
44 }
45}
46
47uuid_t::TypeSize uuid_t::toTypeSize(const jau::nsize_t size) {
48 switch( static_cast<TypeSize>(size) ) {
52 }
53 throw jau::IllegalArgumentException("Given size "+std::to_string(size)+", not matching uuid16_t, uuid32_t or uuid128_t", E_FILE_LINE);
54}
55
56std::unique_ptr<uuid_t> uuid_t::create(TypeSize t, uint8_t const * const buffer, lb_endian_t const le_or_be) {
57 if( TypeSize::UUID16_SZ == t ) {
58 return std::make_unique<uuid16_t>(buffer, le_or_be);
59 } else if( TypeSize::UUID32_SZ == t ) {
60 return std::make_unique<uuid32_t>(buffer, le_or_be);
61 } else if( TypeSize::UUID128_SZ == t ) {
62 return std::make_unique<uuid128_t>(buffer, le_or_be);
63 }
64 throw jau::IllegalArgumentException("Unknown Type "+std::to_string(static_cast<jau::nsize_t>(t)), E_FILE_LINE);
65}
66std::unique_ptr<uuid_t> uuid_t::create(const std::string& str) {
67 const size_t len = str.length();
68 switch( len ) {
69 case 4: // 16
70 return std::make_unique<uuid16_t>(str);
71 case 8: // 32
72 return std::make_unique<uuid32_t>(str);
73 case 36: // 128
74 return std::make_unique<uuid128_t>(str);
75 default: {
76 std::string msg("UUID string not of length 4, 8 or 36 but ");
77 msg.append(std::to_string(str.length()));
78 msg.append(": "+str);
80 }
81 }
82}
83
84std::unique_ptr<uuid_t> uuid_t::clone() const noexcept {
85 switch(type) {
86 case TypeSize::UUID16_SZ: return std::make_unique<uuid16_t>( *( static_cast<const uuid16_t*>(this) ) );
87 case TypeSize::UUID32_SZ: return std::make_unique<uuid32_t>( *( static_cast<const uuid32_t*>(this) ) );
88 case TypeSize::UUID128_SZ: return std::make_unique<uuid128_t>( *( static_cast<const uuid128_t*>(this) ) );
89 }
90 ABORT("Unknown Type %d", static_cast<jau::nsize_t>(type));
91 abort(); // never reached
92}
93
94bool uuid_t::operator==(uuid_t const &o) const noexcept {
95 if( this == &o ) {
96 return true;
97 }
98 if( type != o.getTypeSize() ) {
99 return false;
100 }
101 switch( static_cast<TypeSize>(type) ) {
102 case TypeSize::UUID16_SZ: return static_cast<uuid16_t const *>(this)->value == static_cast<uuid16_t const *>(&o)->value;
103 case TypeSize::UUID32_SZ: return static_cast<uuid32_t const *>(this)->value == static_cast<uuid32_t const *>(&o)->value;
104 case TypeSize::UUID128_SZ: return static_cast<uuid128_t const *>(this)->value == static_cast<uuid128_t const *>(&o)->value;
105 }
106 return false; // dead code
107}
108
109bool uuid_t::equivalent(uuid_t const &o) const noexcept {
110 if( this == &o ) {
111 return true;
112 }
113 if( getTypeSize() == o.getTypeSize() ) {
114 return *this == o;
115 }
116 return toUUID128() == o.toUUID128();
117}
118
119uuid128_t uuid_t::toUUID128(uuid128_t const & base_uuid, jau::nsize_t const uuid32_le_octet_index) const noexcept {
120 switch(type) {
121 case TypeSize::UUID16_SZ: return uuid128_t( *( static_cast<const uuid16_t*>(this) ), base_uuid, uuid32_le_octet_index);
122 case TypeSize::UUID32_SZ: return uuid128_t( *( static_cast<const uuid32_t*>(this) ), base_uuid, uuid32_le_octet_index);
123 case TypeSize::UUID128_SZ: return uuid128_t( *( static_cast<const uuid128_t*>(this) ) );
124 }
125 ABORT("Unknown Type %d", static_cast<jau::nsize_t>(type));
126 abort(); // never reached
127}
128
129uuid128_t::uuid128_t(uuid16_t const & uuid16, uuid128_t const & base_uuid, jau::nsize_t const uuid16_le_octet_index) noexcept
130: uuid_t(TypeSize::UUID128_SZ), value(merge_uint128(uuid16.value, base_uuid.value, uuid16_le_octet_index)) {}
131
132uuid128_t::uuid128_t(uuid32_t const & uuid32, uuid128_t const & base_uuid, jau::nsize_t const uuid32_le_octet_index) noexcept
133: uuid_t(TypeSize::UUID128_SZ), value(merge_uint128(uuid32.value, base_uuid.value, uuid32_le_octet_index)) {}
134
135std::string uuid16_t::toString() const noexcept {
136 const jau::nsize_t length = 4;
137 std::string str;
138 str.reserve(length+1); // including EOS for snprintf
139 str.resize(length);
140
141 const jau::nsize_t count = snprintf(&str[0], str.capacity(), "%.4x", value);
142 if( length != count ) {
143 ABORT("UUID16 string not of length %d but %d", length, count);
144 }
145 return str;
146}
147
148std::string uuid16_t::toUUID128String(uuid128_t const & base_uuid, jau::nsize_t const le_octet_index) const noexcept
149{
150 uuid128_t u128(*this, base_uuid, le_octet_index);
151 return u128.toString();
152}
153
154std::string uuid32_t::toString() const noexcept {
155 const jau::nsize_t length = 8;
156 std::string str;
157 str.reserve(length+1); // including EOS for snprintf
158 str.resize(length);
159
160 const jau::nsize_t count = snprintf(&str[0], str.capacity(), "%.8x", value);
161 if( length != count ) {
162 ABORT("UUID32 string not of length %d but %d", length, count);
163 }
164 return str;
165}
166
167std::string uuid32_t::toUUID128String(uuid128_t const & base_uuid, jau::nsize_t const le_octet_index) const noexcept
168{
169 uuid128_t u128(*this, base_uuid, le_octet_index);
170 return u128.toString();
171}
172
173// one static_assert is sufficient for whole compilation unit
174static_assert( is_defined_endian(endian_t::native) );
175static_assert( is_little_or_big_endian() );
176
177std::string uuid128_t::toString() const noexcept {
178 // 87654321-0000-1000-8000-00805F9B34FB
179 // 0 1 2 3 4 5
180 // LE: low-mem - FB349B5F0800-0080-0010-0000-12345678 - high-mem
181 // 5 4 3 2 1 0
182 //
183 // BE: low-mem - 87654321-0000-1000-8000-00805F9B34FB - high-mem
184 // 0 1 2 3 4 5
185 //
186 const jau::nsize_t length = 36;
187 std::string str;
188 str.reserve(length+1); // including EOS for snprintf
189 str.resize(length);
190 uint32_t part0, part4;
191 uint16_t part1, part2, part3, part5;
192
193 // snprintf uses host data type, in which values are stored,
194 // hence no endian conversion
195 if( is_big_endian() ) {
196 part0 = jau::get_uint32(value.data+ 0);
197 part1 = jau::get_uint16(value.data+ 4);
198 part2 = jau::get_uint16(value.data+ 6);
199 part3 = jau::get_uint16(value.data+ 8);
200 part4 = jau::get_uint32(value.data+ 10);
201 part5 = jau::get_uint16(value.data+ 14);
202 } else {
203 part5 = jau::get_uint16(value.data+ 0);
204 part4 = jau::get_uint32(value.data+ 2);
205 part3 = jau::get_uint16(value.data+ 6);
206 part2 = jau::get_uint16(value.data+ 8);
207 part1 = jau::get_uint16(value.data+ 10);
208 part0 = jau::get_uint32(value.data+ 12);
209 }
210 const jau::nsize_t count = snprintf(&str[0], str.capacity(), "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
211 part0, part1, part2, part3, part4, part5);
212 if( length != count ) {
213 ABORT("UUID128 string not of length %d but %d", length, count);
214 }
215 return str;
216}
217
218uuid16_t::uuid16_t(const std::string& str)
219: uuid_t(TypeSize::UUID16_SZ), value(0)
220{
221 uint16_t part0;
222
223 if( 4 != str.length() ) {
224 std::string msg("UUID16 string not of length 4 but ");
225 msg.append(std::to_string(str.length()));
226 msg.append(": "+str);
228 }
229 if ( sscanf(str.c_str(), "%04hx", &part0) != 1 ) {
230 std::string msg("UUID16 string not in format '0000' but "+str);
232 }
233 // sscanf provided host data type, in which we store the values,
234 // hence no endian conversion
235 value = part0;
236}
237
238uuid32_t::uuid32_t(const std::string& str)
239: uuid_t(TypeSize::UUID32_SZ)
240{
241 uint32_t part0;
242
243 if( 8 != str.length() ) {
244 std::string msg("UUID32 string not of length 8 but ");
245 msg.append(std::to_string(str.length()));
246 msg.append(": "+str);
248 }
249 // if ( sscanf(str.c_str(), "%08x-%04hx-%04hx-%04hx-%08x%04hx",
250 if ( sscanf(str.c_str(), "%08x", &part0) != 1 ) {
251 std::string msg("UUID32 string not in format '00000000' but "+str);
253 }
254 // sscanf provided host data type, in which we store the values,
255 // hence no endian conversion
256 value = part0;
257}
258
259uuid128_t::uuid128_t(const std::string& str)
260: uuid_t(TypeSize::UUID128_SZ)
261{
262 uint32_t part0, part4;
263 uint16_t part1, part2, part3, part5;
264
265 if( 36 != str.length() ) {
266 std::string msg("UUID128 string not of length 36 but ");
267 msg.append(std::to_string(str.length()));
268 msg.append(": "+str);
270 }
271 if ( sscanf(str.c_str(), "%08x-%04hx-%04hx-%04hx-%08x%04hx",
272 &part0, &part1, &part2, &part3, &part4, &part5) != 6 )
273 {
274 std::string msg("UUID128 string not in format '00000000-0000-1000-8000-00805F9B34FB' but "+str);
276 }
277
278 // sscanf provided host data type, in which we store the values,
279 // hence no endian conversion
280 if( is_big_endian() ) {
281 jau::put_uint32(value.data + 0, part0);
282 jau::put_uint16(value.data + 4, part1);
283 jau::put_uint16(value.data + 6, part2);
284 jau::put_uint16(value.data + 8, part3);
285 jau::put_uint32(value.data + 10, part4);
286 jau::put_uint16(value.data + 14, part5);
287 } else {
288 jau::put_uint16(value.data + 0, part5);
289 jau::put_uint32(value.data + 2, part4);
290 jau::put_uint16(value.data + 6, part3);
291 jau::put_uint16(value.data + 8, part2);
292 jau::put_uint16(value.data + 10, part1);
293 jau::put_uint32(value.data + 12, part0);
294 }
295}
296
#define E_FILE_LINE
std::string toString() const noexcept override
Returns the string representation in BE network order, i.e.
Definition: uuid.cpp:177
uuid128_t() noexcept
Definition: uuid.hpp:209
jau::uint128dp_t value
Definition: uuid.hpp:207
uint16_t value
Definition: uuid.hpp:153
std::string toString() const noexcept override
Returns the string representation in BE network order, i.e.
Definition: uuid.cpp:135
std::string toUUID128String(uuid128_t const &base_uuid=BT_BASE_UUID, jau::nsize_t const le_octet_index=12) const noexcept override
Returns the uuid128_t string representation in BE network order, i.e.
Definition: uuid.cpp:148
uuid16_t(uint16_t const v) noexcept
Definition: uuid.hpp:155
std::string toString() const noexcept override
Returns the string representation in BE network order, i.e.
Definition: uuid.cpp:154
std::string toUUID128String(uuid128_t const &base_uuid=BT_BASE_UUID, jau::nsize_t const le_octet_index=12) const noexcept override
Returns the uuid128_t string representation in BE network order, i.e.
Definition: uuid.cpp:167
uint32_t value
Definition: uuid.hpp:180
uuid32_t(uint32_t const v) noexcept
Definition: uuid.hpp:182
uuid128_t toUUID128(uuid128_t const &base_uuid=BT_BASE_UUID, jau::nsize_t const uuid32_le_octet_index=12) const noexcept
Definition: uuid.cpp:119
TypeSize
Underlying integer value present octet count.
Definition: uuid.hpp:60
bool operator==(uuid_t const &o) const noexcept
Strict equality operator.
Definition: uuid.cpp:94
bool equivalent(uuid_t const &o) const noexcept
Relaxed equality operator.
Definition: uuid.cpp:109
static std::unique_ptr< uuid_t > create(TypeSize const t, uint8_t const *const buffer, lb_endian_t const le_or_be)
Definition: uuid.cpp:56
std::unique_ptr< uuid_t > clone() const noexcept
Definition: uuid.cpp:84
#define ABORT(...)
Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ file:line fu...
Definition: debug.hpp:101
constexpr bool is_big_endian() noexcept
Evaluates true if platform is running in big endian mode, i.e.
Definition: byte_util.hpp:316
constexpr bool is_defined_endian(const endian_t &v) noexcept
Evaluates true if the given endian is defined, i.e.
Definition: byte_util.hpp:275
constexpr uint16_t get_uint16(uint8_t const *buffer) noexcept
Returns a uint16_t value from the given byte address using packed_t to resolve a potential memory ali...
Definition: byte_util.hpp:661
constexpr bool is_little_or_big_endian() noexcept
Evaluates true if platform is running in little or big endian mode, i.e.
Definition: byte_util.hpp:324
constexpr uint32_t get_uint32(uint8_t const *buffer) noexcept
See get_uint16() for reference.
Definition: byte_util.hpp:699
constexpr void put_uint32(uint8_t *buffer, const uint32_t v) noexcept
See put_uint16() for reference.
Definition: byte_util.hpp:683
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
Definition: byte_util.hpp:227
constexpr void put_uint16(uint8_t *buffer, const uint16_t v) noexcept
Put the given uint16_t value into the given byte address using packed_t to resolve a potential memory...
Definition: byte_util.hpp:638
@ native
Identifier for native platform type, one of the above.
std::string to_string(const alphabet &v) noexcept
Definition: base_codec.hpp:97
constexpr uint32_t number(const iostate rhs) noexcept
Definition: byte_stream.hpp:72
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:53
uint128dp_t merge_uint128(uint16_t const uuid16, uint128dp_t const &base_uuid, nsize_t const uuid16_le_octet_index)
Merge the given 'uuid16' into a 'base_uuid' copy at the given little endian 'uuid16_le_octet_index' p...
uuid128_t BT_BASE_UUID
Bluetooth UUID https://www.bluetooth.com/specifications/assigned-numbers/service-discovery/
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
uint8_t data[16]
Definition: int_types.hpp:114
static uint8_t bt_base_uuid_be[]
Definition: uuid.cpp:34