]>
Commit | Line | Data |
---|---|---|
bac41a7b A |
1 | /* |
2 | * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. | |
3 | * | |
4 | * The contents of this file constitute Original Code as defined in and are | |
5 | * subject to the Apple Public Source License Version 1.2 (the 'License'). | |
6 | * You may not use this file except in compliance with the License. Please obtain | |
7 | * a copy of the License at http://www.apple.com/publicsource and read it before | |
8 | * using this file. | |
9 | * | |
10 | * This Original Code and all software distributed under the License are | |
11 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS | |
12 | * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT | |
13 | * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
14 | * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the | |
15 | * specific language governing rights and limitations under the License. | |
16 | */ | |
17 | ||
18 | ||
19 | // | |
20 | // cssmdata.h -- Manager different CssmData types | |
21 | // | |
22 | #ifndef _H_CDSA_UTILITIES_CSSMDATA | |
23 | #define _H_CDSA_UTILITIES_CSSMDATA | |
24 | ||
25 | #include <Security/utilities.h> | |
26 | #include <Security/cssmalloc.h> | |
27 | #include <Security/refcount.h> | |
28 | ||
bac41a7b | 29 | |
29654253 A |
30 | namespace Security { |
31 | ||
32 | ||
33 | // | |
34 | // A convenient way to make a CssmData from a (const) string. | |
35 | // Note that the underlying string is not memory-managed, so it | |
36 | // should either be static or of sufficient (immutable) lifetime. | |
37 | // | |
38 | class StringData : public CssmData { | |
39 | public: | |
40 | StringData(const char *s) : CssmData(const_cast<char *>(s), strlen(s)) { } | |
41 | }; | |
42 | ||
43 | ||
44 | // | |
45 | // A CssmData bundled up with a data buffer it refers to | |
46 | // | |
47 | template <size_t size> | |
48 | struct DataBuffer : public CssmData { | |
49 | unsigned char buffer[size]; | |
50 | DataBuffer() : CssmData(buffer, size) { } | |
51 | }; | |
52 | ||
53 | ||
54 | // | |
55 | // Comparing CssmDatas for equality. | |
56 | // Note: No ordering is established here. | |
57 | // Both CSSM_DATAs have to exist. | |
58 | // | |
59 | bool operator == (const CSSM_DATA &d1, const CSSM_DATA &d2); | |
60 | inline bool operator != (const CSSM_DATA &d1, const CSSM_DATA &d2) | |
61 | { return !(d1 == d2); } | |
62 | ||
bac41a7b A |
63 | |
64 | // | |
65 | // The following pseudo-code describes what (at minimum) is required for a class | |
66 | // to be a "PseudoData". PseudoData arguments are used in templates. | |
67 | // | |
68 | // class PseudoData { | |
69 | // void *data() const ... | |
70 | // size_t length() const ... | |
71 | // operator const CssmData &() const ... | |
72 | // } | |
73 | // | |
29654253 | 74 | // All this can be satisfied, of course, by inheriting from CssmData. |
bac41a7b A |
75 | // |
76 | ||
77 | ||
78 | // | |
79 | // A common virtual parent for CssmData-like objects that actively manage the | |
80 | // allocation status of their data blob. Note that this is about allocating | |
81 | // the data(), not the CssmData structure itself. | |
82 | // The ManagedData layer provides for little active memory management, since | |
83 | // the underlying strategies are potentially very disparate. It does however | |
84 | // have a well defined interface for *yielding up* its data for copying or transfer. | |
85 | // | |
86 | class CssmManagedData { | |
87 | public: | |
88 | CssmManagedData(CssmAllocator &alloc) : allocator(alloc) { } | |
89 | virtual ~CssmManagedData(); | |
90 | ||
91 | CssmAllocator &allocator; | |
92 | ||
93 | virtual operator const CssmData & () const { return get(); } | |
94 | template <class T> T *data() const { return reinterpret_cast<T *>(data()); } | |
95 | void *data() const { return get().data(); } | |
96 | size_t length() const { return get().length(); } | |
97 | ||
98 | virtual CssmData &get() const throw() = 0; // get shared copy, no ownership change | |
99 | virtual CssmData release() = 0; // give up copy, ownership is transferred | |
100 | virtual void reset() = 0; // give up copy, data is discarded | |
101 | }; | |
102 | ||
103 | ||
104 | // | |
105 | // A CssmOwnedData is a CssmManagedData that unilaterally owns its data storage. | |
106 | // It has its CssmData object provided during construction. | |
107 | // | |
108 | class CssmOwnedData : public CssmManagedData { | |
109 | public: | |
110 | CssmOwnedData(CssmAllocator &alloc, CssmData &mine) : CssmManagedData(alloc), referent(mine) { } | |
111 | ||
112 | CssmOwnedData(CssmAllocator &alloc, CSSM_DATA &mine) | |
113 | : CssmManagedData(alloc), referent(CssmData::overlay(mine)) { referent.clear(); } | |
114 | ||
115 | // | |
116 | // Basic retrievals (this echoes features of CssmData) | |
117 | // | |
118 | operator void * () const { return referent; } | |
119 | operator char * () const { return referent; } | |
120 | operator signed char * () const { return referent; } | |
121 | operator unsigned char * () const { return referent; } | |
122 | ||
123 | operator bool () const { return referent; } | |
124 | bool operator ! () const { return !referent; } | |
125 | ||
126 | size_t length() const { return referent.length(); } | |
127 | ||
128 | ||
129 | // | |
130 | // Basic allocators | |
131 | // | |
132 | void *malloc(size_t len) | |
133 | { | |
134 | // pseudo-atomic reallocation semantics | |
135 | CssmAutoPtr<uint8> alloc(allocator, allocator.malloc<uint8>(len)); | |
136 | reset(); | |
137 | return referent = CssmData(alloc.release(), len); | |
138 | } | |
139 | ||
140 | void *realloc(size_t newLen) | |
141 | { | |
142 | // CssmAllocator::realloc() should be pseudo-atomic (i.e. throw on error) | |
143 | return referent = CssmData(allocator.realloc<uint8>(referent.data(), newLen), newLen); | |
144 | } | |
145 | ||
146 | void length(size_t len) { realloc(len); } | |
147 | ||
148 | ||
149 | // | |
150 | // Manipulate existing data | |
151 | // | |
152 | void *append(const void *addData, size_t addLength) | |
153 | { | |
154 | size_t oldLength = length(); | |
155 | realloc(oldLength + addLength); | |
156 | return memcpy(referent.at(oldLength), addData, addLength); | |
157 | } | |
158 | ||
159 | void *append(const CssmData &data) | |
160 | { return append(data.data(), data.length()); } | |
161 | ||
162 | // | |
163 | // set() replaces current data with new, taking over ownership to the extent possible. | |
164 | // | |
165 | template <class T> | |
166 | void set(T *data, size_t length) | |
167 | { | |
168 | // assume that data was allocated by our allocator -- we can't be sure | |
169 | reset(); | |
170 | referent = CssmData(data, length); | |
171 | } | |
172 | ||
173 | void set(CssmManagedData &source); | |
174 | void set(const CSSM_DATA &source) { set(source.Data, source.Length); } | |
175 | // NOTE: General template set() cannot be used because all subclasses of CssmManagedData | |
176 | // need to receive the special handling above. Use set(*.data(), *.length()) instead. | |
177 | ||
178 | ||
179 | // | |
180 | // copy() replaces current data with new, making a copy and leaving | |
181 | // the source intact. | |
182 | // | |
183 | template <class T> | |
184 | void copy(const T *data, size_t length) | |
185 | { | |
186 | // don't leave any open windows for Mr. Murphy | |
187 | CssmAutoPtr<void> newData(allocator, memcpy(allocator.malloc(length), data, length)); | |
188 | reset(); | |
189 | referent = CssmData(newData.release(), length); | |
190 | } | |
191 | ||
192 | void copy(const CssmData &source) | |
193 | { if (&source != &referent) copy(source.data(), source.length()); } | |
194 | void copy(const CSSM_DATA &source) | |
195 | { if (&source != &referent) copy(source.Data, source.Length); } | |
196 | void copy(CssmManagedData &source) { copy(source.get()); } | |
197 | template <class Data> | |
198 | void copy(const Data &source) { copy(source.data(), source.length()); } | |
199 | ||
200 | ||
201 | // | |
202 | // Assignment conservatively uses copy if allocator unknown, set if known | |
203 | // | |
204 | void operator = (CssmManagedData &source) { set(source); } | |
205 | void operator = (CssmOwnedData &source) { set(source); } | |
206 | void operator = (const CSSM_DATA &source) { copy(source); } | |
207 | ||
208 | CssmData &get() const throw() { return referent; } | |
209 | ||
210 | protected: | |
211 | CssmData &referent; | |
212 | }; | |
213 | ||
214 | ||
215 | // | |
216 | // A CssmAutoData is a CssmOwnedData that includes its CssmData object. | |
217 | // This is the very simple case: The object includes ownership, data object, | |
218 | // and data storage. | |
219 | // | |
220 | class CssmAutoData : public CssmOwnedData { | |
221 | public: | |
222 | CssmAutoData(CssmAllocator &alloc) : CssmOwnedData(alloc, mData) { } | |
223 | ||
224 | template <class Data> | |
225 | CssmAutoData(CssmAllocator &alloc, const Data &source) : CssmOwnedData(alloc, mData) | |
226 | { *this = source; } | |
29654253 A |
227 | |
228 | CssmAutoData(CssmAutoData &source) : CssmOwnedData(source.allocator, mData) | |
229 | { set(source); } | |
230 | ||
bac41a7b A |
231 | explicit CssmAutoData(CssmManagedData &source) : CssmOwnedData(source.allocator, mData) |
232 | { set(source); } | |
233 | ||
234 | CssmAutoData(CssmAllocator &alloc, const void *data, size_t length) | |
235 | : CssmOwnedData(alloc, mData) { copy(data, length); } | |
236 | ||
237 | ~CssmAutoData() { allocator.free(mData); } | |
238 | ||
239 | CssmData release(); | |
240 | void reset(); | |
241 | ||
242 | // assignment (not usefully inherited) | |
243 | void operator = (CssmManagedData &source) { set(source); } | |
244 | void operator = (CssmOwnedData &source) { set(source); } | |
245 | void operator = (CssmAutoData &source) { set(source); } | |
246 | template <class Data> | |
247 | void operator = (const Data &source) { copy(source); } | |
248 | ||
249 | private: | |
250 | CssmData mData; | |
251 | }; | |
252 | ||
253 | ||
254 | // | |
255 | // A CssmRemoteData is a CssmOwnedData that uses an external CssmData object. | |
256 | // Its release operation clears an internal ownership flag but does not clear | |
257 | // the CssmData values so they can be used to return values to an outside scope. | |
258 | // | |
259 | class CssmRemoteData : public CssmOwnedData { | |
260 | public: | |
261 | CssmRemoteData(CssmAllocator &alloc, CssmData &mine) | |
262 | : CssmOwnedData(alloc, mine), iOwnTheData(true) { } | |
263 | ||
264 | CssmRemoteData(CssmAllocator &alloc, CSSM_DATA &mine) | |
265 | : CssmOwnedData(alloc, mine), iOwnTheData(true) { } | |
266 | ||
267 | ~CssmRemoteData() | |
268 | { if (iOwnTheData) allocator.free(referent); } | |
269 | ||
270 | CssmData release(); | |
271 | void reset(); | |
272 | ||
273 | // assignment (not usefully inherited) | |
274 | void operator = (CssmManagedData &source) { set(source); } | |
275 | void operator = (CssmOwnedData &source) { set(source); } | |
276 | void operator = (CssmAutoData &source) { set(source); } | |
277 | template <class Data> | |
278 | void operator = (const Data &source) { copy(source); } | |
279 | ||
280 | private: | |
281 | bool iOwnTheData; | |
282 | }; | |
283 | ||
284 | ||
285 | // | |
286 | // CssmPolyData | |
287 | // | |
288 | // Used by functions that take a CssmData and would like to allow it to be | |
289 | // initialized with a static string, int or other basic type. The function *must* | |
290 | // copy the Data of the CssmPolyData when doing so if it is to be used | |
291 | // after the function returns. (For example by creating a CssmDataContainer from it). | |
292 | class CssmPolyData : public CssmData { | |
293 | template <class T> | |
294 | uint8 *set(const T &it) | |
295 | { return const_cast<uint8 *>(reinterpret_cast<const uint8 *>(&it)); } | |
296 | public: | |
297 | template <class char_T> | |
298 | CssmPolyData(const char_T *s) : CssmData(const_cast<char_T *>(s), strlen(s)) {} | |
299 | CssmPolyData(const string &s) : CssmData(const_cast<char *>(s.c_str()), s.size()) {} | |
300 | CssmPolyData(const CSSM_DATA &data) : CssmData(data.Data, data.Length) {} | |
301 | ||
302 | // Don't use a template constructor (for T &) here - it would eat way too much | |
303 | CssmPolyData(const bool &t) : CssmData(set(t), sizeof(t)) { } | |
304 | CssmPolyData(const uint32 &t) : CssmData(set(t), sizeof(t)) { } | |
305 | CssmPolyData(const sint32 &t) : CssmData(set(t), sizeof(t)) { } | |
306 | CssmPolyData(const sint64 &t) : CssmData(set(t), sizeof(t)) { } | |
307 | CssmPolyData(const double &t) : CssmData(set(t), sizeof(t)) { } | |
29654253 | 308 | CssmPolyData(const StringPtr s) : CssmData (reinterpret_cast<char*>(s + 1), uint32 (s[0])) {} |
bac41a7b A |
309 | }; |
310 | ||
311 | class CssmDateData : public CssmData | |
312 | { | |
313 | public: | |
314 | CssmDateData(const CSSM_DATE &date); | |
315 | private: | |
316 | uint8 buffer[8]; | |
317 | }; | |
318 | ||
319 | class CssmGuidData : public CssmData | |
320 | { | |
321 | public: | |
322 | CssmGuidData(const CSSM_GUID &guid); | |
323 | private: | |
324 | char buffer[Guid::stringRepLength + 1]; | |
325 | }; | |
326 | ||
327 | ||
328 | // | |
329 | // CssmDLPolyData | |
330 | // | |
331 | class CssmDLPolyData | |
332 | { | |
333 | public: | |
334 | CssmDLPolyData(const CSSM_DATA &data, CSSM_DB_ATTRIBUTE_FORMAT format) | |
335 | : mData(CssmData::overlay(data)), mFormat(format) {} | |
336 | ||
337 | // @@@ Don't use assert, but throw an exception. | |
338 | // @@@ Do a size check on mData as well. | |
339 | ||
340 | // @@@ This method is dangerous since the returned string is not guaranteed to be zero terminated. | |
341 | operator const char *() const | |
342 | { | |
343 | assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_STRING | |
344 | || mFormat == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE); | |
345 | return reinterpret_cast<const char *>(mData.Data); | |
346 | } | |
347 | operator bool() const | |
348 | { | |
349 | assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_UINT32 || mFormat == CSSM_DB_ATTRIBUTE_FORMAT_SINT32); | |
350 | return *reinterpret_cast<uint32 *>(mData.Data); | |
351 | } | |
352 | operator uint32() const | |
353 | { | |
354 | assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_UINT32); | |
355 | return *reinterpret_cast<uint32 *>(mData.Data); | |
356 | } | |
357 | operator const uint32 *() const | |
358 | { | |
359 | assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32); | |
360 | return reinterpret_cast<const uint32 *>(mData.Data); | |
361 | } | |
362 | operator sint32() const | |
363 | { | |
364 | assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_SINT32); | |
365 | return *reinterpret_cast<sint32 *>(mData.Data); | |
366 | } | |
367 | operator double() const | |
368 | { | |
369 | assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_REAL); | |
370 | return *reinterpret_cast<double *>(mData.Data); | |
371 | } | |
372 | operator CSSM_DATE () const; | |
373 | operator Guid () const; | |
374 | operator const CssmData &() const | |
375 | { | |
376 | return mData; | |
377 | } | |
378 | ||
379 | private: | |
380 | const CssmData &mData; | |
381 | CSSM_DB_ATTRIBUTE_FORMAT mFormat; | |
382 | }; | |
383 | ||
384 | ||
385 | // | |
386 | // Non POD refcounted CssmData wrapper that own the data it refers to. | |
387 | // | |
388 | class CssmDataContainer : public CssmData, public RefCount | |
389 | { | |
390 | public: | |
391 | CssmDataContainer(CssmAllocator &inAllocator = CssmAllocator::standard()) : | |
392 | CssmData(), mAllocator(inAllocator) {} | |
393 | template <class T> | |
394 | CssmDataContainer(const T *data, size_t length, CssmAllocator &inAllocator = CssmAllocator::standard()) : | |
395 | CssmData(inAllocator.malloc(length), length), mAllocator(inAllocator) | |
396 | { if (length) ::memcpy(Data, data, length); } | |
397 | void clear() { if (Data) { mAllocator.free(Data); Data = NULL; Length = 0; } } | |
398 | ~CssmDataContainer() { if (Data) mAllocator.free(Data); } | |
399 | void append(const CssmPolyData &data) | |
400 | { | |
401 | uint32 newLength = Length + data.Length; | |
402 | Data = reinterpret_cast<uint8 *>(mAllocator.realloc(Data, newLength)); | |
403 | memcpy(Data + Length, data.Data, data.Length); | |
404 | Length = newLength; | |
405 | } | |
406 | CssmDataContainer(const CssmDataContainer &other) | |
407 | : mAllocator(other.mAllocator) | |
408 | { | |
409 | Data = reinterpret_cast<uint8 *>(mAllocator.malloc(other.Length)); | |
410 | memcpy(Data, other.Data, other.Length); | |
411 | Length = other.Length; | |
412 | } | |
413 | CssmDataContainer & operator = (const CSSM_DATA &other) | |
414 | { | |
415 | clear(); | |
416 | Data = reinterpret_cast<uint8 *>(mAllocator.malloc(other.Length)); | |
417 | memcpy(Data, other.Data, other.Length); | |
418 | Length = other.Length; | |
419 | return *this; | |
420 | } | |
421 | ||
422 | public: | |
423 | CssmAllocator &mAllocator; | |
424 | ||
425 | private: | |
426 | operator CssmDataContainer * () const; // prohibit conversion-to-my-pointer | |
427 | }; | |
428 | ||
429 | // | |
430 | // CSSM_OIDs are CSSM_DATAs but will probably have different wrapping characteristics. | |
431 | // | |
432 | typedef CssmDataContainer CssmOidContainer; | |
433 | ||
434 | template <class Container> | |
435 | class CssmBuffer : public RefPointer<Container> | |
436 | { | |
437 | public: | |
438 | CssmBuffer() : RefPointer<Container>(new Container()) {} // XXX This should may just set ptr to NULL. | |
439 | template <class T> | |
440 | CssmBuffer(const T *data, size_t length, CssmAllocator &inAllocator = CssmAllocator::standard()) : | |
441 | RefPointer<Container>(new Container(data, length, inAllocator)) {} | |
442 | CssmBuffer(const CSSM_DATA &data, CssmAllocator &inAllocator = CssmAllocator::standard()) : | |
443 | RefPointer<Container>(new Container(data.Data, data.Length, inAllocator)) {} | |
444 | CssmBuffer(const CssmBuffer& other) : RefPointer<Container>(other) {} | |
445 | CssmBuffer(Container *p) : RefPointer<Container>(p) {} | |
446 | bool CssmBuffer::operator < (const CssmBuffer &other) const { return (**this) < (*other); } | |
447 | }; | |
448 | ||
bac41a7b | 449 | |
29654253 | 450 | } // end namespace Security |
bac41a7b A |
451 | |
452 | #endif // _H_CDSA_UTILITIES_CSSMDATA |