#include <security_cdsa_utilities/cssmlist.h>
#include <security_cdsa_utilities/cssmdata.h>
ListElement *ListElement::last()
{
for (ListElement *p = this; ; p = p->next())
if (p->next() == NULL)
return p;
}
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;
}
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) { Head = Tail = elem;
} else {
Tail->NextElement = elem;
Tail = elem;
}
elem->NextElement = NULL;
return *this;
}
CssmList &CssmList::insert(ListElement *elem, ListElement *before)
{
if (before == NULL)
return append(elem);
assert(!empty());
if (Head == before) { elem->NextElement = before;
Head = elem;
} else { for (CSSM_LIST_ELEMENT *p = Head; p; p = p->NextElement) {
if (p->NextElement == before) {
elem->NextElement = before;
p->NextElement = elem;
return *this;
}
}
throw 999; }
return *this;
}
CssmList &CssmList::remove(ListElement *elem)
{
assert(elem);
if (elem == Head) { Head = Head->NextElement;
} else { for (CSSM_LIST_ELEMENT *p = Head; p; p = p->NextElement)
if (p->NextElement == elem) {
p->NextElement = elem->NextElement;
if (elem->NextElement == NULL) Tail = p;
return *this;
}
throw 999; }
return *this;
}
void CssmList::snip()
{
assert(Head); if (Head == Tail) { Head = Tail = NULL;
} else { Head = first()->next();
}
}
void ListElement::clear(Allocator &alloc)
{
switch (type()) {
case CSSM_LIST_ELEMENT_WORDID:
break; 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;
}
}
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);
}
bool TypedList::isProper() const
{
return first() && first()->type() == CSSM_LIST_ELEMENT_WORDID;
}
void TypedList::checkProper(CSSM_RETURN error) const
{
if (!isProper())
CssmError::throwMe(error);
}