2  * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. 
   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 
  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. 
  20 // cssmdata.h -- Manager different CssmData types 
  22 #ifndef _H_CDSA_UTILITIES_CSSMDATA 
  23 #define _H_CDSA_UTILITIES_CSSMDATA 
  25 #include <Security/utilities.h> 
  26 #include <Security/cssmalloc.h> 
  27 #include <Security/refcount.h> 
  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. 
  38 class StringData 
: public CssmData 
{ 
  40     StringData(const char *s
) : CssmData(const_cast<char *>(s
), strlen(s
)) { } 
  45 // A CssmData bundled up with a data buffer it refers to 
  47 template <size_t size
> 
  48 struct DataBuffer 
: public CssmData 
{ 
  49         unsigned char buffer
[size
]; 
  50         DataBuffer() : CssmData(buffer
, size
) { } 
  55 // Comparing CssmDatas for equality. 
  56 // Note: No ordering is established here. 
  57 // Both CSSM_DATAs have to exist. 
  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
); } 
  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. 
  69 //      void *data() const ... 
  70 //  size_t length() const ... 
  71 //  operator const CssmData &() const ... 
  74 // All this can be satisfied, of course, by inheriting from CssmData. 
  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. 
  86 class CssmManagedData 
{ 
  88         CssmManagedData(CssmAllocator 
&alloc
) : allocator(alloc
) { } 
  89         virtual ~CssmManagedData(); 
  91         CssmAllocator 
&allocator
; 
  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(); } 
  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 
 105 // A CssmOwnedData is a CssmManagedData that unilaterally owns its data storage. 
 106 // It has its CssmData object provided during construction. 
 108 class CssmOwnedData 
: public CssmManagedData 
{ 
 110         CssmOwnedData(CssmAllocator 
&alloc
, CssmData 
&mine
) : CssmManagedData(alloc
), referent(mine
) { } 
 112         CssmOwnedData(CssmAllocator 
&alloc
, CSSM_DATA 
&mine
) 
 113         : CssmManagedData(alloc
), referent(CssmData::overlay(mine
)) { referent
.clear(); } 
 116         // Basic retrievals (this echoes features of CssmData) 
 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
; } 
 123         operator bool () const                  { return referent
; } 
 124         bool operator ! () const                { return !referent
; } 
 126         size_t length() const                   { return referent
.length(); } 
 132         void *malloc(size_t len
) 
 134                 // pseudo-atomic reallocation semantics 
 135                 CssmAutoPtr
<uint8
> alloc(allocator
, allocator
.malloc
<uint8
>(len
)); 
 137                 return referent 
= CssmData(alloc
.release(), len
); 
 140         void *realloc(size_t newLen
) 
 142                 // CssmAllocator::realloc() should be pseudo-atomic (i.e. throw on error) 
 143                 return referent 
= CssmData(allocator
.realloc
<uint8
>(referent
.data(), newLen
), newLen
); 
 146         void length(size_t len
)                 { realloc(len
); } 
 150         // Manipulate existing data 
 152         void *append(const void *addData
, size_t addLength
) 
 154                 size_t oldLength 
= length(); 
 155                 realloc(oldLength 
+ addLength
); 
 156                 return memcpy(referent
.at(oldLength
), addData
, addLength
); 
 159         void *append(const CssmData 
&data
) 
 160         { return append(data
.data(), data
.length()); } 
 163         // set() replaces current data with new, taking over ownership to the extent possible. 
 166         void set(T 
*data
, size_t length
) 
 168                 // assume that data was allocated by our allocator -- we can't be sure 
 170                 referent 
= CssmData(data
, length
); 
 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. 
 180         // copy() replaces current data with new, making a copy and leaving 
 181         // the source intact. 
 184         void copy(const T 
*data
, size_t length
) 
 186                 // don't leave any open windows for Mr. Murphy 
 187                 CssmAutoPtr
<void> newData(allocator
, memcpy(allocator
.malloc(length
), data
, length
)); 
 189                 referent 
= CssmData(newData
.release(), length
); 
 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()); } 
 202         // Assignment conservatively uses copy if allocator unknown, set if known 
 204         void operator = (CssmManagedData 
&source
) { set(source
); } 
 205         void operator = (CssmOwnedData 
&source
) { set(source
); } 
 206         void operator = (const CSSM_DATA 
&source
) { copy(source
); } 
 208         CssmData 
&get() const throw()                   { return referent
; } 
 216 // A CssmAutoData is a CssmOwnedData that includes its CssmData object. 
 217 // This is the very simple case: The object includes ownership, data object, 
 220 class CssmAutoData 
: public CssmOwnedData 
{ 
 222         CssmAutoData(CssmAllocator 
&alloc
) : CssmOwnedData(alloc
, mData
) { } 
 224         template <class Data
> 
 225         CssmAutoData(CssmAllocator 
&alloc
, const Data 
&source
) : CssmOwnedData(alloc
, mData
) 
 228     CssmAutoData(CssmAutoData 
&source
) : CssmOwnedData(source
.allocator
, mData
) 
 231         explicit CssmAutoData(CssmManagedData 
&source
) : CssmOwnedData(source
.allocator
, mData
) 
 234         CssmAutoData(CssmAllocator 
&alloc
, const void *data
, size_t length
) 
 235         : CssmOwnedData(alloc
, mData
)   { copy(data
, length
); } 
 237         ~CssmAutoData()                                 { allocator
.free(mData
); } 
 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
); } 
 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. 
 259 class CssmRemoteData 
: public CssmOwnedData 
{ 
 261         CssmRemoteData(CssmAllocator 
&alloc
, CssmData 
&mine
) 
 262         : CssmOwnedData(alloc
, mine
), iOwnTheData(true) { } 
 264         CssmRemoteData(CssmAllocator 
&alloc
, CSSM_DATA 
&mine
) 
 265         : CssmOwnedData(alloc
, mine
), iOwnTheData(true) { } 
 268         { if (iOwnTheData
) allocator
.free(referent
); } 
 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
); } 
 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 
{ 
 294         uint8 
*set(const T 
&it
) 
 295         { return const_cast<uint8 
*>(reinterpret_cast<const uint8 
*>(&it
)); } 
 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
) {} 
 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
)) { } 
 308         CssmPolyData(const StringPtr s
) : CssmData (reinterpret_cast<char*>(s 
+ 1), uint32 (s
[0])) {} 
 311 class CssmDateData 
: public CssmData
 
 314         CssmDateData(const CSSM_DATE 
&date
); 
 319 class CssmGuidData 
: public CssmData
 
 322         CssmGuidData(const CSSM_GUID 
&guid
); 
 324         char buffer
[Guid::stringRepLength 
+ 1]; 
 334         CssmDLPolyData(const CSSM_DATA 
&data
, CSSM_DB_ATTRIBUTE_FORMAT format
) 
 335         : mData(CssmData::overlay(data
)), mFormat(format
) {} 
 337         // @@@ Don't use assert, but throw an exception. 
 338         // @@@ Do a size check on mData as well. 
 340         // @@@ This method is dangerous since the returned string is not guaranteed to be zero terminated. 
 341         operator const char *() const 
 343                 assert(mFormat 
== CSSM_DB_ATTRIBUTE_FORMAT_STRING
 
 344                || mFormat 
== CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
); 
 345                 return reinterpret_cast<const char *>(mData
.Data
); 
 347         operator bool() const 
 349                 assert(mFormat 
== CSSM_DB_ATTRIBUTE_FORMAT_UINT32 
|| mFormat 
== CSSM_DB_ATTRIBUTE_FORMAT_SINT32
); 
 350                 return *reinterpret_cast<uint32 
*>(mData
.Data
); 
 352         operator uint32() const 
 354                 assert(mFormat 
== CSSM_DB_ATTRIBUTE_FORMAT_UINT32
); 
 355                 return *reinterpret_cast<uint32 
*>(mData
.Data
); 
 357         operator const uint32 
*() const 
 359                 assert(mFormat 
== CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
); 
 360                 return reinterpret_cast<const uint32 
*>(mData
.Data
); 
 362         operator sint32() const 
 364                 assert(mFormat 
== CSSM_DB_ATTRIBUTE_FORMAT_SINT32
); 
 365                 return *reinterpret_cast<sint32 
*>(mData
.Data
); 
 367         operator double() const 
 369                 assert(mFormat 
== CSSM_DB_ATTRIBUTE_FORMAT_REAL
); 
 370                 return *reinterpret_cast<double *>(mData
.Data
); 
 372         operator CSSM_DATE () const; 
 373         operator Guid () const; 
 374         operator const CssmData 
&() const 
 380         const CssmData 
&mData
; 
 381         CSSM_DB_ATTRIBUTE_FORMAT mFormat
; 
 386 // Non POD refcounted CssmData wrapper that own the data it refers to. 
 388 class CssmDataContainer 
: public CssmData
, public RefCount
 
 391     CssmDataContainer(CssmAllocator 
&inAllocator 
= CssmAllocator::standard()) : 
 392         CssmData(), mAllocator(inAllocator
) {} 
 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
) 
 401                 uint32 newLength 
= Length 
+ data
.Length
; 
 402                 Data 
= reinterpret_cast<uint8 
*>(mAllocator
.realloc(Data
, newLength
)); 
 403                 memcpy(Data 
+ Length
, data
.Data
, data
.Length
); 
 406         CssmDataContainer(const CssmDataContainer 
&other
) 
 407         : mAllocator(other
.mAllocator
) 
 409                 Data 
= reinterpret_cast<uint8 
*>(mAllocator
.malloc(other
.Length
)); 
 410                 memcpy(Data
, other
.Data
, other
.Length
); 
 411                 Length 
= other
.Length
; 
 413         CssmDataContainer 
& operator = (const CSSM_DATA 
&other
) 
 416                 Data 
= reinterpret_cast<uint8 
*>(mAllocator
.malloc(other
.Length
)); 
 417                 memcpy(Data
, other
.Data
, other
.Length
); 
 418                 Length 
= other
.Length
; 
 423         CssmAllocator 
&mAllocator
; 
 426         operator CssmDataContainer 
* () const;  // prohibit conversion-to-my-pointer 
 430 // CSSM_OIDs are CSSM_DATAs but will probably have different wrapping characteristics. 
 432 typedef CssmDataContainer CssmOidContainer
; 
 434 template <class Container
> 
 435 class CssmBuffer 
: public RefPointer
<Container
> 
 438     CssmBuffer() : RefPointer
<Container
>(new Container()) {} // XXX This should may just set ptr to NULL. 
 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
); } 
 450 } // end namespace Security 
 452 #endif // _H_CDSA_UTILITIES_CSSMDATA