--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <regex>
+#include <string>
+
+#include "bluetooth_util.h"
+#include "common/scope_exit.h"
+#include "common/tools.h"
+#include "uuid.h"
+
+using common::PlatformResult;
+using common::ErrorCode;
+
+namespace {
+
+const std::regex kCanonical128BitFormat{
+ "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"};
+const std::regex k16BitFormat{"[0-9a-fA-F]{4}"};
+const std::regex k32BitFormat{"[0-9a-fA-F]{8}"};
+const std::regex kConvertibleTo16Bit{"0000[0-9a-fA-F]{4}-0000-1000-8000-00805[fF]9[bB]34[fF][bB]"};
+const std::regex kConvertibleTo32Bit{"[0-9a-fA-F]{8}-0000-1000-8000-00805[fF]9[bB]34[fF][bB]"};
+const std::string kBaseUuidLast96Bits = "-0000-1000-8000-00805f9b34fb";
+const optional<extension::bluetooth::UUID> NO_UUID{};
+const optional<std::string> NO_UUID_STR{};
+
+const int k16BitUUIDBegin = 4;
+const int k16BitUUIDLen = 4;
+const int k32BitUUIDBegin = 0;
+const int k32BitUUIDLen = 8;
+
+}; // unnamed namespace
+
+namespace extension {
+
+namespace bluetooth {
+
+UUID::UUID(std::string&& uuid_128_bit) : uuid_128_bit{uuid_128_bit} {
+ ScopeLogger("Input: %s", uuid_128_bit.c_str());
+}
+
+optional<UUID> UUID::create(const std::string& uuid) {
+ ScopeLogger("Input: %s", uuid.c_str());
+
+ auto uuid_128_bit = To128Bit(uuid);
+ if (uuid_128_bit.empty()) {
+ return NO_UUID;
+ }
+
+ return UUID{std::move(uuid_128_bit)};
+}
+
+optional<UUID> UUID::createFromGatt(const bt_gatt_h gatt_handle) {
+ ScopeLogger("Input: <a bt_gatt_h>");
+
+ char* uuid_buffer{nullptr};
+ SCOPE_EXIT {
+ free(uuid_buffer);
+ };
+
+ auto ret = bt_gatt_get_uuid(gatt_handle, &uuid_buffer);
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("Couldn't get UUID. Error: %s", util::GetBluetoothErrorMessage(ret).c_str());
+ return NO_UUID;
+ }
+
+ if (!uuid_buffer) {
+ LoggerE("Couldn't get UUID. Returned uuid is a nullptr");
+ return NO_UUID;
+ }
+
+ LoggerD("uuid_buffer: %s", uuid_buffer);
+
+ return {create(std::string{uuid_buffer})};
+}
+
+optional<std::string> UUID::To16Bit() const {
+ ScopeLogger("128 bit UUID: %s", uuid_128_bit.c_str());
+
+ if (std::regex_match(uuid_128_bit, kConvertibleTo16Bit)) {
+ return {uuid_128_bit.substr(k16BitUUIDBegin, k16BitUUIDLen)};
+ }
+
+ return NO_UUID_STR;
+}
+
+optional<std::string> UUID::To32Bit() const {
+ ScopeLogger("128 bit UUID: %s", uuid_128_bit.c_str());
+
+ if (std::regex_match(uuid_128_bit, kConvertibleTo32Bit)) {
+ return {uuid_128_bit.substr(k32BitUUIDBegin, k32BitUUIDLen)};
+ }
+
+ return NO_UUID_STR;
+}
+
+std::string UUID::ShortestPossibleFormat() const {
+ ScopeLogger("128 bit UUID: %s", uuid_128_bit.c_str());
+
+ if (std::regex_match(uuid_128_bit, kConvertibleTo16Bit)) {
+ return {uuid_128_bit.substr(k16BitUUIDBegin, k16BitUUIDLen)};
+ }
+
+ if (std::regex_match(uuid_128_bit, kConvertibleTo32Bit)) {
+ return {uuid_128_bit.substr(k32BitUUIDBegin, k32BitUUIDLen)};
+ }
+
+ return uuid_128_bit;
+}
+
+bool UUID::operator==(const UUID& other) const {
+ return uuid_128_bit == other.uuid_128_bit;
+}
+
+UUID::Format UUID::GetFormat(const std::string& uuid) {
+ ScopeLogger("uuid: %s", uuid.c_str());
+
+ if (std::regex_match(uuid, k16BitFormat)) {
+ return Format::UUID_16_BIT;
+ } else if (std::regex_match(uuid, k32BitFormat)) {
+ return Format::UUID_32_BIT;
+ } else if (std::regex_match(uuid, kCanonical128BitFormat)) {
+ return Format::UUID_128_BIT;
+ }
+
+ return Format::UUID_INVALID;
+}
+
+std::string UUID::To128Bit(const std::string& uuid) {
+ ScopeLogger("uuid: %s", uuid.c_str());
+
+ auto uuid_lower_case = common::tools::ConvertToLowerCase(uuid);
+ switch (GetFormat(uuid_lower_case)) {
+ case Format::UUID_16_BIT:
+ return "0000" + uuid_lower_case + kBaseUuidLast96Bits;
+ case Format::UUID_32_BIT:
+ return uuid_lower_case + kBaseUuidLast96Bits;
+ case Format::UUID_128_BIT:
+ return uuid_lower_case;
+ default:
+ LoggerE("Error: uuid format unknown");
+ return "";
+ }
+}
+
+} // bluetooth
+} // extension
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UUID_H_
+#define UUID_H_
+
+#include <string>
+
+#include <bluetooth.h>
+
+#include "common/platform_result.h"
+#if __cplusplus > 201402L
+#include <optional>
+using std::optional;
+#else
+#include "common/optional.h"
+using common::optional;
+#endif
+
+using common::PlatformResult;
+
+namespace extension {
+
+namespace bluetooth {
+
+struct UUID {
+ /*
+ * A UUID object is only created, if the string containing it
+ * is in a proper format or it can be created from the bt_gatt_h.
+ *
+ * create() functions accept the following formats of strings:
+ * 1. 4 hexadecimal digits, e.g.: "018D"
+ * 2. 8 hexadecimal digits, e.g.: "018Dab17"
+ * 3. 128 bit canonical UUID format defined in
+ * https://tools.ietf.org/html/rfc4122, e.g.:
+ * "f95c593e-efd4-43c4-96e4-97186ee52f83"
+ */
+ static optional<UUID> create(const std::string&);
+
+ /*
+ * This function does not validate passed bt_gatt_h.
+ * If the bt_gatt_h is not initialized, the function will likely crash.
+ *
+ * This function was purposedly not made an overload of create().
+ * If it was an overload, (const) char* could be implicitly converted to
+ * const void* (instead of std::string), which is the underlying type of
+ * bt_gatt_h.
+ */
+ static optional<UUID> createFromGatt(const bt_gatt_h);
+
+ UUID() = delete;
+ UUID(const UUID& uuid) = default;
+ UUID(UUID&& uuid) = default;
+
+ /*
+ * Only UUIDs built with kBaseUUID are convertible to 32 bit format
+ * and only a subset of them are convertible to 16 bit format.
+ *
+ * These functions always return hexadecimal lower case letters as digits.
+ */
+ optional<std::string> To16Bit() const;
+ optional<std::string> To32Bit() const;
+
+ /*
+ * This function checks if the UUID is built with kBaseUUID and tries to
+ * return the UUID in different formats in the following order:
+ * 1. 16 bit
+ * 2. 32 bit
+ * 3. 128 bit
+ */
+ std::string ShortestPossibleFormat() const;
+
+ bool operator==(const UUID&) const;
+ /*
+ * Hexadecimal letter digits are always stored in lower case.
+ */
+ const std::string uuid_128_bit;
+
+ private:
+ /*
+ * These functions don't validate passed arguments.
+ */
+ UUID(std::string&& uuid_128_bit);
+ static std::string To128Bit(const std::string& uuid);
+
+ enum class Format : int { UUID_16_BIT, UUID_32_BIT, UUID_128_BIT, UUID_INVALID };
+
+ static Format GetFormat(const std::string& uuid);
+};
+
+} // bluetooth
+} // extension
+
+#endif // UUID_H_