]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/superblob.h
e6b8edc86b4eac6e9b203ff34810f89842c90e69
   2 // SuperBlob - a typed bag of Blobs 
   7 #include <security_utilities/blob.h> 
  15 // A SuperBlob is a Blob that contains multiple sub-Blobs of varying type. 
  16 // The SuperBlob is contiguous and contains a directory of its sub-blobs. 
  17 // A Maker is included. 
  19 // SuperBlobCore lets you define your own SuperBlob type. To just use a generic 
  20 // SuperBlob, use SuperBlob<> below. 
  22 template <class _BlobType
, uint32_t _magic
, class _Type
> 
  23 class SuperBlobCore
: public Blob
<_BlobType
, _magic
> { 
  25         class Maker
; friend class Maker
; 
  29         // echoes from parent BlobCore (the C++ type system is too restrictive here) 
  30         typedef BlobCore::Offset Offset
; 
  31         template <class BlobType
> BlobType 
*at(Offset offset
) { return BlobCore::at
<BlobType
>(offset
); } 
  32         template <class BlobType
> const BlobType 
*at(Offset offset
) const { return BlobCore::at
<BlobType
>(offset
); } 
  34         void setup(size_t size
, unsigned count
) 
  35         { this->initialize(size
); this->mCount 
= count
; } 
  38                 Endian
<Type
> type
;                      // type of sub-Blob 
  39                 Endian
<Offset
> offset
;          // starting offset 
  42         bool validateBlob(size_t maxSize 
= 0) const; 
  44         unsigned count() const { return mCount
; } 
  46         // access by index number 
  47         Type 
type(unsigned n
) const { assert(n 
< mCount
); return mIndex
[n
].type
; } 
  48         const BlobCore 
*blob(unsigned n
) const 
  49                 { assert(n 
< mCount
); return mIndex
[n
].offset 
? at
<const BlobCore
>(mIndex
[n
].offset
) : NULL
; } 
  50         template <class BlobType
> 
  51         const BlobType 
*blob(unsigned n
) const { return BlobType::specific(blob(n
)); } 
  53         // access by index type (assumes unique types) 
  54         const BlobCore 
*find(Type type
) const; 
  55         template <class BlobType
> 
  56         const BlobType 
*find(Type type
) const { return BlobType::specific(find(type
)); } 
  59         Endian
<uint32_t> mCount
;                // number of sub-Blobs following 
  60         Index mIndex
[0];                                // <count> IndexSlot structures 
  61         // followed by sub-Blobs, packed and ordered in an undefined way 
  65 template <class _BlobType
, uint32_t _magic
, class _Type
> 
  66 inline bool SuperBlobCore
<_BlobType
, _magic
, _Type
>::validateBlob(size_t maxSize 
/* = 0 */) const 
  68         unsigned count 
= mCount
; 
  69         size_t ixLimit 
= sizeof(SuperBlobCore
) + count 
* sizeof(Index
); // end of index vector 
  70         if (!BlobCore::validateBlob(_magic
, ixLimit
, maxSize
)) 
  72         for (const Index 
*ix 
= mIndex 
+ count 
- 1; ix 
>= mIndex
; ix
--) { 
  73                 Offset offset 
= ix
->offset
; 
  74                 if (offset
)                                                                                                                                             // if non-null 
  75                         if (offset 
< ixLimit                                                                                                            
// offset not too small 
  76                                 || offset 
+ sizeof(BlobCore
) > this->length()                                                   // fits Blob header (including length field) 
  77                                 || offset 
+ at
<const BlobCore
>(offset
)->length() > this->length())      // fits entire blob 
  85 // A generic SuperBlob ready for use. You still need to specify a magic number. 
  87 template <uint32_t _magic
, class _Type 
= uint32_t> 
  88 class SuperBlob 
: public SuperBlobCore
<SuperBlob
<_magic
, _Type
>, _magic
, _Type
> { 
  92 template <class _BlobType
, uint32_t _magic
, class _Type
> 
  93 const BlobCore 
*SuperBlobCore
<_BlobType
, _magic
, _Type
>::find(Type type
) const 
  95         for (unsigned slot 
= 0; slot 
< mCount
; slot
++) 
  96                 if (mIndex
[slot
].type 
== type
) 
  97                         return mIndex
[slot
].offset 
? at
<const BlobCore
>(mIndex
[slot
].offset
) : NULL
; 
  98         return NULL
;    // not found 
 103 // A SuperBlob::Maker simply assembles multiple Blobs into a single, indexed 
 104 // super-blob. Just add() sub-Blobs by type and call make() to get 
 105 // the result, malloc'ed. A Maker is not resettable. 
 106 // Maker can repeatedly make SuperBlobs from the same (cached) inputs. 
 107 // It can also tell you how big its output will be, given established contents 
 108 // plus (optional) additional sizes of blobs yet to come. 
 110 template <class _BlobType
, uint32_t _magic
, class _Type
> 
 111 class SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker 
{ 
 115         Maker(const Maker 
&src
) 
 117                 for (typename 
BlobMap::iterator it 
= mPieces
.begin(); it 
!= mPieces
.end(); ++it
) 
 118                         mPieces
.insert(make_pair(it
->first
, it
->second
->clone())); 
 123                 for (typename 
BlobMap::iterator it 
= mPieces
.begin(); it 
!= mPieces
.end(); ++it
) 
 127         void add(Type type
, BlobCore 
*blob
);            // takes ownership of blob 
 128         void add(const _BlobType 
*blobs
);                       // copies all blobs 
 129         void add(const Maker 
&maker
);                           // ditto 
 131         bool contains(Type type
) const                          // see if we have this type already 
 132                 { return mPieces
.find(type
) != mPieces
.end(); } 
 133         BlobCore 
*get(Type type
) const 
 135                         typename 
BlobMap::const_iterator it 
= mPieces
.find(type
); 
 136                         return (it 
== mPieces
.end()) ? NULL 
: it
->second
; 
 139 //      size_t size(size_t size1 = 0, ...) const;       // size with optional additional blob sizes 
 140         size_t size(const std::vector
<size_t> &sizes
, size_t size1 
= 0, ...) const; // same with array-of-sizes input 
 141         _BlobType 
*make() const;                                        // create (malloc) and return SuperBlob 
 142         _BlobType 
*operator () () const { return make(); } 
 145         typedef std::map
<Type
, BlobCore 
*> BlobMap
; 
 151 // Add a Blob to a SuperBlob::Maker. 
 152 // This takes ownership of the blob, which must have been malloc'ed. 
 153 // Any previous value set for this Type will be freed immediately. 
 155 template <class _BlobType
, uint32_t _magic
, class _Type
> 
 156 void SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::add(Type type
, BlobCore 
*blob
) 
 158         pair
<typename 
BlobMap::iterator
, bool> r 
= mPieces
.insert(make_pair(type
, blob
)); 
 159         if (!r
.second
) {        // already there 
 160                 secdebug("superblob", "Maker %p replaces type=%d", this, type
); 
 161                 ::free(r
.first
->second
); 
 162                 r
.first
->second 
= blob
; 
 166 template <class _BlobType
, uint32_t _magic
, class _Type
> 
 167 void SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::add(const _BlobType 
*blobs
) 
 169         for (uint32_t ix 
= 0; ix 
< blobs
->mCount
; ix
++) 
 170                 this->add(blobs
->mIndex
[ix
].type
, blobs
->blob(ix
)->clone()); 
 173 template <class _BlobType
, uint32_t _magic
, class _Type
> 
 174 void SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::add(const Maker 
&maker
) 
 176         for (typename 
BlobMap::const_iterator it 
= maker
.mPieces
.begin(); it 
!= maker
.mPieces
.end(); ++it
) 
 177                 this->add(it
->first
, it
->second
->clone()); 
 182 // Calculate the size the new SuperBlob would have, given the contents of the Maker 
 183 // so far, plus additional blobs with the sizes given. 
 185 template <class _BlobType
, uint32_t _magic
, class _Type
> 
 186 size_t SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::size(const std::vector
<size_t> &sizes
, size_t size1
, ...) const 
 188         // count established blobs 
 189         size_t count 
= mPieces
.size(); 
 191         for (auto it 
= mPieces
.begin(); it 
!= mPieces
.end(); ++it
) 
 192                 total 
+= it
->second
->length(); 
 194         // add more blobs from the sizes array 
 195         for (auto it 
= sizes
.begin(); it 
!= sizes
.end(); ++it
) 
 197         count 
+= sizes
.size(); 
 199         // add more blobs from individual sizes specified 
 202                 va_start(args
, size1
); 
 206                         size1 
= va_arg(args
, size_t); 
 211         return sizeof(SuperBlobCore
) + count 
* sizeof(Index
) + total
; 
 216 // Finish SuperBlob construction and return the new, malloc'ed, SuperBlob. 
 217 // This can be done repeatedly. 
 219 template <class _BlobType
, uint32_t _magic
, class _Type
> 
 220 _BlobType 
*SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::make() const 
 222         Offset pc 
= (Offset
)(sizeof(SuperBlobCore
) + mPieces
.size() * sizeof(Index
)); 
 223         Offset total 
= (Offset
)size(vector
<size_t>(), 0); 
 224         _BlobType 
*result 
= (_BlobType 
*)malloc(total
); 
 226                 UnixError::throwMe(ENOMEM
); 
 227         result
->setup(total
, (unsigned)mPieces
.size()); 
 229         for (typename 
BlobMap::const_iterator it 
= mPieces
.begin(); it 
!= mPieces
.end(); ++it
) { 
 230                 result
->mIndex
[n
].type 
= it
->first
; 
 231                 result
->mIndex
[n
].offset 
= pc
; 
 232                 memcpy(result
->template at
<unsigned char>(pc
), it
->second
, it
->second
->length()); 
 233                 pc 
+= it
->second
->length(); 
 236         secdebug("superblob", "Maker %p assembles %ld blob(s) into %p (size=%d)", 
 237                 this, mPieces
.size(), result
, total
); 
 244 #endif //_H_SUPERBLOB