]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/superblob.h
Security-57337.20.44.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
10 namespace 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 //
21 template <class _BlobType, uint32_t _magic, class _Type>
22 class SuperBlobCore: public Blob<_BlobType, _magic> {
23 public:
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
57 private:
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
64 template <class _BlobType, uint32_t _magic, class _Type>
65 inline 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 //
86 template <uint32_t _magic, class _Type = uint32_t>
87 class SuperBlob : public SuperBlobCore<SuperBlob<_magic, _Type>, _magic, _Type> {
88 };
89
90
91 template <class _BlobType, uint32_t _magic, class _Type>
92 const 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 //
109 template <class _BlobType, uint32_t _magic, class _Type>
110 class SuperBlobCore<_BlobType, _magic, _Type>::Maker {
111 public:
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
142 private:
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 //
153 template <class _BlobType, uint32_t _magic, class _Type>
154 void 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
164 template <class _BlobType, uint32_t _magic, class _Type>
165 void 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
171 template <class _BlobType, uint32_t _magic, class _Type>
172 void 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 //
183 template <class _BlobType, uint32_t _magic, class _Type>
184 size_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 //
212 template <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