X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/OSX/libsecurity_cdsa_utilities/lib/cssmlist.h diff --git a/OSX/libsecurity_cdsa_utilities/lib/cssmlist.h b/OSX/libsecurity_cdsa_utilities/lib/cssmlist.h new file mode 100644 index 00000000..6506b0df --- /dev/null +++ b/OSX/libsecurity_cdsa_utilities/lib/cssmlist.h @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2000-2006,2011,2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// cssmlist - CSSM_LIST operational utilities +// +#ifndef _H_CSSMLIST +#define _H_CSSMLIST + +#include +#include +#include + + +namespace Security { + +class CssmList; +class TypedList; + + +// +// A POD Wrapper for CSSM_LIST_ELEMENTs. +// List elements are pseudo-polymorphic, so we provide ways to get and +// set their three personalities. It's up to the caller to get this right; +// you mustn't (for example) call the data() method on a list element that +// is not of (element) type CSSM_LIST_ELEMENT_DATUM. To violate this rule +// will get you an assertion (not exception). +// +class ListElement : public PodWrapper { +public: + // type control + CSSM_LIST_ELEMENT_TYPE type() const { return ElementType; } + bool is(CSSM_LIST_ELEMENT_TYPE t) const { return type() == t; } + + // list element chaining + ListElement * &next() { return ListElement::overlayVar(NextElement); } + ListElement *next() const { return ListElement::overlay(NextElement); } + ListElement *last(); + + // CssmData personality + explicit ListElement(const CssmData &data); + explicit ListElement(Allocator &alloc, const CssmData &data); + explicit ListElement(Allocator &alloc, const std::string &stringData); + + CssmData &data(); + string toString() const { return data().toString(); } + const CssmData &data() const; + ListElement &operator = (const CssmData &data); + operator CssmData &() { return data(); } + operator std::string () const { return toString(); } + bool operator == (const CssmData &other) const { return data() == other; } + bool operator != (const CssmData &other) const { return data() != other; } + + template + void extract(T &destination, CSSM_RETURN error = CSSM_ERRCODE_INVALID_DATA) + { data().extract(destination, error); } + + // CssmList (sublist) personality + explicit ListElement(const CssmList &list); + CssmList &list(); + const CssmList &list() const; + TypedList &typedList(); + const TypedList &typedList() const; + ListElement &operator = (const CssmList &list); + operator CssmList &() { return list(); } + operator TypedList &(); + + // WORDID (number) personality + explicit ListElement(CSSM_WORDID_TYPE word); + CSSM_WORDID_TYPE word() const; + ListElement &operator = (CSSM_WORDID_TYPE word); + operator CSSM_WORDID_TYPE () const { return word(); } + +public: + void *operator new (size_t size, Allocator &alloc) + { return alloc.malloc(size); } + + void clear(Allocator &alloc); // free my contents +}; + +} // end namespace Security + +// specialize destroy() to call clear() for cleanup +inline void destroy(ListElement *elem, Allocator &alloc) +{ + elem->clear(alloc); + alloc.free(elem); +} + +namespace Security { + + +// +// A POD Wrapper for CSSM_LIST. +// CssmList does no memory allocations. Retrieval functions return pointers or +// references into existing content, and modifiers modify in-place without any +// attempt to release previous dynamic content. May the Leaking God be with You. +// +class CssmList : public PodWrapper { +public: + CssmList() { ListType = CSSM_LIST_TYPE_UNKNOWN; Head = Tail = NULL; } + CssmList(const CssmList &list) { *(CssmList *)this = list; } + +public: + CSSM_LIST_TYPE kind() const { return ListType; } // type() reserved for TypedList + + ListElement &operator [] (unsigned ix) const; + unsigned int length() const; + ListElement * &first() { return ListElement::overlayVar(Head); } + ListElement *first() const { return ListElement::overlay(Head); } + ListElement *last() const { return ListElement::overlay(Tail); } + bool empty() const { return first() == NULL; } + + CssmList &append(ListElement *elem); + CssmList &insert(ListElement *elem, ListElement *before); + CssmList &remove(ListElement *elem); + CssmList &operator += (ListElement *elem) { return append(elem); } + CssmList &operator -= (ListElement *elem) { return remove(elem); } + + // logically remove the first element (skip it) + void snip(); + +public: + void clear(Allocator &alloc); // free my contents +}; + +} // end namespace Security + +inline void destroy(CssmList *list, Allocator &alloc) +{ + list->clear(alloc); + alloc.free(list); +} + +namespace Security +{ + +// +// Enhanced overlay for CssmLists whose first element is known to be a wordid. +// +class TypedList : public CssmList { +public: + explicit TypedList(const CSSM_LIST &list) { *(CSSM_LIST *)this = list; } + TypedList(Allocator &alloc, CSSM_WORDID_TYPE type); + TypedList(Allocator &alloc, CSSM_WORDID_TYPE type, ListElement *elem1); + TypedList(Allocator &alloc, CSSM_WORDID_TYPE type, ListElement *elem1, + ListElement *elem2); + TypedList(Allocator &alloc, CSSM_WORDID_TYPE type, ListElement *elem1, + ListElement *elem2, ListElement *elem3); + TypedList(Allocator &alloc, CSSM_WORDID_TYPE type, ListElement *elem1, + ListElement *elem2, ListElement *elem3, ListElement *elem4); + + bool isProper() const; // format check (does not throw) + void checkProper(CSSM_RETURN error = CSSM_ERRCODE_INVALID_SAMPLE_VALUE) const; + static TypedList &overlay(CSSM_LIST &list) + { return static_cast(list); } + static const TypedList &overlay(const CSSM_LIST &list) + { return static_cast(list); } + + CSSM_WORDID_TYPE type() const + { assert(isProper()); return first()->word(); } +}; + +inline ListElement::operator TypedList &() +{ return TypedList::overlay(operator CssmList &()); } + + +// +// Data walkers to parse list elements and lists. +// @@@ Walking lists by recursing over next() is stack intensive. Do this in CssmList walker by loop? +// +namespace DataWalkers { + +// ListElement +template +ListElement *walk(Action &operate, ListElement * &elem) +{ + operate(elem); + switch (elem->type()) { + case CSSM_LIST_ELEMENT_DATUM: + walk(operate, elem->data()); + break; + case CSSM_LIST_ELEMENT_SUBLIST: + walk(operate, elem->list()); + break; + case CSSM_LIST_ELEMENT_WORDID: + break; + default: + secdebug("walkers", "invalid list element type (%ux)", (unsigned)elem->type()); + break; + } + if (elem->next()) + walk(operate, elem->next()); + return elem; +} + +template +ListElement *walk(Action &operate, CSSM_LIST_ELEMENT * &elem) +{ return walk(operate, ListElement::overlayVar(elem)); } + +// CssmList +template +void enumerate(Action &operate, CssmList &list) +{ + if (!list.empty()) { + walk(operate, list.first()); + if (operate.needsRelinking) + list.Tail = list.first()->last(); // re-establish "tail" link + } +} + +template +CssmList *walk(Action &operate, CssmList * &list) +{ + operate(list); + enumerate(operate, *list); + return list; +} + +template +void walk(Action &operate, CssmList &list) +{ + operate(list); + enumerate(operate, list); +} + +template +void walk(Action &operate, CSSM_LIST &list) +{ walk(operate, CssmList::overlay(list)); } + +template +CSSM_LIST *walk(Action &operate, CSSM_LIST * &list) +{ return walk(operate, CssmList::overlayVar(list)); } + +template +TypedList *walk(Action &operate, TypedList * &list) +{ return static_cast(walk(operate, reinterpret_cast(list))); } + +template +void walk(Action &operate, TypedList &list) +{ walk(operate, static_cast(list)); } + + +} // end namespace DataWalkers +} // end namespace Security + + +#endif //_H_CSSMLIST