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