#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; }
void initialize(Magic magic, size_t length = 0)
{ mMagic = magic; mLength = (uint32_t)length; }
bool validateBlob(Magic magic, size_t minSize = 0, size_t maxSize = 0) const;
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); }
template <class Offset1, class Offset2>
bool contains(Offset1 offset, Offset2 size) const
{ return offset >= 0 && size_t(offset) >= sizeof(BlobCore) && (size_t(offset) + size) <= this->length(); }
template <class Base, class Offset>
bool contains(Base *ptr, Offset size) const
{ return contains(LowLevelMemoryUtilities::difference(ptr, this), size); }
char *stringAt(Offset offset);
const char *stringAt(Offset offset) const;
void *data() { return this; }
const void *data() const { return this; }
void length(size_t size) { mLength = (uint32_t)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, 0); }
static BlobCore *readBlob(int fd) { return readBlob(fd, 0, 0, 0); }
protected:
static BlobCore *readBlob(std::FILE *file, uint32_t magic, size_t minSize, size_t maxSize); static BlobCore *readBlob(int fd, uint32_t magic, size_t minSize, size_t maxSize); static BlobCore *readBlob(int fd, size_t offset, uint32_t magic, size_t minSize, size_t maxSize);
protected:
Endian<uint32_t> mMagic;
Endian<uint32_t> mLength;
};
inline bool BlobCore::validateBlob(Magic magic, size_t minSize , size_t maxSize ) const
{
uint32_t length = this->mLength;
if (magic && magic != this->mMagic) {
errno = EINVAL;
return false;
}
if (minSize ? (length < minSize) : (length < sizeof(BlobCore))) {
errno = EINVAL;
return false;
}
if (maxSize && length > maxSize) {
errno = ENOMEM;
return false;
}
return true;
}
template <class BlobType, uint32_t _magic>
class Blob: public BlobCore {
public:
void initialize(size_t size = 0) { BlobCore::initialize(_magic, size); }
static const Magic typeMagic = _magic;
bool validateBlob() const
{ return BlobCore::validateBlob(_magic, sizeof(BlobType)); }
bool validateBlob(size_t extLength) const
{ return extLength >= sizeof(BlobType) && validateBlob() && mLength == extLength; }
static BlobType *specific(BlobCore *blob, bool unalloc = false)
{
if (BlobType *p = static_cast<BlobType *>(blob)) {
if (p->validateBlob())
return p;
if (unalloc)
::free(p);
}
return NULL;
}
static const BlobType *specific(const BlobCore *blob)
{
const BlobType *p = static_cast<const BlobType *>(blob);
if (p && p->validateBlob())
return p;
return NULL;
}
BlobType *clone() const
{ assert(validateBlob()); return specific(this->BlobCore::clone()); }
static BlobType *readBlob(int fd)
{ return specific(BlobCore::readBlob(fd, _magic, sizeof(BlobType), 0), true); }
static BlobType *readBlob(int fd, size_t offset, size_t maxSize = 0)
{ return specific(BlobCore::readBlob(fd, offset, _magic, sizeof(BlobType), maxSize), true); }
static BlobType *readBlob(std::FILE *file)
{ return specific(BlobCore::readBlob(file, _magic, sizeof(BlobType), 0), true); }
};
class BlobWrapper : public Blob<BlobWrapper, 0xfade0b01> {
public:
static BlobWrapper *alloc(size_t length, Magic magic = BlobWrapper::typeMagic);
static BlobWrapper *alloc(const void *data, size_t length, Magic magic = BlobWrapper::typeMagic);
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