#ifndef _H_SUPERBLOB
#define _H_SUPERBLOB
#include <security_utilities/blob.h>
#include <map>
namespace Security {
template <class _BlobType, uint32_t _magic, class _Type>
class SuperBlobCore: public Blob<_BlobType, _magic> {
public:
class Maker; friend class Maker;
typedef _Type Type;
typedef BlobCore::Offset Offset;
template <class BlobType> BlobType *at(Offset offset) { return BlobCore::at<BlobType>(offset); }
template <class BlobType> const BlobType *at(Offset offset) const { return BlobCore::at<BlobType>(offset); }
void setup(size_t size, unsigned count)
{ this->initialize(size); this->mCount = count; }
struct Index {
Endian<Type> type; Endian<Offset> offset; };
bool validateBlob(size_t maxSize = 0) const;
unsigned count() const { return mCount; }
Type type(unsigned n) const { assert(n < mCount); return mIndex[n].type; }
const BlobCore *blob(unsigned n) const
{ assert(n < mCount); return mIndex[n].offset ? at<const BlobCore>(mIndex[n].offset) : NULL; }
template <class BlobType>
const BlobType *blob(unsigned n) const { return BlobType::specific(blob(n)); }
const BlobCore *find(Type type) const;
template <class BlobType>
const BlobType *find(Type type) const { return BlobType::specific(find(type)); }
private:
Endian<uint32_t> mCount; Index mIndex[0]; };
template <class _BlobType, uint32_t _magic, class _Type>
inline bool SuperBlobCore<_BlobType, _magic, _Type>::validateBlob(size_t maxSize ) const
{
unsigned count = mCount;
size_t ixLimit = sizeof(SuperBlobCore) + count * sizeof(Index); if (!BlobCore::validateBlob(_magic, ixLimit, maxSize))
return false;
for (const Index *ix = mIndex + count - 1; ix >= mIndex; ix--) {
Offset offset = ix->offset;
if (offset) if (offset < ixLimit || offset + sizeof(BlobCore) > this->length() || offset + at<const BlobCore>(offset)->length() > this->length()) return false;
}
return true;
}
template <uint32_t _magic, class _Type = uint32_t>
class SuperBlob : public SuperBlobCore<SuperBlob<_magic, _Type>, _magic, _Type> {
};
template <class _BlobType, uint32_t _magic, class _Type>
const BlobCore *SuperBlobCore<_BlobType, _magic, _Type>::find(Type type) const
{
for (unsigned slot = 0; slot < mCount; slot++)
if (mIndex[slot].type == type)
return mIndex[slot].offset ? at<const BlobCore>(mIndex[slot].offset) : NULL;
return NULL; }
template <class _BlobType, uint32_t _magic, class _Type>
class SuperBlobCore<_BlobType, _magic, _Type>::Maker {
public:
Maker() { }
Maker(const Maker &src)
{
for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
mPieces.insert(make_pair(it->first, it->second->clone()));
}
~Maker()
{
for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
::free(it->second);
}
void add(Type type, BlobCore *blob); void add(const _BlobType *blobs); void add(const Maker &maker);
bool contains(Type type) const { return mPieces.find(type) != mPieces.end(); }
BlobCore *get(Type type) const
{
typename BlobMap::const_iterator it = mPieces.find(type);
return (it == mPieces.end()) ? NULL : it->second;
}
size_t size(size_t size1 = 0, ...) const; _BlobType *make() const; _BlobType *operator () () const { return make(); }
private:
typedef std::map<Type, BlobCore *> BlobMap;
BlobMap mPieces;
};
template <class _BlobType, uint32_t _magic, class _Type>
void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(Type type, BlobCore *blob)
{
pair<typename BlobMap::iterator, bool> r = mPieces.insert(make_pair(type, blob));
if (!r.second) { secdebug("superblob", "Maker %p replaces type=%d", this, type);
::free(r.first->second);
r.first->second = blob;
}
}
template <class _BlobType, uint32_t _magic, class _Type>
void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const _BlobType *blobs)
{
for (uint32_t ix = 0; ix < blobs->mCount; ix++)
this->add(blobs->mIndex[ix].type, blobs->blob(ix)->clone());
}
template <class _BlobType, uint32_t _magic, class _Type>
void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const Maker &maker)
{
for (typename BlobMap::const_iterator it = maker.mPieces.begin(); it != maker.mPieces.end(); ++it)
this->add(it->first, it->second->clone());
}
template <class _BlobType, uint32_t _magic, class _Type>
size_t SuperBlobCore<_BlobType, _magic, _Type>::Maker::size(size_t size1, ...) const
{
unsigned count = mPieces.size();
size_t total = 0;
for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it)
total += it->second->length();
if (size1) {
va_list args;
va_start(args, size1);
do {
count++;
total += size1;
size1 = va_arg(args, size_t);
} while (size1);
va_end(args);
}
return sizeof(SuperBlobCore) + count * sizeof(Index) + total;
}
template <class _BlobType, uint32_t _magic, class _Type>
_BlobType *SuperBlobCore<_BlobType, _magic, _Type>::Maker::make() const
{
Offset pc = sizeof(SuperBlobCore) + mPieces.size() * sizeof(Index);
Offset total = size();
_BlobType *result = (_BlobType *)malloc(total);
if (!result)
UnixError::throwMe(ENOMEM);
result->setup(total, mPieces.size());
unsigned n = 0;
for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) {
result->mIndex[n].type = it->first;
result->mIndex[n].offset = pc;
memcpy(result->at<unsigned char>(pc), it->second, it->second->length());
pc += it->second->length();
n++;
}
secdebug("superblob", "Maker %p assembles %ld blob(s) into %p (size=%d)",
this, mPieces.size(), result, total);
return result;
}
}
#endif //_H_SUPERBLOB