1/*
2 * Copyright (c) 2000-2006,2011,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// cssmlist - CSSM_LIST operational utilities
27//
28#ifndef _H_CSSMLIST
29#define _H_CSSMLIST
30
31#include <security_utilities/utilities.h>
32#include <security_cdsa_utilities/cssmalloc.h>
33#include <security_cdsa_utilities/cssmwalkers.h>
34
35
36namespace Security {
37
38class CssmList;
39class TypedList;
40
41
42//
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).
49//
50class ListElement : public PodWrapper<ListElement, CSSM_LIST_ELEMENT> {
51public:
52	// type control
53	CSSM_LIST_ELEMENT_TYPE type() const { return ElementType; }
54	bool is(CSSM_LIST_ELEMENT_TYPE t) const { return type() == t; }
55
56    // list element chaining
57	ListElement * &next() { return ListElement::overlayVar(NextElement); }
58	ListElement *next() const { return ListElement::overlay(NextElement); }
59	ListElement *last();
60
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);
65
66	CssmData &data();
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; }
74
75    template <class T>
76    void extract(T &destination, CSSM_RETURN error = CSSM_ERRCODE_INVALID_DATA)
77    { data().extract(destination, error); }
78
79    // CssmList (sublist) personality
80	explicit ListElement(const CssmList &list);
81	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 &();
88
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(); }
94
95public:
96	void *operator new (size_t size, Allocator &alloc)
97	{ return alloc.malloc(size); }
98
99	void clear(Allocator &alloc);		// free my contents
100};
101
102} // end namespace Security
103
104// specialize destroy() to call clear() for cleanup
105inline void destroy(ListElement *elem, Allocator &alloc)
106{
107	elem->clear(alloc);
108	alloc.free(elem);
109}
110
111namespace Security {
112
113
114//
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.
119//
120class CssmList : public PodWrapper<CssmList, CSSM_LIST> {
121public:
122	CssmList() { ListType = CSSM_LIST_TYPE_UNKNOWN; Head = Tail = NULL; }
123	CssmList(const CssmList &list)	{ *(CssmList *)this = list; }
124
125public:
126	CSSM_LIST_TYPE kind() const { return ListType; }	// type() reserved for TypedList
127
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; }
134
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); }
140
141    // logically remove the first element (skip it)
142    void snip();
143
144public:
145	void clear(Allocator &alloc);		// free my contents
146};
147
148} // end namespace Security
149
150inline void destroy(CssmList *list, Allocator &alloc)
151{
152	list->clear(alloc);
153	alloc.free(list);
154}
155
156namespace Security
157{
158
159//
160// Enhanced overlay for CssmLists whose first element is known to be a wordid.
161//
162class TypedList : public CssmList {
163public:
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,
168		ListElement *elem2);
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);
173
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); }
180
181	CSSM_WORDID_TYPE type() const
182	{ assert(isProper()); return first()->word(); }
183};
184
185inline ListElement::operator TypedList &()
186{ return TypedList::overlay(operator CssmList &()); }
187
188
189//
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?
192//
193namespace DataWalkers {
194
195// ListElement
196template <class Action>
197ListElement *walk(Action &operate, ListElement * &elem)
198{
199	operate(elem);
200	switch (elem->type()) {
201	case CSSM_LIST_ELEMENT_DATUM:
202		walk(operate, elem->data());
203		break;
204	case CSSM_LIST_ELEMENT_SUBLIST:
205		walk(operate, elem->list());
206		break;
207	case CSSM_LIST_ELEMENT_WORDID:
208		break;
209	default:
210		secdebug("walkers", "invalid list element type (%ux)", (unsigned)elem->type());
211		break;
212	}
213	if (elem->next())
214		walk(operate, elem->next());
215	return elem;
216}
217
218template <class Action>
219ListElement *walk(Action &operate, CSSM_LIST_ELEMENT * &elem)
220{ return walk(operate, ListElement::overlayVar(elem)); }
221
222// CssmList
223template <class Action>
224void enumerate(Action &operate, CssmList &list)
225{
226	if (!list.empty()) {
227		walk(operate, list.first());
228		if (operate.needsRelinking)
229			list.Tail = list.first()->last();	// re-establish "tail" link
230	}
231}
232
233template <class Action>
234CssmList *walk(Action &operate, CssmList * &list)
235{
236	operate(list);
237	enumerate(operate, *list);
238	return list;
239}
240
241template <class Action>
242void walk(Action &operate, CssmList &list)
243{
244	operate(list);
245	enumerate(operate, list);
246}
247
248template <class Action>
249void walk(Action &operate, CSSM_LIST &list)
250{ walk(operate, CssmList::overlay(list)); }
251
252template <class Action>
253CSSM_LIST *walk(Action &operate, CSSM_LIST * &list)
254{ return walk(operate, CssmList::overlayVar(list)); }
255
256template <class Action>
257TypedList *walk(Action &operate, TypedList * &list)
258{ return static_cast<TypedList *>(walk(operate, reinterpret_cast<CssmList * &>(list))); }
259
260template <class Action>
261void walk(Action &operate, TypedList &list)
262{ walk(operate, static_cast<CssmList &>(list)); }
263
264
265}	// end namespace DataWalkers
266} 	// end namespace Security
267
268
269#endif //_H_CSSMLIST
270