blob: 5788eee8c0cf300c94ca4b98f355554aa89fad53 [file] [log] [blame]
// Copyright 2015 The Chromium 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/binder/transaction_data_reader.h"
#include <stddef.h>
#include <stdint.h>
#include "base/logging.h"
#include "chromeos/binder/binder_driver_api.h"
#include "chromeos/binder/local_object.h"
#include "chromeos/binder/object.h"
#include "chromeos/binder/remote_object.h"
#include "chromeos/binder/transaction_data.h"
namespace binder {
namespace {
// Adds appropriate padding to the given size to make it 4-byte aligned.
size_t AddPadding(size_t n) {
return (n + 3) & (~3);
}
} // namespace
TransactionDataReader::TransactionDataReader(const TransactionData& data)
: reader_(reinterpret_cast<const char*>(data.GetData()),
data.GetDataSize()) {}
TransactionDataReader::~TransactionDataReader() {}
bool TransactionDataReader::HasMoreData() const {
return reader_.HasMoreData();
}
bool TransactionDataReader::ReadData(void* buf, size_t n) {
DCHECK(buf);
return reader_.Read(buf, n) && reader_.Skip(AddPadding(n) - n);
}
bool TransactionDataReader::ReadInt32(int32_t* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadUint32(uint32_t* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadInt64(int64_t* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadUint64(uint64_t* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadFloat(float* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadDouble(double* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadCString(const char** value) {
*value = reader_.current();
for (size_t len = 0; reader_.HasMoreData(); ++len) {
char c = 0;
if (!reader_.Read(&c, sizeof(c))) {
return false;
}
if (c == 0) {
return reader_.Skip(AddPadding(len + 1) - (len + 1));
}
}
return false;
}
bool TransactionDataReader::ReadString(std::string* value) {
int32_t len = 0;
if (!ReadInt32(&len)) {
return false;
}
if (len == 0) {
// Read only when the string is not empty.
// This is different from ReadString16().
value->clear();
return true;
}
const char* start = reader_.current();
if (!reader_.Skip(AddPadding(len + 1))) {
return false;
}
value->assign(start, len);
return true;
}
bool TransactionDataReader::ReadString16(base::string16* value) {
int32_t len = 0;
if (!ReadInt32(&len)) {
return false;
}
const base::char16* start =
reinterpret_cast<const base::char16*>(reader_.current());
if (!reader_.Skip(AddPadding((len + 1) * sizeof(base::char16)))) {
return false;
}
value->assign(start, len);
return true;
}
scoped_refptr<Object> TransactionDataReader::ReadObject(
CommandBroker* command_broker) {
DCHECK(command_broker);
flat_binder_object obj = {};
if (!ReadData(&obj, sizeof(obj))) {
return scoped_refptr<Object>();
}
switch (obj.type) {
case BINDER_TYPE_HANDLE:
return make_scoped_refptr(new RemoteObject(command_broker, obj.handle));
case BINDER_TYPE_BINDER:
return make_scoped_refptr(reinterpret_cast<LocalObject*>(obj.cookie));
}
return scoped_refptr<Object>();
}
bool TransactionDataReader::ReadFileDescriptor(int* fd) {
flat_binder_object obj = {};
if (!ReadData(&obj, sizeof(obj)) || obj.type != BINDER_TYPE_FD) {
return false;
}
*fd = obj.handle;
return true;
}
} // namespace binder