blob: d3106da2b2ee90741a67be86d4413a5d6b2d5d75 [file] [log] [blame]
// Copyright 2005-2009 Google Inc.
//
// 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.
// ========================================================================
//
// Provides the base class framework for those objects to be serialized
//
// HACK:
//
// During the serialization/deserialization of vector<T> members, we
// coerce the type from vector<T> to vector<byte> since we are unable to
// get the real type vector<T> at later time. This is feasible because
// vector<T> in the vector library we are linking now keeps track of
// only front() and end() pointers and use them to calculate size().
// We need to check whether this approach is still OK if we upgrade the
// standard libraries.
#include "omaha/common/serializable_object.h"
#include "omaha/common/debug.h"
#include "omaha/common/logging.h"
namespace omaha {
// Serialize
bool SerializableObject::Serialize(std::vector<byte>* data) const {
ASSERT(data, (_T("")));
// Estimate how much memory we need
int size = data->size();
for (size_t i = 0; i < members_.size(); ++i)
size += (members_[i].size > 0) ? members_[i].size : sizeof(int);
// Reserve the estimated size fo vector memory
data->reserve(size);
// Copy over the data
for (size_t i = 0; i < members_.size(); ++i) {
switch (members_[i].type) {
case SERIALIZABLE_VALUE_TYPE: {
int pos = data->size();
data->resize(data->size() + members_[i].size);
memcpy(&(*data)[pos], members_[i].ptr, members_[i].size);
break;
}
case SERIALIZABLE_CSTRING: {
CString* s = reinterpret_cast<CString*>(members_[i].ptr);
SerializeValueList(data,
reinterpret_cast<const byte*>(s->GetString()),
sizeof(TCHAR),
s->GetLength());
break;
}
case SERIALIZABLE_NESTED_OBJECT: {
SerializableObject* nested_obj =
reinterpret_cast<SerializableObject*>(members_[i].ptr);
if (!nested_obj->Serialize(data))
return false;
break;
}
case SERIALIZABLE_VECTOR | SERIALIZABLE_VALUE_TYPE: {
// Hack: coerce vector<T> to vector<byte>
std::vector<byte>* v =
reinterpret_cast<std::vector<byte>*>(members_[i].ptr);
if (v->size() != 0) {
SerializeValueList(data,
&v->front(),
members_[i].size,
v->size() / members_[i].size);
} else {
SerializeValueList(data,
NULL,
members_[i].size,
v->size() / members_[i].size);
}
break;
}
case SERIALIZABLE_VECTOR | SERIALIZABLE_CSTRING: {
std::vector<CString>* v =
reinterpret_cast<std::vector<CString>*>(members_[i].ptr);
SerializeSizeAndCount(data, 1, v->size());
if (!v->empty()) {
for (std::vector<CString>::const_iterator it = v->begin();
it != v->end();
++it) {
SerializeValueList(data,
reinterpret_cast<const byte*>(it->GetString()),
sizeof(TCHAR),
it->GetLength());
}
}
break;
}
case SERIALIZABLE_VECTOR | SERIALIZABLE_NESTED_OBJECT: {
if (!SerializeVectorNestedObject(data, members_[i].ptr))
return false;
break;
}
default:
ASSERT(false, (_T("")));
return false;
}
}
return true;
}
// Serialize the size and count values
void SerializableObject::SerializeSizeAndCount(std::vector<byte>* data,
int size,
int count) const {
ASSERT(data, (_T("")));
ASSERT(size >= 0, (_T("")));
// Get current size
int pos = data->size();
// Adjust the size of the data buffer
data->resize(data->size() + 2 * sizeof(int));
// Get pointer to the position of data buffer we start to write
byte* ptr = &((*data)[pos]);
// Push size
memcpy(ptr, &size, sizeof(int));
ptr += sizeof(int);
// Push count
memcpy(ptr, &count, sizeof(int));
ptr += sizeof(int);
}
// Serialize a list of value-typed elements
//
// Args:
// ser_data: pointer to the vector for the serialized data
// raw_data: pointer to the raw data to be serialized
// size: the size of the element in the list
// count: the number of the elements in the list
void SerializableObject::SerializeValueList(std::vector<byte>* ser_data,
const byte* raw_data,
int size,
int count) const {
ASSERT(ser_data, (_T("")));
ASSERT(size > 0, (_T("")));
// Serialize the size and count values
SerializeSizeAndCount(ser_data, size, count);
// Push data
if (count > 0) {
// Get current size
int pos = ser_data->size();
// Adjust the size of the data buffer
ser_data->resize(ser_data->size() + count * size);
// Get pointer to the position of data buffer we start to write
byte* ptr = &((*ser_data)[pos]);
// Copy data
memcpy(ptr, raw_data, count * size);
}
}
// Deserialize
bool SerializableObject::Deserialize(byte* data, int size, uint32 version) {
ASSERT(data, (_T("")));
ASSERT(size > 0, (_T("")));
byte* tail = data + size;
byte** data_ptr = &data;
if (!DeserializeHelper(data_ptr, size, version))
return false;
if (*data_ptr != tail) {
UTIL_LOG(LE, (_T("[SerializableObject::Deserialize]")
_T("[failed to deserialize all data]")));
return false;
}
return true;
}
// Deserialize helper
bool SerializableObject::DeserializeHelper(byte** data,
int size,
uint32 version) {
ASSERT(data, (_T("")));
ASSERT(size > 0, (_T("")));
byte* tail = *data + size;
for (size_t i = 0; i < members_.size(); ++i) {
// Ignore those members which are persisted in newer versions
if (version != kLatestSerializableVersion &&
members_[i].version > version) {
continue;
}
switch (members_[i].type) {
case SERIALIZABLE_VALUE_TYPE:
if (*data + members_[i].size > tail) {
UTIL_LOG(L6, (_T("[SerializableObject::DeserializeHelper]")
_T("[overflow when deserializing value type]")));
return false;
}
memcpy(members_[i].ptr, *data, members_[i].size);
*data += members_[i].size;
break;
case SERIALIZABLE_CSTRING: {
std::vector<byte> deser_data;
if (!DeserializeValueList(&deser_data,
members_[i].size,
data,
tail - *data))
return false;
CString* s = reinterpret_cast<CString*>(members_[i].ptr);
if (deser_data.size() != 0) {
s->SetString(reinterpret_cast<const TCHAR*>(&deser_data.front()),
deser_data.size() / members_[i].size);
} else {
s->SetString(_T(""));
}
break;
}
case SERIALIZABLE_NESTED_OBJECT: {
SerializableObject* nested_obj =
reinterpret_cast<SerializableObject*>(members_[i].ptr);
if (!nested_obj->DeserializeHelper(data, size, version))
return false;
break;
}
case SERIALIZABLE_VECTOR | SERIALIZABLE_VALUE_TYPE: {
// Hack: coerce vector<T> to vector<byte>
std::vector<byte>* v =
reinterpret_cast<std::vector<byte>*>(members_[i].ptr);
if (!DeserializeValueList(v, members_[i].size, data, tail - *data))
return false;
break;
}
case SERIALIZABLE_VECTOR | SERIALIZABLE_CSTRING: {
std::vector<CString>* v =
reinterpret_cast<std::vector<CString>*>(members_[i].ptr);
int count = 0;
if (!DeserializeSizeAndCount(&count, 1, data, tail - *data))
return false;
for (int j = 0; j < count; ++j) {
std::vector<byte> deser_data;
if (!DeserializeValueList(&deser_data,
members_[i].size,
data,
tail - *data))
return false;
CString s;
if (deser_data.size() != 0) {
s = CString(reinterpret_cast<const TCHAR*>(&deser_data.front()),
deser_data.size() / members_[i].size);
}
v->push_back(s);
}
break;
}
case SERIALIZABLE_VECTOR | SERIALIZABLE_NESTED_OBJECT: {
if (!DeserializeVectorNestedObject(data,
tail - *data,
members_[i].ptr,
version))
return false;
break;
}
default:
ASSERT(false, (_T("")));
break;
}
}
return true;
}
// Serialize the size and count values
bool SerializableObject::DeserializeSizeAndCount(int* count,
int size,
byte** ser_data,
int ser_size) const {
ASSERT(ser_data, (_T("")));
ASSERT(count, (_T("")));
byte* ser_tail = *ser_data + ser_size;
// Check to make sure that the serialization data should at least contain
// 'size' and 'count'
if (*ser_data + 2 * sizeof(int) > ser_tail) {
UTIL_LOG(L6, (_T("[SerializableObject::DeserializeSizeAndCount]")
_T("[overflow when deserializing size and count]")));
return false;
}
// Get size
// If the passing size is 0, skip the size check
int size2 = *(reinterpret_cast<const int*>(*ser_data));
*ser_data += sizeof(int);
if (size && size != size2)
return false;
// Get count
*count = *(reinterpret_cast<const int*>(*ser_data));
*ser_data += sizeof(int);
return true;
}
// Deserialize a list of value-typed elements
//
// Args:
// ser_data: pointer to the vector for the serialized data
// size: the size of the element in the list
// raw_data: pointer to the raw data to be serialized
// ser_size: size of the serization data
bool SerializableObject::DeserializeValueList(std::vector<byte>* raw_data,
int size,
byte** ser_data,
int ser_size) {
ASSERT(raw_data, (_T("")));
ASSERT(ser_data, (_T("")));
byte* ser_tail = *ser_data + ser_size;
// Deserialize the size and count values
int count = 0;
bool ret = DeserializeSizeAndCount(&count, size, ser_data, ser_size);
if (!ret)
return false;
// Check to make sure that the serialization data is in the right size
if (*ser_data + count * size > ser_tail) {
UTIL_LOG(L6, (_T("[SerializableObject::DeserializeValueList]")
_T("[overflow when deserializing value list]")));
return false;
}
// Get data
raw_data->resize(size * count);
if (count > 0) {
memcpy(&raw_data->front(), *ser_data, count * size);
*ser_data += count * size;
}
return true;
}
} // namespace omaha