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_utilities/debugging.h>
33 #include <security_cdsa_utilities/cssmalloc.h>
34 #include <security_cdsa_utilities/cssmwalkers.h>
44 // A POD Wrapper for CSSM_LIST_ELEMENTs.
45 // List elements are pseudo-polymorphic, so we provide ways to get and
46 // set their three personalities. It's up to the caller to get this right;
47 // you mustn't (for example) call the data() method on a list element that
48 // is not of (element) type CSSM_LIST_ELEMENT_DATUM. To violate this rule
49 // will get you an assertion (not exception).
51 class ListElement
: public PodWrapper
<ListElement
, CSSM_LIST_ELEMENT
> {
54 CSSM_LIST_ELEMENT_TYPE
type() const { return ElementType
; }
55 bool is(CSSM_LIST_ELEMENT_TYPE t
) const { return type() == t
; }
57 // list element chaining
58 ListElement
* &next() { return ListElement::overlayVar(NextElement
); }
59 ListElement
*next() const { return ListElement::overlay(NextElement
); }
62 // CssmData personality
63 explicit ListElement(const CssmData
&data
);
64 explicit ListElement(Allocator
&alloc
, const CssmData
&data
);
65 explicit ListElement(Allocator
&alloc
, const std::string
&stringData
);
68 string
toString() const { return data().toString(); }
69 const CssmData
&data() const;
70 ListElement
&operator = (const CssmData
&data
);
71 operator CssmData
&() { return data(); }
72 operator std::string () const { return toString(); }
73 bool operator == (const CssmData
&other
) const { return data() == other
; }
74 bool operator != (const CssmData
&other
) const { return data() != other
; }
77 void extract(T
&destination
, CSSM_RETURN error
= CSSM_ERRCODE_INVALID_DATA
)
78 { data().extract(destination
, error
); }
80 // CssmList (sublist) personality
81 explicit ListElement(const CssmList
&list
);
83 const CssmList
&list() const;
84 TypedList
&typedList();
85 const TypedList
&typedList() const;
86 ListElement
&operator = (const CssmList
&list
);
87 operator CssmList
&() { return list(); }
88 operator TypedList
&();
90 // WORDID (number) personality
91 explicit ListElement(CSSM_WORDID_TYPE word
);
92 CSSM_WORDID_TYPE
word() const;
93 ListElement
&operator = (CSSM_WORDID_TYPE word
);
94 operator CSSM_WORDID_TYPE () const { return word(); }
97 void *operator new (size_t size
, Allocator
&alloc
)
98 { return alloc
.malloc(size
); }
100 void clear(Allocator
&alloc
); // free my contents
103 } // end namespace Security
105 // specialize destroy() to call clear() for cleanup
106 inline void destroy(ListElement
*elem
, Allocator
&alloc
)
116 // A POD Wrapper for CSSM_LIST.
117 // CssmList does no memory allocations. Retrieval functions return pointers or
118 // references into existing content, and modifiers modify in-place without any
119 // attempt to release previous dynamic content. May the Leaking God be with You.
121 class CssmList
: public PodWrapper
<CssmList
, CSSM_LIST
> {
123 CssmList() { ListType
= CSSM_LIST_TYPE_UNKNOWN
; Head
= Tail
= NULL
; }
124 CssmList(const CssmList
&list
) { *(CssmList
*)this = list
; }
127 CSSM_LIST_TYPE
kind() const { return ListType
; } // type() reserved for TypedList
129 ListElement
&operator [] (unsigned ix
) const;
130 unsigned int length() const;
131 ListElement
* &first() { return ListElement::overlayVar(Head
); }
132 ListElement
*first() const { return ListElement::overlay(Head
); }
133 ListElement
*last() const { return ListElement::overlay(Tail
); }
134 bool empty() const { return first() == NULL
; }
136 CssmList
&append(ListElement
*elem
);
137 CssmList
&insert(ListElement
*elem
, ListElement
*before
);
138 CssmList
&remove(ListElement
*elem
);
139 CssmList
&operator += (ListElement
*elem
) { return append(elem
); }
140 CssmList
&operator -= (ListElement
*elem
) { return remove(elem
); }
142 // logically remove the first element (skip it)
145 CssmList
&operator =(const CssmList
& other
);
148 void clear(Allocator
&alloc
); // free my contents
151 } // end namespace Security
153 inline void destroy(CssmList
*list
, Allocator
&alloc
)
163 // Enhanced overlay for CssmLists whose first element is known to be a wordid.
165 class TypedList
: public CssmList
{
167 explicit TypedList(const CSSM_LIST
&list
) { *(CSSM_LIST
*)this = list
; }
168 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
);
169 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
);
170 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
,
172 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
,
173 ListElement
*elem2
, ListElement
*elem3
);
174 TypedList(Allocator
&alloc
, CSSM_WORDID_TYPE type
, ListElement
*elem1
,
175 ListElement
*elem2
, ListElement
*elem3
, ListElement
*elem4
);
177 bool isProper() const; // format check (does not throw)
178 void checkProper(CSSM_RETURN error
= CSSM_ERRCODE_INVALID_SAMPLE_VALUE
) const;
179 static TypedList
&overlay(CSSM_LIST
&list
)
180 { return static_cast<TypedList
&>(list
); }
181 static const TypedList
&overlay(const CSSM_LIST
&list
)
182 { return static_cast<const TypedList
&>(list
); }
184 CSSM_WORDID_TYPE
type() const
185 { assert(isProper()); return first()->word(); }
188 inline ListElement::operator TypedList
&()
189 { return TypedList::overlay(operator CssmList
&()); }
193 // Data walkers to parse list elements and lists.
194 // @@@ Walking lists by recursing over next() is stack intensive. Do this in CssmList walker by loop?
196 namespace DataWalkers
{
199 template <class Action
>
200 ListElement
*walk(Action
&operate
, ListElement
* &elem
)
203 switch (elem
->type()) {
204 case CSSM_LIST_ELEMENT_DATUM
:
205 walk(operate
, elem
->data());
207 case CSSM_LIST_ELEMENT_SUBLIST
:
208 walk(operate
, elem
->list());
210 case CSSM_LIST_ELEMENT_WORDID
:
213 secinfo("walkers", "invalid list element type (%ux)", (unsigned)elem
->type());
217 walk(operate
, elem
->next());
221 template <class Action
>
222 ListElement
*walk(Action
&operate
, CSSM_LIST_ELEMENT
* &elem
)
223 { return walk(operate
, ListElement::overlayVar(elem
)); }
226 template <class Action
>
227 void enumerate(Action
&operate
, CssmList
&list
)
230 walk(operate
, list
.first());
231 if (operate
.needsRelinking
)
232 list
.Tail
= list
.first()->last(); // re-establish "tail" link
236 template <class Action
>
237 CssmList
*walk(Action
&operate
, CssmList
* &list
)
240 enumerate(operate
, *list
);
244 template <class Action
>
245 void walk(Action
&operate
, CssmList
&list
)
248 enumerate(operate
, list
);
251 template <class Action
>
252 void walk(Action
&operate
, CSSM_LIST
&list
)
253 { walk(operate
, CssmList::overlay(list
)); }
255 template <class Action
>
256 CSSM_LIST
*walk(Action
&operate
, CSSM_LIST
* &list
)
257 { return walk(operate
, CssmList::overlayVar(list
)); }
259 template <class Action
>
260 TypedList
*walk(Action
&operate
, TypedList
* &list
)
261 { return static_cast<TypedList
*>(walk(operate
, reinterpret_cast<CssmList
* &>(list
))); }
263 template <class Action
>
264 void walk(Action
&operate
, TypedList
&list
)
265 { walk(operate
, static_cast<CssmList
&>(list
)); }
268 } // end namespace DataWalkers
269 } // end namespace Security