#ifndef _H_WALKERS
#define _H_WALKERS
#include <security_utilities/alloc.h>
#include <security_utilities/memstreams.h>
#include <security_cdsa_utilities/cssmdata.h>
#include <security_utilities/debugging.h>
#include <set>
namespace Security {
namespace DataWalkers {
#define WALKERDEBUG 0
#if WALKERDEBUG
# define DEBUGWALK(who) secdebug("walkers", "walk " who " %s@%p (%ld)", \
Debug::typeName(addr).c_str(), addr, size)
#else
# define DEBUGWALK(who)
#endif
class SizeWalker : public LowLevelMemoryUtilities::Writer::Counter {
public:
template <class T>
void operator () (T &obj, size_t size = sizeof(T)) { }
template <class T>
void operator () (T *addr, size_t size = sizeof(T))
{ DEBUGWALK("size"); LowLevelMemoryUtilities::Writer::Counter::insert(size); }
void blob(void *addr, size_t size)
{ (*this)(addr, size); }
void reserve(size_t space)
{ LowLevelMemoryUtilities::Writer::Counter::insert(space); }
static const bool needsRelinking = false;
static const bool needsSize = true;
};
class CopyWalker : public LowLevelMemoryUtilities::Writer {
public:
CopyWalker() { }
CopyWalker(void *base) : LowLevelMemoryUtilities::Writer(base) { }
public:
template <class T>
void operator () (T &obj, size_t size = sizeof(T))
{ }
template <class T>
void operator () (T * &addr, size_t size = sizeof(T))
{
DEBUGWALK("copy");
if (addr)
addr = reinterpret_cast<T *>(LowLevelMemoryUtilities::Writer::operator () (addr, size));
}
template <class T>
void blob(T * &addr, size_t size)
{ (*this)(addr, size); }
static const bool needsRelinking = true;
static const bool needsSize = true;
};
class ReconstituteWalker {
public:
ReconstituteWalker(off_t offset) : mOffset(offset) { }
ReconstituteWalker(void *ptr, void *base)
: mOffset(LowLevelMemoryUtilities::difference(ptr, base)) { }
template <class T>
void operator () (T &obj, size_t size = sizeof(T))
{ }
template <class T>
void operator () (T * &addr, size_t size = 0)
{
DEBUGWALK("reconstitute");
if (addr)
addr = LowLevelMemoryUtilities::increment<T>(addr, (ptrdiff_t)mOffset);
}
template <class T>
void blob(T * &addr, size_t size)
{ (*this)(addr, size); }
static const bool needsRelinking = true;
static const bool needsSize = false;
private:
off_t mOffset;
};
class ChunkCopyWalker {
public:
ChunkCopyWalker(Allocator &alloc = Allocator::standard()) : allocator(alloc) { }
Allocator &allocator;
template <class T>
void operator () (T &obj, size_t size = sizeof(T))
{ }
template <class T>
void operator () (T * &addr, size_t size = sizeof(T))
{
DEBUGWALK("chunkcopy");
#if BUG_GCC
T *copy = reinterpret_cast<T *>(allocator.malloc(size));
#else
T *copy = allocator.malloc<T>(size);
#endif
memcpy(copy, addr, size);
addr = copy;
}
template <class T>
void blob(T * &addr, size_t size)
{ (*this)(addr, size); }
static const bool needsRelinking = true;
static const bool needsSize = true;
};
class ChunkFreeWalker {
public:
ChunkFreeWalker(Allocator &alloc = Allocator::standard()) : allocator(alloc) { }
Allocator &allocator;
template <class T>
void operator () (T &obj, size_t size = 0)
{ }
template <class T>
void operator () (T *addr, size_t size = 0)
{
DEBUGWALK("chunkfree");
freeSet.insert(addr);
}
void blob(void *addr, size_t size)
{ (*this)(addr, 0); }
void free();
~ChunkFreeWalker() { free(); }
static const bool needsRelinking = false;
static const bool needsSize = false;
private:
std::set<void *> freeSet;
};
template <class T>
size_t size(T obj)
{
SizeWalker w;
walk(w, obj);
return w;
}
template <class T>
size_t size(const T *obj)
{ return size(const_cast<T *>(obj)); }
template <class T>
T *copy(const T *obj, void *addr)
{
if (obj == NULL)
return NULL;
CopyWalker w(addr);
walk(w, const_cast<T * &>(obj));
return const_cast<T *>(obj);
}
template <class T>
T *copy(const T *obj, Allocator &alloc, size_t size)
{
if (obj == NULL)
return NULL;
return copy(obj, alloc.malloc(size));
}
template <class T>
T *copy(const T *obj, Allocator &alloc = Allocator::standard())
{
return obj ? copy(obj, alloc, size(obj)) : NULL;
}
template <class T>
void relocate(T *obj, T *base)
{
if (obj) {
ReconstituteWalker w(LowLevelMemoryUtilities::difference(obj, base));
walk(w, base);
}
}
template <class T>
typename Nonconst<T>::Type *chunkCopy(T *obj, Allocator &alloc = Allocator::standard())
{
if (obj) {
ChunkCopyWalker w(alloc);
return walk(w, unconst_ref_cast<T *>(obj));
} else
return NULL;
}
template <class T>
T chunkCopy(T obj, Allocator &alloc = Allocator::standard())
{
ChunkCopyWalker w(alloc);
walk(w, obj);
return obj;
}
template <class T>
void chunkFree(T *obj, Allocator &alloc = Allocator::standard())
{
if (obj) {
ChunkFreeWalker w(alloc);
walk(w, unconst_ref_cast<T *>(obj));
}
}
template <class T>
void chunkFree(const T &obj, Allocator &alloc = Allocator::standard())
{
ChunkFreeWalker w(alloc);
walk(w, obj);
}
template <class T>
class Copier {
public:
Copier(const T *obj, Allocator &alloc = Allocator::standard()) : allocator(alloc)
{
if (obj == NULL) {
mValue = NULL;
mLength = 0;
} else {
mLength = size(const_cast<T *>(obj));
#if BUG_GCC
mValue = reinterpret_cast<T *>(alloc.malloc(mLength));
#else
mValue = alloc.malloc<T>(mLength);
#endif
mValue = copy(obj, mValue);
}
}
Copier(const T *obj, uint32 count, Allocator &alloc = Allocator::standard())
: allocator(alloc)
{
if (obj == NULL) {
mValue = NULL;
mLength = 0;
} else {
SizeWalker sizer;
sizer.reserve(sizeof(T) * count); for (uint32 n = 0; n < count; n++)
walk(sizer, const_cast<T &>(obj[n])); mLength = sizer;
#if BUG_GCC
mValue = reinterpret_cast<T *>(alloc.malloc(mLength));
#else
mValue = alloc.malloc<T>(mLength);
#endif
CopyWalker copier(LowLevelMemoryUtilities::increment(mValue, sizeof(T) * count));
for (uint32 n = 0; n < count; n++) {
mValue[n] = obj[n];
walk(copier, mValue[n]);
}
}
}
Allocator &allocator;
~Copier() { allocator.free(mValue); }
T *value() const { return mValue; }
operator T *() const { return value(); }
size_t length() const { return mLength; }
T *keep() { T *result = mValue; mValue = NULL; return result; }
private:
T *mValue;
size_t mLength;
};
} }
#endif //_H_WALKERS