blob: 03493006531f657409395414aa9a446e4138831e [file] [edit]
/*
*
* Copyright (c) 2016 Nest Labs, Inc.
* 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.
*
* Description:
* Implementation of utility functions related to boost::any.
*
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdint.h>
#include "any-to.h"
#include <exception>
#include <stdexcept>
#include <ctype.h>
#include <list>
#include "string-utils.h"
#include "IPv6Helpers.h"
using namespace nl;
nl::Data any_to_data(const boost::any& value)
{
nl::Data ret;
if (value.type() == typeid(std::string)) {
std::string key_string = boost::any_cast<std::string>(value);
uint8_t data[key_string.size()/2];
int length = parse_string_into_data(data,
key_string.size()/2,
key_string.c_str());
ret = nl::Data(data, length);
} else if (value.type() == typeid(nl::Data)) {
ret = boost::any_cast<nl::Data>(value);
} else if (value.type() == typeid(uint64_t)) {
union {
uint64_t val;
uint8_t data[sizeof(uint64_t)];
} x;
x.val = boost::any_cast<uint64_t>(value);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
reverse_bytes(x.data, sizeof(uint64_t));
#endif
ret.append(x.data,sizeof(uint64_t));
} else {
ret = nl::Data(boost::any_cast<std::vector<uint8_t> >(value));
}
return ret;
}
int any_to_int(const boost::any& value)
{
int32_t ret = 0;
if (value.type() == typeid(std::string)) {
std::string key_string = boost::any_cast<std::string>(value);
ret = (int)strtol(key_string.c_str(), NULL, 0);
} else if (value.type() == typeid(uint8_t)) {
ret = boost::any_cast<uint8_t>(value);
} else if (value.type() == typeid(int8_t)) {
ret = boost::any_cast<int8_t>(value);
} else if (value.type() == typeid(uint16_t)) {
ret = boost::any_cast<uint16_t>(value);
} else if (value.type() == typeid(int16_t)) {
ret = boost::any_cast<int16_t>(value);
} else if (value.type() == typeid(uint32_t)) {
ret = boost::any_cast<uint32_t>(value);
} else if (value.type() == typeid(int32_t)) {
ret = boost::any_cast<int32_t>(value);
} else if (value.type() == typeid(bool)) {
ret = boost::any_cast<bool>(value);
} else if (value.type() == typeid(unsigned int)) {
ret = boost::any_cast<unsigned int>(value);
} else {
ret = boost::any_cast<int>(value);
}
return ret;
}
struct in6_addr
any_to_ipv6(const boost::any& value)
{
struct in6_addr ret = {};
if (value.type() == typeid(std::string)) {
std::string str(boost::any_cast<std::string>(value));
size_t lastchar(str.find_first_not_of("0123456789abcdefABCDEF:."));
int bytes;
if (lastchar != std::string::npos) {
str.erase(str.begin() + lastchar, str.end());
}
bytes = inet_pton(
AF_INET6,
str.c_str(),
ret.s6_addr
);
if (bytes <= 0) {
throw std::invalid_argument("String not IPv6 address");
}
} else if (value.type() == typeid(nl::Data)) {
nl::Data data(boost::any_cast<nl::Data>(value));
if (data.size() <= sizeof(ret)) {
memcpy(ret.s6_addr, data.data(), data.size());
}
} else {
ret = boost::any_cast<struct in6_addr>(value);
}
return ret;
}
uint64_t
any_to_uint64(const boost::any& value, bool expect_hex_str)
{
uint64_t ret(0);
if (value.type() == typeid(std::string)) {
const std::string& key_string = boost::any_cast<std::string>(value);
if (expect_hex_str && key_string.size() != 16) {
throw std::invalid_argument("String not 16 characters long");
}
// If `expect_hex_str` is set, we expect the string to be 16 hex chars.
ret = static_cast<uint64_t>(strtoull(key_string.c_str(), NULL, expect_hex_str ? 16 : 0));
} else if (value.type() == typeid(nl::Data)) {
const nl::Data& data = boost::any_cast<nl::Data>(value);
union {
uint64_t val;
uint8_t data[sizeof(uint64_t)];
} x;
if (data.size() != sizeof(uint64_t)) {
throw std::invalid_argument("Data not 8 bytes long");
}
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
memcpyrev(x.data, data.data(), sizeof(uint64_t));
#else
memcpy(x.data, data.data(), sizeof(uint64_t));
#endif
ret = x.val;
} else {
ret = boost::any_cast<uint64_t>(value);
}
return ret;
}
bool any_to_bool(const boost::any& value)
{
bool ret = 0;
if (value.type() == typeid(std::string)) {
std::string key_string = boost::any_cast<std::string>(value);
if (key_string=="true" || key_string=="yes" || key_string=="1" || key_string == "TRUE" || key_string == "YES")
ret = true;
else if (key_string=="false" || key_string=="no" || key_string=="0" || key_string == "FALSE" || key_string == "NO")
ret = false;
else
ret = (bool)strtol(key_string.c_str(), NULL, 0);
} else if (value.type() == typeid(bool)) {
ret = boost::any_cast<bool>(value);
} else {
ret = any_to_int(value) != 0;
}
return ret;
}
std::string any_to_string(const boost::any& value)
{
std::string ret;
if (value.type() == typeid(std::string)) {
ret = boost::any_cast<std::string>(value);
} else if (value.type() == typeid(uint8_t)) {
char tmp[10];
snprintf(tmp, sizeof(tmp), "%u", boost::any_cast<uint8_t>(value));
ret = tmp;
} else if (value.type() == typeid(int8_t)) {
char tmp[10];
snprintf(tmp, sizeof(tmp), "%d", boost::any_cast<int8_t>(value));
ret = tmp;
} else if (value.type() == typeid(uint16_t)) {
char tmp[10];
snprintf(tmp, sizeof(tmp), "%u", boost::any_cast<uint16_t>(value));
ret = tmp;
} else if (value.type() == typeid(int16_t)) {
char tmp[10];
snprintf(tmp, sizeof(tmp), "%d", boost::any_cast<int16_t>(value));
ret = tmp;
} else if (value.type() == typeid(uint32_t)) {
char tmp[10];
snprintf(tmp, sizeof(tmp), "%u", (unsigned int)boost::any_cast<uint32_t>(value));
ret = tmp;
} else if (value.type() == typeid(int32_t)) {
char tmp[10];
snprintf(tmp, sizeof(tmp), "%d", (int)boost::any_cast<int32_t>(value));
ret = tmp;
} else if (value.type() == typeid(uint64_t)) {
char tmp[20];
uint64_t u64_val = boost::any_cast<uint64_t>(value);
snprintf(tmp,
sizeof(tmp),
"%08x%08x",
static_cast<uint32_t>(u64_val >> 32),
static_cast<uint32_t>(u64_val & 0xFFFFFFFF));
ret = tmp;
} else if (value.type() == typeid(unsigned int)) {
char tmp[10];
snprintf(tmp, sizeof(tmp), "%u", boost::any_cast<unsigned int>(value));
ret = tmp;
} else if (value.type() == typeid(int)) {
char tmp[10];
snprintf(tmp, sizeof(tmp), "%d", boost::any_cast<int>(value));
ret = tmp;
} else if (value.type() == typeid(bool)) {
ret = (boost::any_cast<bool>(value))? "true" : "false";
} else if (value.type() == typeid(nl::Data)) {
nl::Data data = boost::any_cast<nl::Data>(value);
ret = std::string(data.size()*2,0);
// Reserve the zero termination
ret.reserve(data.size()*2+1);
encode_data_into_string(data.data(),
data.size(),
&ret[0],
ret.capacity(),
0);
} else if (value.type() == typeid(std::list<std::string>)) {
std::list<std::string> l = boost::any_cast<std::list<std::string> >(value);
if (!l.empty()) {
std::list<std::string>::const_iterator iter;
ret = "{\n";
for (iter = l.begin(); iter != l.end(); ++iter) {
ret += "\t\"" + *iter + "\"\n";
}
ret += "}";
} else {
ret = "{ }";
}
} else if (value.type() == typeid(struct in6_addr)) {
struct in6_addr addr = boost::any_cast<struct in6_addr>(value);
ret = in6_addr_to_string(addr);
} else {
ret += "<";
ret += value.type().name();
ret += ">";
}
return ret;
}
std::set<int>
any_to_int_set(const boost::any& value)
{
std::set<int> ret;
if (value.type() == typeid(std::string)) {
std::string key_string = boost::any_cast<std::string>(value);
if (key_string.empty()) {
// Empty set. Do nothing.
} else if (key_string.find(',') != std::string::npos) {
// List of values. Not yet supported.
throw std::invalid_argument("integer mask string format not yet implemented");
} else if (isdigit(key_string[0])) {
// Special case, only one value.
ret.insert((int)strtol(key_string.c_str(), NULL, 0));
} else {
throw std::invalid_argument(key_string);
}
} else if (value.type() == typeid(uint8_t)) {
ret.insert(boost::any_cast<uint8_t>(value));
} else if (value.type() == typeid(int8_t)) {
ret.insert(boost::any_cast<int8_t>(value));
} else if (value.type() == typeid(uint16_t)) {
ret.insert(boost::any_cast<uint16_t>(value));
} else if (value.type() == typeid(int16_t)) {
ret.insert(boost::any_cast<int16_t>(value));
} else if (value.type() == typeid(uint32_t)) {
ret.insert(boost::any_cast<uint32_t>(value));
} else if (value.type() == typeid(int32_t)) {
ret.insert(boost::any_cast<int32_t>(value));
} else if (value.type() == typeid(bool)) {
ret.insert(boost::any_cast<bool>(value));
} else if (value.type() == typeid(std::list<int>)) {
std::list<int> number_list(boost::any_cast< std::list<int> >(value));
ret.insert(number_list.begin(), number_list.end());
} else if (value.type() == typeid(std::list<boost::any>)) {
std::list<boost::any> any_list(boost::any_cast< std::list<boost::any> >(value));
std::list<boost::any>::const_iterator iter;
for(iter = any_list.begin(); iter != any_list.end(); ++iter) {
ret.insert(any_to_int(*iter));
}
} else {
ret = boost::any_cast< std::set<int> >(value);
}
return ret;
}