#ifndef _H_CDSA_CLIENT_DLITERATORS
#define _H_CDSA_CLIENT_DLITERATORS
#include <security_utilities/threading.h>
#include <security_utilities/globalizer.h>
#include <security_utilities/refcount.h>
#include <security_cdsa_utilities/cssmalloc.h>
#include <security_cdsa_utilities/cssmpods.h>
#include <security_cdsa_utilities/cssmerrors.h>
#include <security_cdsa_utilities/cssmdb.h>
#include <security_cdsa_client/dlquery.h>
namespace Security {
namespace CssmClient {
class DLAccess {
public:
virtual ~DLAccess();
virtual CSSM_HANDLE dlGetFirst(const CSSM_QUERY &query,
CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes, CSSM_DATA *data,
CSSM_DB_UNIQUE_RECORD *&id) = 0;
virtual bool dlGetNext(CSSM_HANDLE handle,
CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes, CSSM_DATA *data,
CSSM_DB_UNIQUE_RECORD *&id) = 0;
virtual void dlAbortQuery(CSSM_HANDLE handle) = 0;
virtual void dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id) = 0;
virtual void dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id) = 0;
virtual Allocator &allocator() = 0;
};
class Record : public RefCount, public CssmAutoData {
public:
Record() : CssmAutoData(Allocator::standard(Allocator::sensitive)) { }
Record(const char * const * attributeNames); virtual ~Record();
static const CSSM_DB_RECORDTYPE recordType = CSSM_DL_DB_RECORD_ANY;
void addAttributes(const char * const * attributeNames);
CssmDbRecordAttributeData &attributes() { return mAttributes; }
const CssmDbRecordAttributeData &attributes() const { return mAttributes; }
CSSM_DB_RECORDTYPE actualRecordType() const { return mAttributes.recordType(); }
CssmAutoData &recordData() { return *this; }
protected:
CssmAutoDbRecordAttributeData mAttributes;
};
class TableBase {
public:
DLAccess &database;
CSSM_DB_RECORDTYPE recordType() const { return mRecordType; }
void recordType(CSSM_DB_RECORDTYPE t) { mRecordType = t; }
uint32 erase(const CSSM_QUERY &query);
uint32 erase(const Query &query);
protected:
TableBase(DLAccess &source, CSSM_DB_RECORDTYPE type, bool getData = true);
class AccessRef : public RefCount {
protected:
AccessRef() : mAccess(NULL) { }
AccessRef(DLAccess *ac) : mAccess(ac) { }
DLAccess *mAccess;
};
struct Handle : public AccessRef {
CSSM_HANDLE query;
Handle(DLAccess *ac, CSSM_HANDLE q) : AccessRef(ac), query(q) { }
~Handle();
};
struct Uid : public AccessRef {
CSSM_DB_UNIQUE_RECORD *uid;
Uid(DLAccess *ac, CSSM_DB_UNIQUE_RECORD *id) : AccessRef(ac), uid(id) { }
~Uid();
};
class Iterator {
public:
const CSSM_DB_UNIQUE_RECORD *recordHandle() const
{ assert(mUid); return mUid->uid; }
protected:
Iterator() { }
Iterator(DLAccess *ac, CSSM_HANDLE query, CSSM_DB_UNIQUE_RECORD *id,
Record *record, bool getData);
void advance(Record *newRecord);
DLAccess *mAccess; RefPointer<Handle> mQuery; RefPointer<Uid> mUid; RefPointer<Record> mRecord; bool mGetData; };
protected:
CSSM_DB_RECORDTYPE mRecordType; bool mGetData; };
template <class RecordType>
class Table : private TableBase {
typedef RefPointer<RecordType> RecPtr;
public:
Table(DLAccess &source) : TableBase(source, RecordType::recordType) { }
Table(DLAccess &source, CSSM_DB_RECORDTYPE type) : TableBase(source, type) { }
Table(DLAccess &source, bool getData) : TableBase(source, RecordType::recordType, getData) { }
public:
class iterator : public Iterator,
public std::iterator<forward_iterator_tag, RefPointer<RecordType> > {
friend class Table;
public:
iterator() { }
bool operator == (const iterator &other) const
{ return mUid.get() == other.mUid.get(); }
bool operator != (const iterator &other) const
{ return mUid.get() != other.mUid.get(); }
RecPtr operator * () const { return static_cast<RecordType *>(mRecord.get()); }
RecordType *operator -> () const { return static_cast<RecordType *>(mRecord.get()); }
iterator operator ++ () { advance(new RecordType); return *this; }
iterator operator ++ (int) { iterator old = *this; operator ++ (); return old; }
void erase();
private:
iterator(DLAccess *ac, CSSM_HANDLE query, CSSM_DB_UNIQUE_RECORD *id,
RecordType *record, bool getData)
: Iterator(ac, query, id, record, getData) { }
};
public:
iterator begin();
iterator find(const CSSM_QUERY &query);
iterator find(const Query &query);
iterator end() { return iterator(); }
RecPtr fetch(const Query &query, CSSM_RETURN err = CSSM_OK) { return fetchFirst(find(query), err); }
RecPtr fetch(CSSM_RETURN err = CSSM_OK) { return fetchFirst(begin(), err); }
void erase(const CSSM_QUERY &query);
void erase(const Query &query);
void erase(iterator it) { it.erase(); }
private:
iterator startQuery(const CssmQuery &query, bool getData);
RecPtr fetchFirst(iterator it, CSSM_RETURN err);
};
template <class RecordType>
typename Table<RecordType>::iterator Table<RecordType>::begin()
{
return startQuery(CssmQuery(mRecordType), mGetData);
}
template <class RecordType>
typename Table<RecordType>::iterator Table<RecordType>::find(const CSSM_QUERY &query)
{
return startQuery(CssmQuery(CssmQuery::overlay(query), mRecordType), mGetData);
}
template <class RecordType>
typename Table<RecordType>::iterator Table<RecordType>::find(const Query &query)
{
return startQuery(CssmQuery(query.cssmQuery(), mRecordType), mGetData);
}
template <class RecordType>
RefPointer<RecordType> Table<RecordType>::fetchFirst(iterator it, CSSM_RETURN err)
{
if (it == end())
if (err)
CssmError::throwMe(err);
else
return NULL;
else
return *it;
}
template <class RecordType>
typename Table<RecordType>::iterator Table<RecordType>::startQuery(const CssmQuery &query, bool getData)
{
RefPointer<RecordType> record = new RecordType;
CSSM_DB_UNIQUE_RECORD *id;
CssmAutoData data(database.allocator());
CSSM_HANDLE queryHandle = database.dlGetFirst(query, record->attributes(),
getData ? &data.get() : NULL, id);
if (queryHandle == CSSM_INVALID_HANDLE)
return end(); if (getData)
record->recordData() = data;
return iterator(&database, queryHandle, id, record, getData);
}
template <class RecordType>
void Table<RecordType>::iterator::erase()
{
mAccess->dlDeleteRecord(mUid->uid);
mUid->uid = NULL;
}
} }
#endif // _H_CDSA_CLIENT_DLITERATORS