cssmlist.cpp   [plain text]


/*
 * Copyright (c) 2000-2004,2006-2007 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);
}