]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/superblob.h
2 // SuperBlob - a typed bag of Blobs
7 #include <security_utilities/blob.h>
16 // A SuperBlob is a Blob that contains multiple sub-Blobs of varying type.
17 // The SuperBlob is contiguous and contains a directory of its sub-blobs.
18 // A Maker is included.
20 // SuperBlobCore lets you define your own SuperBlob type. To just use a generic
21 // SuperBlob, use SuperBlob<> below.
23 template <class _BlobType
, uint32_t _magic
, class _Type
>
24 class SuperBlobCore
: public Blob
<_BlobType
, _magic
> {
26 class Maker
; friend class Maker
;
30 // echoes from parent BlobCore (the C++ type system is too restrictive here)
31 typedef BlobCore::Offset Offset
;
32 template <class BlobType
> BlobType
*at(Offset offset
) { return BlobCore::at
<BlobType
>(offset
); }
33 template <class BlobType
> const BlobType
*at(Offset offset
) const { return BlobCore::at
<BlobType
>(offset
); }
35 void setup(size_t size
, unsigned count
)
36 { this->initialize(size
); this->mCount
= count
; }
39 Endian
<Type
> type
; // type of sub-Blob
40 Endian
<Offset
> offset
; // starting offset
43 bool validateBlob(size_t maxSize
= 0) const;
44 bool strictValidateBlob(size_t maxSize
= 0) const;
46 unsigned count() const { return mCount
; }
48 // access by index number
49 Type
type(unsigned n
) const { assert(n
< mCount
); return mIndex
[n
].type
; }
50 const BlobCore
*blob(unsigned n
) const
51 { assert(n
< mCount
); return mIndex
[n
].offset
? at
<const BlobCore
>(mIndex
[n
].offset
) : NULL
; }
52 template <class BlobType
>
53 const BlobType
*blob(unsigned n
) const { return BlobType::specific(blob(n
)); }
55 // access by index type (assumes unique types)
56 const BlobCore
*find(Type type
) const;
57 template <class BlobType
>
58 const BlobType
*find(Type type
) const { return BlobType::specific(find(type
)); }
61 Endian
<uint32_t> mCount
; // number of sub-Blobs following
62 Index mIndex
[0]; // <count> IndexSlot structures
63 // followed by sub-Blobs, packed and ordered in an undefined way
67 template <class _BlobType
, uint32_t _magic
, class _Type
>
68 inline bool SuperBlobCore
<_BlobType
, _magic
, _Type
>::validateBlob(size_t maxSize
/* = 0 */) const
70 unsigned count
= mCount
;
71 size_t ixLimit
= sizeof(SuperBlobCore
) + count
* sizeof(Index
); // end of index vector
72 if (!BlobCore::validateBlob(_magic
, ixLimit
, maxSize
))
74 for (const Index
*ix
= mIndex
+ count
- 1; ix
>= mIndex
; ix
--) {
75 Offset offset
= ix
->offset
;
76 if (offset
) // if non-null
77 if (offset
< ixLimit
// offset not too small
78 || offset
+ sizeof(BlobCore
) > this->length() // fits Blob header (including length field)
79 || offset
+ at
<const BlobCore
>(offset
)->length() > this->length()) // fits entire blob
88 _SBRange(size_t b
, size_t len
) : base(b
), end(b
+len
) { }
89 bool operator < (const _SBRange
& other
) const { return this->base
< other
.base
; }
92 template <class _BlobType
, uint32_t _magic
, class _Type
>
93 inline bool SuperBlobCore
<_BlobType
, _magic
, _Type
>::strictValidateBlob(size_t size
/* = 0 */) const
95 if (!validateBlob(size
)) // verifies in-bound sub-blobs
97 unsigned count
= mCount
;
99 return this->length() == sizeof(SuperBlobCore
); // nothing in here
101 std::vector
<_SBRange
> ranges
;
102 for (unsigned ix
= 0; ix
< count
; ++ix
)
103 ranges
.push_back(_SBRange(mIndex
[ix
].offset
, this->blob(ix
)->length()));
104 sort(ranges
.begin(), ranges
.end());
105 if (ranges
[0].base
!= sizeof(SuperBlobCore
) + count
* sizeof(Index
))
106 return false; // start anchor
107 for (unsigned ix
= 1; ix
< count
; ++ix
)
108 if (ranges
[ix
].base
!= ranges
[ix
-1].end
) // nothing in between
110 return ranges
[count
-1].end
== this->length(); // end anchor
115 // A generic SuperBlob ready for use. You still need to specify a magic number.
117 template <uint32_t _magic
, class _Type
= uint32_t>
118 class SuperBlob
: public SuperBlobCore
<SuperBlob
<_magic
, _Type
>, _magic
, _Type
> {
122 template <class _BlobType
, uint32_t _magic
, class _Type
>
123 const BlobCore
*SuperBlobCore
<_BlobType
, _magic
, _Type
>::find(Type type
) const
125 for (unsigned slot
= 0; slot
< mCount
; slot
++)
126 if (mIndex
[slot
].type
== type
)
127 return mIndex
[slot
].offset
? at
<const BlobCore
>(mIndex
[slot
].offset
) : NULL
;
128 return NULL
; // not found
133 // A SuperBlob::Maker simply assembles multiple Blobs into a single, indexed
134 // super-blob. Just add() sub-Blobs by type and call make() to get
135 // the result, malloc'ed. A Maker is not resettable.
136 // Maker can repeatedly make SuperBlobs from the same (cached) inputs.
137 // It can also tell you how big its output will be, given established contents
138 // plus (optional) additional sizes of blobs yet to come.
140 template <class _BlobType
, uint32_t _magic
, class _Type
>
141 class SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker
{
145 Maker(const Maker
&src
)
147 for (typename
BlobMap::iterator it
= mPieces
.begin(); it
!= mPieces
.end(); ++it
)
148 mPieces
.insert(make_pair(it
->first
, it
->second
->clone()));
153 for (typename
BlobMap::iterator it
= mPieces
.begin(); it
!= mPieces
.end(); ++it
)
157 void add(Type type
, BlobCore
*blob
); // takes ownership of blob
158 void add(const _BlobType
*blobs
); // copies all blobs
159 void add(const Maker
&maker
); // ditto
161 bool contains(Type type
) const // see if we have this type already
162 { return mPieces
.find(type
) != mPieces
.end(); }
163 BlobCore
*get(Type type
) const
165 typename
BlobMap::const_iterator it
= mPieces
.find(type
);
166 return (it
== mPieces
.end()) ? NULL
: it
->second
;
169 // size_t size(size_t size1 = 0, ...) const; // size with optional additional blob sizes
170 size_t size(const std::vector
<size_t> &sizes
, size_t size1
= 0, ...) const; // same with array-of-sizes input
171 _BlobType
*make() const; // create (malloc) and return SuperBlob
172 _BlobType
*operator () () const { return make(); }
175 typedef std::map
<Type
, BlobCore
*> BlobMap
;
181 // Add a Blob to a SuperBlob::Maker.
182 // This takes ownership of the blob, which must have been malloc'ed.
183 // Any previous value set for this Type will be freed immediately.
185 template <class _BlobType
, uint32_t _magic
, class _Type
>
186 void SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::add(Type type
, BlobCore
*blob
)
188 pair
<typename
BlobMap::iterator
, bool> r
= mPieces
.insert(make_pair(type
, blob
));
189 if (!r
.second
) { // already there
190 secinfo("superblob", "Maker %p replaces type=%d", this, type
);
191 ::free(r
.first
->second
);
192 r
.first
->second
= blob
;
196 template <class _BlobType
, uint32_t _magic
, class _Type
>
197 void SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::add(const _BlobType
*blobs
)
199 for (uint32_t ix
= 0; ix
< blobs
->mCount
; ix
++)
200 this->add(blobs
->mIndex
[ix
].type
, blobs
->blob(ix
)->clone());
203 template <class _BlobType
, uint32_t _magic
, class _Type
>
204 void SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::add(const Maker
&maker
)
206 for (typename
BlobMap::const_iterator it
= maker
.mPieces
.begin(); it
!= maker
.mPieces
.end(); ++it
)
207 this->add(it
->first
, it
->second
->clone());
212 // Calculate the size the new SuperBlob would have, given the contents of the Maker
213 // so far, plus additional blobs with the sizes given.
215 template <class _BlobType
, uint32_t _magic
, class _Type
>
216 size_t SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::size(const std::vector
<size_t> &sizes
, size_t size1
, ...) const
218 // count established blobs
219 size_t count
= mPieces
.size();
221 for (auto it
= mPieces
.begin(); it
!= mPieces
.end(); ++it
)
222 total
+= it
->second
->length();
224 // add more blobs from the sizes array
225 for (auto it
= sizes
.begin(); it
!= sizes
.end(); ++it
)
227 count
+= sizes
.size();
229 // add more blobs from individual sizes specified
232 va_start(args
, size1
);
236 size1
= va_arg(args
, size_t);
241 return sizeof(SuperBlobCore
) + count
* sizeof(Index
) + total
;
246 // Finish SuperBlob construction and return the new, malloc'ed, SuperBlob.
247 // This can be done repeatedly.
249 template <class _BlobType
, uint32_t _magic
, class _Type
>
250 _BlobType
*SuperBlobCore
<_BlobType
, _magic
, _Type
>::Maker::make() const
252 Offset pc
= (Offset
)(sizeof(SuperBlobCore
) + mPieces
.size() * sizeof(Index
));
253 Offset total
= (Offset
)size(vector
<size_t>(), 0);
254 _BlobType
*result
= (_BlobType
*)malloc(total
);
256 UnixError::throwMe(ENOMEM
);
257 result
->setup(total
, (unsigned)mPieces
.size());
259 for (typename
BlobMap::const_iterator it
= mPieces
.begin(); it
!= mPieces
.end(); ++it
) {
260 result
->mIndex
[n
].type
= it
->first
;
261 result
->mIndex
[n
].offset
= pc
;
262 memcpy(result
->template at
<unsigned char>(pc
), it
->second
, it
->second
->length());
263 pc
+= it
->second
->length();
267 os
<< "Maker " << this << " assembles " << mPieces
.size() << " blob(s) into " << result
268 << " (size=" << total
<< ")";
269 secinfo("superblob", "%s", os
.str().c_str());
276 #endif //_H_SUPERBLOB