blob: 4d4ace244077f558bd45355a9ae78d969444b425 [file] [log] [blame]
// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/utility.h"
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <string>
#include <vector>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <dbus/dbus.h>
using base::DictionaryValue;
using base::ListValue;
using base::Value;
namespace {
bool DBusMessageIterToPrimitiveValue(DBus::MessageIter& iter, Value** result) {
DBus::MessageIter subiter;
switch (iter.type()) {
case DBUS_TYPE_BYTE:
*result = Value::CreateIntegerValue(iter.get_byte());
return true;
case DBUS_TYPE_BOOLEAN:
*result = Value::CreateBooleanValue(iter.get_bool());
return true;
case DBUS_TYPE_INT16:
*result = Value::CreateIntegerValue(iter.get_int16());
return true;
case DBUS_TYPE_UINT16:
*result = Value::CreateIntegerValue(iter.get_uint16());
return true;
case DBUS_TYPE_INT32:
*result = Value::CreateIntegerValue(iter.get_int32());
return true;
case DBUS_TYPE_UINT32:
*result = Value::CreateStringValue(base::UintToString(iter.get_uint32()));
return true;
case DBUS_TYPE_INT64:
*result = Value::CreateStringValue(
base::Int64ToString(iter.get_int64()));
return true;
case DBUS_TYPE_UINT64:
*result = Value::CreateStringValue(
base::Uint64ToString(iter.get_uint64()));
return true;
case DBUS_TYPE_DOUBLE:
*result = Value::CreateDoubleValue(iter.get_double());
return true;
case DBUS_TYPE_STRING:
*result = Value::CreateStringValue(iter.get_string());
return true;
case DBUS_TYPE_OBJECT_PATH:
*result = Value::CreateStringValue(iter.get_path());
return true;
case DBUS_TYPE_SIGNATURE:
*result = Value::CreateStringValue(iter.get_signature());
return true;
case DBUS_TYPE_UNIX_FD:
*result = Value::CreateIntegerValue(iter.get_int32());
return true;
case DBUS_TYPE_VARIANT:
subiter = iter.recurse();
return chromeos::DBusMessageIterToValue(subiter, result);
default:
LOG(ERROR) << "Unhandled primitive type: " << iter.type();
return false;
}
}
bool DBusMessageIterToArrayValue(DBus::MessageIter& iter, Value** result) {
// For an array, create an empty ListValue, then recurse into it.
ListValue* lv = new ListValue();
while (!iter.at_end()) {
Value* subvalue = NULL;
bool r = chromeos::DBusMessageIterToValue(iter, &subvalue);
if (!r) {
delete lv;
return false;
}
lv->Append(subvalue);
iter++;
}
*result = lv;
return true;
}
bool DBusMessageIterToDictValue(DBus::MessageIter& iter, Value** result) {
// For a dict, create an empty DictionaryValue, then walk the subcontainers
// with the key-value pairs, adding them to the dict.
DictionaryValue* dv = new DictionaryValue();
while (!iter.at_end()) {
DBus::MessageIter subiter = iter.recurse();
Value* key = NULL;
Value* value = NULL;
bool r = chromeos::DBusMessageIterToValue(subiter, &key);
if (!r || key->GetType() != Value::TYPE_STRING) {
delete dv;
return false;
}
subiter++;
r = chromeos::DBusMessageIterToValue(subiter, &value);
if (!r) {
delete key;
delete dv;
return false;
}
std::string keystr;
key->GetAsString(&keystr);
dv->Set(keystr, value);
delete key;
iter++;
}
*result = dv;
return true;
}
}; // namespace
namespace chromeos {
using std::string;
char DecodeChar(char in) {
in = tolower(in);
if ((in <= '9') && (in >= '0')) {
return in - '0';
} else {
CHECK_GE(in, 'a');
CHECK_LE(in, 'f');
return in - 'a' + 10;
}
}
string AsciiEncode(const Blob &blob) {
static const char table[] = "0123456789abcdef";
string out;
for (Blob::const_iterator it = blob.begin(); blob.end() != it; ++it) {
out += table[((*it) >> 4) & 0xf];
out += table[*it & 0xf];
}
CHECK_EQ(blob.size() * 2, out.size());
return out;
}
Blob AsciiDecode(const string &str) {
Blob out;
if (str.size() % 2)
return out;
for (string::const_iterator it = str.begin(); it != str.end(); ++it) {
char append = DecodeChar(*it);
append <<= 4;
++it;
append |= DecodeChar(*it);
out.push_back(append);
}
CHECK_EQ(out.size() * 2, str.size());
return out;
}
void* SecureMemset(void *v, int c, size_t n) {
volatile unsigned char *p = static_cast<unsigned char *>(v);
while (n--)
*p++ = c;
return v;
}
int SafeMemcmp(const void* s1, const void* s2, size_t n) {
const unsigned char* us1 = static_cast<const unsigned char*>(s1);
const unsigned char* us2 = static_cast<const unsigned char*>(s2);
int result = 0;
if (0 == n)
return 1;
/* Code snippet without data-dependent branch due to
* Nate Lawson (nate@root.org) of Root Labs. */
while (n--)
result |= *us1++ ^ *us2++;
return result != 0;
}
bool DBusMessageToValue(DBus::Message& message, Value** v) {
DBus::MessageIter r = message.reader();
return DBusMessageIterToArrayValue(r, v);
}
bool DBusMessageIterToValue(DBus::MessageIter& iter, Value** result) {
if (iter.at_end()) {
*result = NULL;
return true;
}
if (!iter.is_array() && !iter.is_dict()) {
// Primitive type. Stash it in result directly and return.
return DBusMessageIterToPrimitiveValue(iter, result);
}
if (iter.is_dict()) {
DBus::MessageIter subiter = iter.recurse();
return DBusMessageIterToDictValue(subiter, result);
}
if (iter.is_array()) {
DBus::MessageIter subiter = iter.recurse();
return DBusMessageIterToArrayValue(subiter, result);
}
return false;
}
bool DBusPropertyMapToValue(std::map<std::string, DBus::Variant>& properties,
Value** v) {
DictionaryValue* dv = new DictionaryValue();
for (std::map<std::string, DBus::Variant>::iterator it = properties.begin();
it != properties.end();
++it) {
Value* v = NULL;
// make a copy so we can take a reference to the MessageIter
DBus::MessageIter reader = it->second.reader();
bool r = DBusMessageIterToValue(reader, &v);
if (!r) {
delete dv;
return false;
}
dv->Set(it->first, v);
}
*v = static_cast<Value*>(dv);
return true;
}
bool SecureRandom(uint8_t *buf, size_t len) {
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0)
return false;
if (read(fd, buf, len) != static_cast<ssize_t>(len)) {
close(fd);
return false;
}
close(fd);
return true;
}
bool SecureRandomString(size_t len, std::string* result) {
char rbuf[len];
if (!SecureRandom(reinterpret_cast<uint8_t*>(rbuf), len))
return false;
*result = base::HexEncode(rbuf, len);
return true;
}
} // namespace chromeos