2 * Copyright (c) 2000-2006,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // cssmlist - CSSM_LIST operational utilities
31 #include <security_utilities/utilities.h>
32 #include <security_cdsa_utilities/cssmalloc.h>
33 #include <security_cdsa_utilities/cssmwalkers.h>
43 // A POD Wrapper for CSSM_LIST_ELEMENTs.
44 // List elements are pseudo-polymorphic, so we provide ways to get and
45 // set their three personalities. It's up to the caller to get this right;
46 // you mustn't (for example) call the data() method on a list element that
47 // is not of (element) type CSSM_LIST_ELEMENT_DATUM. To violate this rule
48 // will get you an assertion (not exception).
50 class ListElement
: public PodWrapper
<ListElement
, CSSM_LIST_ELEMENT
> {
53 CSSM_LIST_ELEMENT_TYPE
type() const { return ElementType
; }
54 bool is(CSSM_LIST_ELEMENT_TYPE t
) const { return type() == t
; }
56 // list element chaining
57 ListElement
* &next() { return ListElement::overlayVar(NextElement
); }
58 ListElement
*next() const { return ListElement::overlay(NextElement
); }
61 // CssmData personality
62 explicit ListElement(const CssmData
&data
);
63 explicit ListElement(Allocator
&alloc
, const CssmData
&data
);
64 explicit ListElement(Allocator
&alloc
, const std::string
&stringData
);
67 string
toString() const { return data().toString(); }
68 const CssmData
&data() const;
69 ListElement
&operator = (const CssmData
&data
);
70 operator CssmData
&() { return data(); }
71 operator std::string () const { return toString(); }
72 bool operator == (const CssmData
&other
) const { return data() == other
; }
73 bool operator != (const CssmData
&other
) const { return data() != other
; }
76 void extract(T
&destination
, CSSM_RETURN error
= CSSM_ERRCODE_INVALID_DATA
)
77 { data().extract(destination
, error
); }
79 // CssmList (sublist) personality
80 explicit ListElement(const CssmList
&list
);
82 const CssmList
&list() const;
83 TypedList
&typedList();
84 const TypedList
&typedList() const;
85 ListElement
&operator = (const CssmList
&list
);
86 operator CssmList
&() { return list(); }
87 operator TypedList
&();
89 // WORDID (number) personality
90 explicit ListElement(CSSM_WORDID_TYPE word
);
91 CSSM_WORDID_TYPE
word() const;
92 ListElement
&operator = (CSSM_WORDID_TYPE word
);
93 operator CSSM_WORDID_TYPE () const { return word(); }
96 void *operator new (size_t size
, Allocator
&alloc
)
97 { return alloc
.malloc(size
); }
99 void clear(Allocator
&alloc
); // free my contents
102 } // end namespace Security
104 // specialize destroy() to call clear() for cleanup
105 inline void destroy(ListElement
*elem
, Allocator
&alloc
)
115 // A POD Wrapper for CSSM_LIST.
116 // CssmList does no memory allocations. Retrieval functions return pointers or
117 // references into existing content, and modifiers modify in-place without any
118 // attempt to release previous dynamic content. May the Leaking God be with You.
120 class CssmList
: public PodWrapper
<CssmList
, CSSM_LIST
> {
122 CssmList() { ListType
= CSSM_LIST_TYPE_UNKNOWN
; Head
= Tail
= NULL
; }
123 CssmList(const CssmList
&list
) { *(CssmList
*)this = list
; }
126 CSSM_LIST_TYPE
kind() const { return ListType
; } // type() reserved for TypedList
128 ListElement
&operator [] (unsigned ix
) const;
129 unsigned int length() const;
130 ListElement
* &first() { return ListElement::overlayVar(Head
); }
131 ListElement
*first() const { return ListElement::overlay(Head
); }
132 ListElement
*last() const { return ListElement::overlay(Tail
); }
133 bool empty() const { return first() == NULL
; }
135 CssmList
&append(ListElement
*elem
);
136 CssmList
&insert(ListElement
*elem
, ListElement
*before
);
137 CssmList
&remove(ListElement
*elem
);
138 CssmList
&operator += (ListElement
*elem
) { return append(elem
); }
139 CssmList
&operator -= (ListElement
*elem
) { return remove(elem
); }
141 // logically remove the first element (skip it)
145 void clear(Allocator
&alloc
); // free my contents
148 } // end namespace Security
150 inline void destroy(CssmList
*list
, Allocator
&alloc
)
160 // Enhanced overlay for CssmLists whose first element is known to be a wordid.
162 class TypedList
: public CssmList
{
164 explicit TypedList(const CSSM_LIST
&list
) { *(CSSM_LIST
*)this = list
; }
165 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
);
166 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
);
167 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
,
169 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
,
170 ListElement
*elem2
, ListElement
*elem3
);
171 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
,
172 ListElement
*elem2
, ListElement
*elem3
, ListElement
*elem4
);
174 bool isProper() const; // format check (does not throw)
175 void checkProper(CSSM_RETURN error
= CSSM_ERRCODE_INVALID_SAMPLE_VALUE
) const;
176 static TypedList
&overlay(CSSM_LIST
&list
)
177 { return static_cast<TypedList
&>(list
); }
178 static const TypedList
&overlay(const CSSM_LIST
&list
)
179 { return static_cast<const TypedList
&>(list
); }
181 CSSM_WORDID_TYPE
type() const
182 { assert(isProper()); return first()->word(); }
185 inline ListElement::operator TypedList
&()
186 { return TypedList::overlay(operator CssmList
&()); }
190 // Data walkers to parse list elements and lists.
191 // @@@ Walking lists by recursing over next() is stack intensive. Do this in CssmList walker by loop?
193 namespace DataWalkers
{
196 template <class Action
>
197 ListElement
*walk(Action
&operate
, ListElement
* &elem
)
200 switch (elem
->type()) {
201 case CSSM_LIST_ELEMENT_DATUM
:
202 walk(operate
, elem
->data());
204 case CSSM_LIST_ELEMENT_SUBLIST
:
205 walk(operate
, elem
->list());
207 case CSSM_LIST_ELEMENT_WORDID
:
210 secdebug("walkers", "invalid list element type (%ux)", (unsigned)elem
->type());
214 walk(operate
, elem
->next());
218 template <class Action
>
219 ListElement
*walk(Action
&operate
, CSSM_LIST_ELEMENT
* &elem
)
220 { return walk(operate
, ListElement::overlayVar(elem
)); }
223 template <class Action
>
224 void enumerate(Action
&operate
, CssmList
&list
)
227 walk(operate
, list
.first());
228 if (operate
.needsRelinking
)
229 list
.Tail
= list
.first()->last(); // re-establish "tail" link
233 template <class Action
>
234 CssmList
*walk(Action
&operate
, CssmList
* &list
)
237 enumerate(operate
, *list
);
241 template <class Action
>
242 void walk(Action
&operate
, CssmList
&list
)
245 enumerate(operate
, list
);
248 template <class Action
>
249 void walk(Action
&operate
, CSSM_LIST
&list
)
250 { walk(operate
, CssmList::overlay(list
)); }
252 template <class Action
>
253 CSSM_LIST
*walk(Action
&operate
, CSSM_LIST
* &list
)
254 { return walk(operate
, CssmList::overlayVar(list
)); }
256 template <class Action
>
257 TypedList
*walk(Action
&operate
, TypedList
* &list
)
258 { return static_cast<TypedList
*>(walk(operate
, reinterpret_cast<CssmList
* &>(list
))); }
260 template <class Action
>
261 void walk(Action
&operate
, TypedList
&list
)
262 { walk(operate
, static_cast<CssmList
&>(list
)); }
265 } // end namespace DataWalkers
266 } // end namespace Security