]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/superblob.h
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / superblob.h
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 #include <vector>
10
11 namespace Security {
12
13
14 //
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.
18 //
19 // SuperBlobCore lets you define your own SuperBlob type. To just use a generic
20 // SuperBlob, use SuperBlob<> below.
21 //
22 template <class _BlobType, uint32_t _magic, class _Type>
23 class SuperBlobCore: public Blob<_BlobType, _magic> {
24 public:
25 class Maker; friend class Maker;
26
27 typedef _Type Type;
28
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); }
33
34 void setup(size_t size, unsigned count)
35 { this->initialize(size); this->mCount = count; }
36
37 struct Index {
38 Endian<Type> type; // type of sub-Blob
39 Endian<Offset> offset; // starting offset
40 };
41
42 bool validateBlob(size_t maxSize = 0) const;
43
44 unsigned count() const { return mCount; }
45
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)); }
52
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)); }
57
58 private:
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
62 };
63
64
65 template <class _BlobType, uint32_t _magic, class _Type>
66 inline bool SuperBlobCore<_BlobType, _magic, _Type>::validateBlob(size_t maxSize /* = 0 */) const
67 {
68 unsigned count = mCount;
69 size_t ixLimit = sizeof(SuperBlobCore) + count * sizeof(Index); // end of index vector
70 if (!BlobCore::validateBlob(_magic, ixLimit, maxSize))
71 return false;
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
78 return false;
79 }
80 return true;
81 }
82
83
84 //
85 // A generic SuperBlob ready for use. You still need to specify a magic number.
86 //
87 template <uint32_t _magic, class _Type = uint32_t>
88 class SuperBlob : public SuperBlobCore<SuperBlob<_magic, _Type>, _magic, _Type> {
89 };
90
91
92 template <class _BlobType, uint32_t _magic, class _Type>
93 const BlobCore *SuperBlobCore<_BlobType, _magic, _Type>::find(Type type) const
94 {
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
99 }
100
101
102 //
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.
109 //
110 template <class _BlobType, uint32_t _magic, class _Type>
111 class SuperBlobCore<_BlobType, _magic, _Type>::Maker {
112 public:
113 Maker() { }
114
115 Maker(const Maker &src)
116 {
117 for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
118 mPieces.insert(make_pair(it->first, it->second->clone()));
119 }
120
121 ~Maker()
122 {
123 for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
124 ::free(it->second);
125 }
126
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
130
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
134 {
135 typename BlobMap::const_iterator it = mPieces.find(type);
136 return (it == mPieces.end()) ? NULL : it->second;
137 }
138
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(); }
143
144 private:
145 typedef std::map<Type, BlobCore *> BlobMap;
146 BlobMap mPieces;
147 };
148
149
150 //
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.
154 //
155 template <class _BlobType, uint32_t _magic, class _Type>
156 void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(Type type, BlobCore *blob)
157 {
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;
163 }
164 }
165
166 template <class _BlobType, uint32_t _magic, class _Type>
167 void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const _BlobType *blobs)
168 {
169 for (uint32_t ix = 0; ix < blobs->mCount; ix++)
170 this->add(blobs->mIndex[ix].type, blobs->blob(ix)->clone());
171 }
172
173 template <class _BlobType, uint32_t _magic, class _Type>
174 void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const Maker &maker)
175 {
176 for (typename BlobMap::const_iterator it = maker.mPieces.begin(); it != maker.mPieces.end(); ++it)
177 this->add(it->first, it->second->clone());
178 }
179
180
181 //
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.
184 //
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
187 {
188 // count established blobs
189 size_t count = mPieces.size();
190 size_t total = 0;
191 for (auto it = mPieces.begin(); it != mPieces.end(); ++it)
192 total += it->second->length();
193
194 // add more blobs from the sizes array
195 for (auto it = sizes.begin(); it != sizes.end(); ++it)
196 total += *it;
197 count += sizes.size();
198
199 // add more blobs from individual sizes specified
200 if (size1) {
201 va_list args;
202 va_start(args, size1);
203 do {
204 count++;
205 total += size1;
206 size1 = va_arg(args, size_t);
207 } while (size1);
208 va_end(args);
209 }
210
211 return sizeof(SuperBlobCore) + count * sizeof(Index) + total;
212 }
213
214
215 //
216 // Finish SuperBlob construction and return the new, malloc'ed, SuperBlob.
217 // This can be done repeatedly.
218 //
219 template <class _BlobType, uint32_t _magic, class _Type>
220 _BlobType *SuperBlobCore<_BlobType, _magic, _Type>::Maker::make() const
221 {
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);
225 if (!result)
226 UnixError::throwMe(ENOMEM);
227 result->setup(total, (unsigned)mPieces.size());
228 unsigned n = 0;
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();
234 n++;
235 }
236 secdebug("superblob", "Maker %p assembles %ld blob(s) into %p (size=%d)",
237 this, mPieces.size(), result, total);
238 return result;
239 }
240
241
242 } // Security
243
244 #endif //_H_SUPERBLOB