1// 2// SuperBlob - a typed bag of Blobs 3// 4#ifndef _H_SUPERBLOB 5#define _H_SUPERBLOB 6 7#include <security_utilities/blob.h> 8#include <map> 9 10namespace Security { 11 12 13// 14// A SuperBlob is a Blob that contains multiple sub-Blobs of varying type. 15// The SuperBlob is contiguous and contains a directory of its sub-blobs. 16// A Maker is included. 17// 18// SuperBlobCore lets you define your own SuperBlob type. To just use a generic 19// SuperBlob, use SuperBlob<> below. 20// 21template <class _BlobType, uint32_t _magic, class _Type> 22class SuperBlobCore: public Blob<_BlobType, _magic> { 23public: 24 class Maker; friend class Maker; 25 26 typedef _Type Type; 27 28 // echoes from parent BlobCore (the C++ type system is too restrictive here) 29 typedef BlobCore::Offset Offset; 30 template <class BlobType> BlobType *at(Offset offset) { return BlobCore::at<BlobType>(offset); } 31 template <class BlobType> const BlobType *at(Offset offset) const { return BlobCore::at<BlobType>(offset); } 32 33 void setup(size_t size, unsigned count) 34 { this->initialize(size); this->mCount = count; } 35 36 struct Index { 37 Endian<Type> type; // type of sub-Blob 38 Endian<Offset> offset; // starting offset 39 }; 40 41 bool validateBlob(size_t maxSize = 0) const; 42 43 unsigned count() const { return mCount; } 44 45 // access by index number 46 Type type(unsigned n) const { assert(n < mCount); return mIndex[n].type; } 47 const BlobCore *blob(unsigned n) const 48 { assert(n < mCount); return mIndex[n].offset ? at<const BlobCore>(mIndex[n].offset) : NULL; } 49 template <class BlobType> 50 const BlobType *blob(unsigned n) const { return BlobType::specific(blob(n)); } 51 52 // access by index type (assumes unique types) 53 const BlobCore *find(Type type) const; 54 template <class BlobType> 55 const BlobType *find(Type type) const { return BlobType::specific(find(type)); } 56 57private: 58 Endian<uint32_t> mCount; // number of sub-Blobs following 59 Index mIndex[0]; // <count> IndexSlot structures 60 // followed by sub-Blobs, packed and ordered in an undefined way 61}; 62 63 64template <class _BlobType, uint32_t _magic, class _Type> 65inline bool SuperBlobCore<_BlobType, _magic, _Type>::validateBlob(size_t maxSize /* = 0 */) const 66{ 67 unsigned count = mCount; 68 size_t ixLimit = sizeof(SuperBlobCore) + count * sizeof(Index); // end of index vector 69 if (!BlobCore::validateBlob(_magic, ixLimit, maxSize)) 70 return false; 71 for (const Index *ix = mIndex + count - 1; ix >= mIndex; ix--) { 72 Offset offset = ix->offset; 73 if (offset) // if non-null 74 if (offset < ixLimit // offset not too small 75 || offset + sizeof(BlobCore) > this->length() // fits Blob header (including length field) 76 || offset + at<const BlobCore>(offset)->length() > this->length()) // fits entire blob 77 return false; 78 } 79 return true; 80} 81 82 83// 84// A generic SuperBlob ready for use. You still need to specify a magic number. 85// 86template <uint32_t _magic, class _Type = uint32_t> 87class SuperBlob : public SuperBlobCore<SuperBlob<_magic, _Type>, _magic, _Type> { 88}; 89 90 91template <class _BlobType, uint32_t _magic, class _Type> 92const BlobCore *SuperBlobCore<_BlobType, _magic, _Type>::find(Type type) const 93{ 94 for (unsigned slot = 0; slot < mCount; slot++) 95 if (mIndex[slot].type == type) 96 return mIndex[slot].offset ? at<const BlobCore>(mIndex[slot].offset) : NULL; 97 return NULL; // not found 98} 99 100 101// 102// A SuperBlob::Maker simply assembles multiple Blobs into a single, indexed 103// super-blob. Just add() sub-Blobs by type and call make() to get 104// the result, malloc'ed. A Maker is not resettable. 105// Maker can repeatedly make SuperBlobs from the same (cached) inputs. 106// It can also tell you how big its output will be, given established contents 107// plus (optional) additional sizes of blobs yet to come. 108// 109template <class _BlobType, uint32_t _magic, class _Type> 110class SuperBlobCore<_BlobType, _magic, _Type>::Maker { 111public: 112 Maker() { } 113 114 Maker(const Maker &src) 115 { 116 for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it) 117 mPieces.insert(make_pair(it->first, it->second->clone())); 118 } 119 120 ~Maker() 121 { 122 for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it) 123 ::free(it->second); 124 } 125 126 void add(Type type, BlobCore *blob); // takes ownership of blob 127 void add(const _BlobType *blobs); // copies all blobs 128 void add(const Maker &maker); // ditto 129 130 bool contains(Type type) const // see if we have this type already 131 { return mPieces.find(type) != mPieces.end(); } 132 BlobCore *get(Type type) const 133 { 134 typename BlobMap::const_iterator it = mPieces.find(type); 135 return (it == mPieces.end()) ? NULL : it->second; 136 } 137 138 size_t size(size_t size1 = 0, ...) const; // size with optional additional blob sizes 139 _BlobType *make() const; // create (malloc) and return SuperBlob 140 _BlobType *operator () () const { return make(); } 141 142private: 143 typedef std::map<Type, BlobCore *> BlobMap; 144 BlobMap mPieces; 145}; 146 147 148// 149// Add a Blob to a SuperBlob::Maker. 150// This takes ownership of the blob, which must have been malloc'ed. 151// Any previous value set for this Type will be freed immediately. 152// 153template <class _BlobType, uint32_t _magic, class _Type> 154void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(Type type, BlobCore *blob) 155{ 156 pair<typename BlobMap::iterator, bool> r = mPieces.insert(make_pair(type, blob)); 157 if (!r.second) { // already there 158 secdebug("superblob", "Maker %p replaces type=%d", this, type); 159 ::free(r.first->second); 160 r.first->second = blob; 161 } 162} 163 164template <class _BlobType, uint32_t _magic, class _Type> 165void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const _BlobType *blobs) 166{ 167 for (uint32_t ix = 0; ix < blobs->mCount; ix++) 168 this->add(blobs->mIndex[ix].type, blobs->blob(ix)->clone()); 169} 170 171template <class _BlobType, uint32_t _magic, class _Type> 172void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const Maker &maker) 173{ 174 for (typename BlobMap::const_iterator it = maker.mPieces.begin(); it != maker.mPieces.end(); ++it) 175 this->add(it->first, it->second->clone()); 176} 177 178 179// 180// Calculate the size the new SuperBlob would have, given the contents of the Maker 181// so far, plus additional blobs with the sizes given. 182// 183template <class _BlobType, uint32_t _magic, class _Type> 184size_t SuperBlobCore<_BlobType, _magic, _Type>::Maker::size(size_t size1, ...) const 185{ 186 // count established blobs 187 size_t count = mPieces.size(); 188 size_t total = 0; 189 for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) 190 total += it->second->length(); 191 192 // add preview blob sizes to calculation (if any) 193 if (size1) { 194 va_list args; 195 va_start(args, size1); 196 do { 197 count++; 198 total += size1; 199 size1 = va_arg(args, size_t); 200 } while (size1); 201 va_end(args); 202 } 203 204 return sizeof(SuperBlobCore) + count * sizeof(Index) + total; 205} 206 207 208// 209// Finish SuperBlob construction and return the new, malloc'ed, SuperBlob. 210// This can be done repeatedly. 211// 212template <class _BlobType, uint32_t _magic, class _Type> 213_BlobType *SuperBlobCore<_BlobType, _magic, _Type>::Maker::make() const 214{ 215 Offset pc = (Offset)(sizeof(SuperBlobCore) + mPieces.size() * sizeof(Index)); 216 Offset total = (Offset)size(); 217 _BlobType *result = (_BlobType *)malloc(total); 218 if (!result) 219 UnixError::throwMe(ENOMEM); 220 result->setup(total, (unsigned)mPieces.size()); 221 unsigned n = 0; 222 for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) { 223 result->mIndex[n].type = it->first; 224 result->mIndex[n].offset = pc; 225 memcpy(result->template at<unsigned char>(pc), it->second, it->second->length()); 226 pc += it->second->length(); 227 n++; 228 } 229 secdebug("superblob", "Maker %p assembles %ld blob(s) into %p (size=%d)", 230 this, mPieces.size(), result, total); 231 return result; 232} 233 234 235} // Security 236 237#endif //_H_SUPERBLOB 238