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 // cssmlist - CSSM_LIST operational utilities
25 #include <Security/utilities.h>
26 #include <Security/cssmalloc.h>
27 #include <Security/cssmwalkers.h>
37 // A POD Wrapper for CSSM_LIST_ELEMENTs.
38 // List elements are pseudo-polymorphic, so we provide ways to get and
39 // set their three personalities. It's up to the caller to get this right;
40 // you mustn't (for example) call the data() method on a list element that
41 // is not of (element) type CSSM_LIST_ELEMENT_DATUM. To violate this rule
42 // will get you an assertion (not exception).
44 class ListElement
: public PodWrapper
<ListElement
, CSSM_LIST_ELEMENT
> {
47 CSSM_LIST_ELEMENT_TYPE
type() const { return ElementType
; }
48 bool is(CSSM_LIST_ELEMENT_TYPE t
) const { return type() == t
; }
50 // list element chaining
51 ListElement
* &next() { return ListElement::overlayVar(NextElement
); }
52 ListElement
*next() const { return ListElement::overlay(NextElement
); }
55 // CssmData personality
56 explicit ListElement(const CssmData
&data
);
57 explicit ListElement(CssmAllocator
&alloc
, const CssmData
&data
);
58 explicit ListElement(CssmAllocator
&alloc
, const std::string
&stringData
);
60 string
toString() const { return data().toString(); }
61 const CssmData
&data() const;
62 ListElement
&operator = (const CssmData
&data
);
63 operator CssmData
&() { return data(); }
64 operator std::string () const { return toString(); }
65 bool operator == (const CssmData
&other
) const { return data() == other
; }
66 bool operator != (const CssmData
&other
) const { return data() != other
; }
69 void extract(T
&destination
, CSSM_RETURN error
= CSSM_ERRCODE_INVALID_DATA
)
70 { data().extract(destination
, error
); }
72 // CssmList (sublist) personality
73 explicit ListElement(const CssmList
&list
);
75 const CssmList
&list() const;
76 TypedList
&typedList();
77 const TypedList
&typedList() const;
78 ListElement
&operator = (const CssmList
&list
);
79 operator CssmList
&() { return list(); }
80 operator TypedList
&();
82 // WORDID (number) personality
83 explicit ListElement(CSSM_WORDID_TYPE word
);
84 CSSM_WORDID_TYPE
word() const;
85 ListElement
&operator = (CSSM_WORDID_TYPE word
);
86 operator CSSM_WORDID_TYPE () const { return word(); }
89 void *operator new (size_t size
, CssmAllocator
&alloc
)
90 { return alloc
.malloc(size
); }
92 void clear(CssmAllocator
&alloc
); // free my contents
95 } // end namespace Security
97 // specialize destroy() to call clear() for cleanup
98 inline void destroy(ListElement
*elem
, CssmAllocator
&alloc
)
108 // A POD Wrapper for CSSM_LIST.
109 // CssmList does no memory allocations. Retrieval functions return pointers or
110 // references into existing content, and modifiers modify in-place without any
111 // attempt to release previous dynamic content. May the Leaking God be with You.
113 class CssmList
: public PodWrapper
<CssmList
, CSSM_LIST
> {
115 CssmList() { ListType
= CSSM_LIST_TYPE_UNKNOWN
; Head
= Tail
= NULL
; }
116 CssmList(const CssmList
&list
) { *(CssmList
*)this = list
; }
119 CSSM_LIST_TYPE
kind() const { return ListType
; } // type() reserved for TypedList
121 ListElement
&operator [] (unsigned ix
) const;
122 unsigned int length() const;
123 ListElement
* &first() { return ListElement::overlayVar(Head
); }
124 ListElement
*first() const { return ListElement::overlay(Head
); }
125 ListElement
*last() const { return ListElement::overlay(Tail
); }
126 bool empty() const { return first() == NULL
; }
128 CssmList
&append(ListElement
*elem
);
129 CssmList
&insert(ListElement
*elem
, ListElement
*before
);
130 CssmList
&remove(ListElement
*elem
);
131 CssmList
&operator += (ListElement
*elem
) { return append(elem
); }
132 CssmList
&operator -= (ListElement
*elem
) { return remove(elem
); }
134 // logically remove the first element (skip it)
138 void clear(CssmAllocator
&alloc
); // free my contents
141 } // end namespace Security
143 inline void destroy(CssmList
*list
, CssmAllocator
&alloc
)
153 // Enhanced overlay for CssmLists whose first element is known to be a wordid.
155 class TypedList
: public CssmList
{
157 explicit TypedList(const CSSM_LIST
&list
) { *(CSSM_LIST
*)this = list
; }
158 TypedList(CssmAllocator
&alloc
, CSSM_WORDID_TYPE type
);
159 TypedList(CssmAllocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
);
160 TypedList(CssmAllocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
,
162 TypedList(CssmAllocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
,
163 ListElement
*elem2
, ListElement
*elem3
);
164 TypedList(CssmAllocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
,
165 ListElement
*elem2
, ListElement
*elem3
, ListElement
*elem4
);
167 bool isProper() const; // format check (does not throw)
168 void checkProper(CSSM_RETURN error
= CSSM_ERRCODE_INVALID_SAMPLE_VALUE
) const;
169 static TypedList
&overlay(CSSM_LIST
&list
)
170 { return static_cast<TypedList
&>(list
); }
171 static const TypedList
&overlay(const CSSM_LIST
&list
)
172 { return static_cast<const TypedList
&>(list
); }
174 CSSM_WORDID_TYPE
type() const
175 { assert(isProper()); return first()->word(); }
178 inline ListElement::operator TypedList
&()
179 { return TypedList::overlay(operator CssmList
&()); }
183 // Data walkers to parse list elements and lists.
184 // @@@ Walking lists by recursing over next() is stack intensive. Do this in CssmList walker by loop?
186 namespace DataWalkers
{
189 template <class Action
>
190 ListElement
*walk(Action
&operate
, ListElement
* &elem
)
193 switch (elem
->type()) {
194 case CSSM_LIST_ELEMENT_DATUM
:
195 walk(operate
, elem
->data());
197 case CSSM_LIST_ELEMENT_SUBLIST
:
198 walk(operate
, elem
->list());
200 case CSSM_LIST_ELEMENT_WORDID
:
203 secdebug("walkers", "invalid list element type (%lx)", elem
->type());
207 walk(operate
, elem
->next());
211 template <class Action
>
212 ListElement
*walk(Action
&operate
, CSSM_LIST_ELEMENT
* &elem
)
213 { walk(operate
, ListElement::overlayVar(elem
)); }
216 template <class Action
>
217 void enumerate(Action
&operate
, CssmList
&list
)
220 walk(operate
, list
.first());
221 if (operate
.needsRelinking
)
222 list
.Tail
= list
.first()->last(); // re-establish "tail" link
226 template <class Action
>
227 CssmList
*walk(Action
&operate
, CssmList
* &list
)
230 enumerate(operate
, *list
);
234 template <class Action
>
235 void walk(Action
&operate
, CssmList
&list
)
238 enumerate(operate
, list
);
241 template <class Action
>
242 void walk(Action
&operate
, const CssmList
&list
)
243 { walk(operate
, const_cast<CssmList
&>(list
)); }
245 template <class Action
>
246 void walk(Action
&operate
, CSSM_LIST
&list
)
247 { walk(operate
, CssmList::overlay(list
)); }
249 template <class Action
>
250 void walk(Action
&operate
, const CSSM_LIST
&list
)
251 { walk(operate
, const_cast<CSSM_LIST
&>(list
)); }
253 template <class Action
>
254 CSSM_LIST
*walk(Action
&operate
, CSSM_LIST
* &list
)
255 { return walk(operate
, CssmList::overlayVar(list
)); }
257 template <class Action
>
258 TypedList
*walk(Action
&operate
, TypedList
* &list
)
259 { return static_cast<TypedList
*>(walk(operate
, reinterpret_cast<CssmList
* &>(list
))); }
261 template <class Action
>
262 void walk(Action
&operate
, TypedList
&list
)
263 { walk(operate
, static_cast<CssmList
&>(list
)); }
266 } // end namespace DataWalkers
267 } // end namespace Security