--- /dev/null
+/*
+ * Copyright (c) 2000-2004,2006-2007,2011 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
+//
+#include <security_cdsa_utilities/cssmlist.h>
+#include <security_cdsa_utilities/cssmdata.h>
+
+
+//
+// Managing list elements
+//
+ListElement *ListElement::last()
+{
+ for (ListElement *p = this; ; p = p->next())
+ if (p->next() == NULL)
+ return p;
+ // not reached
+}
+
+
+ListElement::ListElement(CSSM_WORDID_TYPE word)
+{
+ ElementType = CSSM_LIST_ELEMENT_WORDID;
+ WordID = word;
+}
+
+ListElement::ListElement(const CssmData &data)
+{
+ ElementType = CSSM_LIST_ELEMENT_DATUM;
+ WordID = 0;
+ Element.Word = data;
+}
+
+ListElement::ListElement(Allocator &alloc, const CssmData &data)
+{
+ ElementType = CSSM_LIST_ELEMENT_DATUM;
+ WordID = 0;
+ Element.Word = CssmAutoData(alloc, data).release();
+}
+
+ListElement::ListElement(Allocator &alloc, const string &s)
+{
+ ElementType = CSSM_LIST_ELEMENT_DATUM;
+ WordID = 0;
+ Element.Word = CssmAutoData(alloc, s.data(), s.size()).release();
+}
+
+ListElement::ListElement(const CssmList &list)
+{
+ ElementType = CSSM_LIST_ELEMENT_SUBLIST;
+ WordID = 0;
+ Element.Sublist = list;
+}
+
+
+CssmData &ListElement::data()
+{
+ assert(type() == CSSM_LIST_ELEMENT_DATUM);
+ return CssmData::overlay(Element.Word);
+}
+
+const CssmData &ListElement::data() const
+{
+ assert(type() == CSSM_LIST_ELEMENT_DATUM);
+ return CssmData::overlay(Element.Word);
+}
+
+ListElement &ListElement::operator = (const CssmData &data)
+{
+ assert(type() == CSSM_LIST_ELEMENT_DATUM);
+ Element.Word = data;
+ return *this;
+}
+
+
+CssmList &ListElement::list()
+{
+ assert(type() == CSSM_LIST_ELEMENT_SUBLIST);
+ return CssmList::overlay(Element.Sublist);
+}
+
+const CssmList &ListElement::list() const
+{
+ assert(type() == CSSM_LIST_ELEMENT_SUBLIST);
+ return CssmList::overlay(Element.Sublist);
+}
+
+TypedList &ListElement::typedList()
+{
+ return static_cast<TypedList &>(list());
+}
+
+const TypedList &ListElement::typedList() const
+{
+ return static_cast<const TypedList &>(list());
+}
+
+ListElement &ListElement::operator = (const CssmList &list)
+{
+ assert(type() == CSSM_LIST_ELEMENT_SUBLIST);
+ Element.Sublist = list;
+ return *this;
+}
+
+
+CSSM_WORDID_TYPE ListElement::word() const
+{
+ assert(type() == CSSM_LIST_ELEMENT_WORDID);
+ return WordID;
+}
+
+ListElement &ListElement::operator = (CSSM_WORDID_TYPE word)
+{
+ assert(type() == CSSM_LIST_ELEMENT_WORDID);
+ WordID = word;
+ return *this;
+}
+
+
+//
+// List operations
+//
+ListElement &CssmList::operator [] (unsigned ix) const
+{
+ for (ListElement *elem = first(); elem; elem = elem->next(), ix--) {
+ if (ix == 0)
+ return *elem;
+ }
+ throw 999; //@@@
+}
+
+unsigned int CssmList::length() const
+{
+ unsigned int len = 0;
+ for (ListElement *elem = first(); elem; elem = elem->next())
+ len++;
+ return len;
+}
+
+CssmList &CssmList::append(ListElement *elem)
+{
+ if (Tail == NULL) { // first element
+ Head = Tail = elem;
+ } else {
+ Tail->NextElement = elem;
+ Tail = elem;
+ }
+ elem->NextElement = NULL;
+ return *this;
+}
+
+CssmList &CssmList::insert(ListElement *elem, ListElement *before)
+{
+ // null before -> append
+ if (before == NULL)
+ return append(elem);
+
+ // we have a real position
+ assert(!empty());
+ if (Head == before) { // before first element
+ elem->NextElement = before;
+ Head = elem;
+ } else { // before is not first
+ for (CSSM_LIST_ELEMENT *p = Head; p; p = p->NextElement) {
+ if (p->NextElement == before) {
+ elem->NextElement = before;
+ p->NextElement = elem;
+ return *this;
+ }
+ }
+ // end of list, before not in list
+ throw 999; //@@@
+ }
+ return *this;
+}
+
+CssmList &CssmList::remove(ListElement *elem)
+{
+ assert(elem);
+ if (elem == Head) { // remove first element
+ Head = Head->NextElement;
+ } else { // subsequent element
+ for (CSSM_LIST_ELEMENT *p = Head; p; p = p->NextElement)
+ if (p->NextElement == elem) {
+ p->NextElement = elem->NextElement;
+ if (elem->NextElement == NULL) // removing last element
+ Tail = p;
+ return *this;
+ }
+ // end of list, elem not found
+ throw 999; //@@@
+ }
+ return *this;
+}
+
+void CssmList::snip()
+{
+ assert(Head); // can't be empty
+ if (Head == Tail) { // single element, empty when snipped
+ Head = Tail = NULL;
+ } else { // more than one, bypass first
+ Head = first()->next();
+ }
+}
+
+
+//
+// Deep-destruction of CssmLists and ListElements.
+// The underlying assumption is that all components were allocated from a single
+// Allocator in canonical chunks.
+//
+void ListElement::clear(Allocator &alloc)
+{
+ switch (type()) {
+ case CSSM_LIST_ELEMENT_WORDID:
+ break; // no substructure
+ case CSSM_LIST_ELEMENT_DATUM:
+ alloc.free(data().data());
+ break;
+ case CSSM_LIST_ELEMENT_SUBLIST:
+ list().clear(alloc);
+ break;
+ default:
+ assert(false);
+ }
+}
+
+void CssmList::clear(Allocator &alloc)
+{
+ ListElement *elem = first();
+ while (elem) {
+ ListElement *next = elem->next();
+ destroy(elem, alloc);
+ elem = next;
+ }
+}
+
+
+//
+// Building TypedLists
+//
+TypedList::TypedList(Allocator &alloc, CSSM_WORDID_TYPE type)
+{
+ append(new(alloc) ListElement(type));
+}
+
+TypedList::TypedList(Allocator &alloc, CSSM_WORDID_TYPE type, ListElement *elem1)
+{
+ append(new(alloc) ListElement(type));
+ append(elem1);
+}
+
+TypedList::TypedList(Allocator &alloc, CSSM_WORDID_TYPE type, ListElement *elem1, ListElement *elem2)
+{
+ append(new(alloc) ListElement(type));
+ append(elem1);
+ append(elem2);
+}
+
+TypedList::TypedList(Allocator &alloc, CSSM_WORDID_TYPE type, ListElement *elem1, ListElement *elem2, ListElement *elem3)
+{
+ append(new(alloc) ListElement(type));
+ append(elem1);
+ append(elem2);
+ append(elem3);
+}
+
+TypedList::TypedList(Allocator &alloc, CSSM_WORDID_TYPE type, ListElement *elem1, ListElement *elem2, ListElement *elem3, ListElement *elem4)
+{
+ append(new(alloc) ListElement(type));
+ append(elem1);
+ append(elem2);
+ append(elem3);
+ append(elem4);
+}
+
+
+//
+// Verify that a TypedList is "proper", i.e. has a first element of WORDID form
+//
+bool TypedList::isProper() const
+{
+ return first() && first()->type() == CSSM_LIST_ELEMENT_WORDID;
+}
+
+void TypedList::checkProper(CSSM_RETURN error) const
+{
+ if (!isProper())
+ CssmError::throwMe(error);
+}