]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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> | |
e3d460c9 | 9 | #include <vector> |
b1ab9ed8 A |
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 | ||
e3d460c9 A |
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 | |
b1ab9ed8 A |
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> | |
e3d460c9 | 186 | size_t SuperBlobCore<_BlobType, _magic, _Type>::Maker::size(const std::vector<size_t> &sizes, size_t size1, ...) const |
b1ab9ed8 A |
187 | { |
188 | // count established blobs | |
427c49bc | 189 | size_t count = mPieces.size(); |
b1ab9ed8 | 190 | size_t total = 0; |
e3d460c9 | 191 | for (auto it = mPieces.begin(); it != mPieces.end(); ++it) |
b1ab9ed8 | 192 | total += it->second->length(); |
e3d460c9 A |
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(); | |
b1ab9ed8 | 198 | |
e3d460c9 | 199 | // add more blobs from individual sizes specified |
b1ab9ed8 A |
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 | { | |
427c49bc | 222 | Offset pc = (Offset)(sizeof(SuperBlobCore) + mPieces.size() * sizeof(Index)); |
e3d460c9 | 223 | Offset total = (Offset)size(vector<size_t>(), 0); |
b1ab9ed8 A |
224 | _BlobType *result = (_BlobType *)malloc(total); |
225 | if (!result) | |
226 | UnixError::throwMe(ENOMEM); | |
427c49bc | 227 | result->setup(total, (unsigned)mPieces.size()); |
b1ab9ed8 A |
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; | |
427c49bc | 232 | memcpy(result->template at<unsigned char>(pc), it->second, it->second->length()); |
b1ab9ed8 A |
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 |