#ifndef _H_BLOB
#define _H_BLOB
#include <security_utilities/endian.h>
#include <security_utilities/memutils.h>
#include <security_utilities/errors.h>
namespace Security {
class BlobCore {
public:
typedef uint32_t Offset;
typedef uint32_t Magic;
Magic magic() const { return mMagic; }
size_t length() const { return mLength; }
bool validateBlob(Magic magic, size_t blobLength) const
{
return mMagic == magic && mLength >= blobLength;
}
template <class T, class Offset>
T *at(Offset offset)
{ return LowLevelMemoryUtilities::increment<T>(this, offset); }
template <class T, class Offset>
const T *at(Offset offset) const
{ return LowLevelMemoryUtilities::increment<const T>(this, offset); }
void *data() { return this; }
const void *data() const { return this; }
void length(size_t size) { mLength = size; }
BlobCore *clone() const
{
if (BlobCore *copy = (BlobCore *)malloc(this->length())) {
memcpy(copy, this, this->length());
return copy;
}
UnixError::throwMe(ENOMEM);
}
template <class BlobType>
bool is() const { return magic() == BlobType::typeMagic; }
static BlobCore *readBlob(std::FILE *file) { return readBlob(file, 0, 0); }
static BlobCore *readBlob(int fd) { return readBlob(fd, 0, 0); }
protected:
static BlobCore *readBlob(std::FILE *file, uint32_t magic, size_t blobSize);
static BlobCore *readBlob(int fd, uint32_t magic, size_t blobSize);
protected:
Endian<uint32_t> mMagic;
Endian<uint32_t> mLength;
};
template <class BlobType, uint32_t _magic>
class Blob: public BlobCore {
public:
void initialize(size_t size = 0) { mMagic = _magic; mLength = size; }
static const Magic typeMagic = _magic;
bool validateBlob() const
{
return BlobCore::validateBlob(_magic, sizeof(BlobType));
}
bool validateBlob(size_t extLength) const
{
return validateBlob() && mLength == extLength;
}
static BlobType *specific(BlobCore *blob)
{
BlobType *p = static_cast<BlobType *>(blob);
if (p)
assert(p->validateBlob());
return p;
}
static const BlobType *specific(const BlobCore *blob)
{
const BlobType *p = static_cast<const BlobType *>(blob);
if (p)
assert(p->validateBlob());
return p;
}
BlobType *clone() const
{ assert(validateBlob()); return specific(this->BlobCore::clone()); }
static BlobType *readBlob(int fd)
{
return specific(BlobCore::readBlob(fd, _magic, sizeof(BlobType)));
}
static BlobType *readBlob(std::FILE *file)
{
return specific(BlobCore::readBlob(file, _magic, sizeof(BlobType)));
}
};
class BlobWrapper : public Blob<BlobWrapper, 0xfade0b01> {
public:
static BlobWrapper *alloc(size_t length);
static BlobWrapper *alloc(const void *data, size_t length);
unsigned char dataArea[0];
void *data() { return dataArea; }
const void *data() const { return dataArea; }
size_t length() const { return BlobCore::length() - sizeof(BlobCore); }
};
}
#endif //_H_BLOB