| /* |
| * Copyright 2018 The Android Open Source Project |
| * |
| * 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 "hci/address.h" |
| |
| #include <packet_runtime.h> |
| |
| #include <algorithm> |
| #include <array> |
| #include <cstdint> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <initializer_list> |
| #include <iomanip> |
| #include <ios> |
| #include <iterator> |
| #include <optional> |
| #include <sstream> |
| #include <string> |
| #include <utility> |
| |
| namespace bluetooth::hci { |
| |
| const Address Address::kAny{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |
| const Address Address::kEmpty{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| |
| // Address cannot initialize member variables as it is a POD type |
| // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) |
| constexpr Address::Address(std::array<uint8_t, kLength> const& address) |
| : address(address) {} |
| |
| Address::Address(const uint8_t (&address)[kLength]) { |
| std::copy(address, address + kLength, this->address.begin()); |
| } |
| |
| Address::Address(std::initializer_list<uint8_t> l) { |
| std::copy(l.begin(), std::min(l.begin() + kLength, l.end()), data()); |
| } |
| |
| bool Address::Parse(pdl::packet::slice& input, Address* output) { |
| if (input.size() < kLength) { |
| return false; |
| } |
| |
| std::array<uint8_t, kLength> address{ |
| input.read_le<uint8_t>(), input.read_le<uint8_t>(), |
| input.read_le<uint8_t>(), input.read_le<uint8_t>(), |
| input.read_le<uint8_t>(), input.read_le<uint8_t>(), |
| }; |
| *output = Address(address); |
| return true; |
| } |
| |
| std::string Address::ToString() const { |
| std::stringstream ss; |
| for (auto it = address.rbegin(); it != address.rend(); it++) { |
| ss << std::nouppercase << std::hex << std::setw(2) << std::setfill('0') |
| << +*it; |
| if (std::next(it) != address.rend()) { |
| ss << ':'; |
| } |
| } |
| return ss.str(); |
| } |
| |
| std::optional<Address> Address::FromString(const std::string& from) { |
| if (from.length() != 17) { |
| return std::nullopt; |
| } |
| |
| Address addr{}; |
| std::istringstream stream(from); |
| std::string token; |
| int index = 0; |
| while (getline(stream, token, ':')) { |
| if (index >= 6) { |
| return std::nullopt; |
| } |
| |
| if (token.length() != 2) { |
| return std::nullopt; |
| } |
| |
| char* temp = nullptr; |
| addr.address.at(5 - index) = std::strtol(token.c_str(), &temp, 16); |
| if (temp == token.c_str()) { |
| // string token is empty or has wrong format |
| return std::nullopt; |
| } |
| if (temp != (token.c_str() + token.size())) { |
| // cannot parse whole string |
| return std::nullopt; |
| } |
| |
| index++; |
| } |
| |
| if (index != 6) { |
| return std::nullopt; |
| } |
| |
| return addr; |
| } |
| |
| bool Address::FromString(const std::string& from, Address& to) { |
| auto addr = FromString(from); |
| if (!addr) { |
| to = {}; |
| return false; |
| } |
| to = std::move(*addr); |
| return true; |
| } |
| |
| size_t Address::FromOctets(const uint8_t* from) { |
| std::copy(from, from + kLength, data()); |
| return kLength; |
| } |
| |
| bool Address::IsValidAddress(const std::string& address) { |
| return Address::FromString(address).has_value(); |
| } |
| |
| } // namespace bluetooth::hci |