#include "PrimaryKey.h"
using namespace KeychainCore;
using namespace CssmClient;
PrimaryKeyImpl::PrimaryKeyImpl(const CSSM_DATA &data)
: CssmDataContainer(data.Data, data.Length)
{
}
PrimaryKeyImpl::PrimaryKeyImpl(const DbAttributes &primaryKeyAttrs)
{
Length = sizeof(uint32);
for (uint32 ix = 0; ix < primaryKeyAttrs.size(); ++ix)
{
if (primaryKeyAttrs.at(ix).size() == 0)
MacOSError::throwMe(errSecInvalidKeychain);
Length += sizeof(uint32) + primaryKeyAttrs.at(ix).Value[0].Length;
}
Data = mAllocator.alloc<uint8>(Length);
uint8 *p = Data;
putUInt32(p, primaryKeyAttrs.recordType());
for (uint32 ix = 0; ix < primaryKeyAttrs.size(); ++ix)
{
uint32 len = primaryKeyAttrs.at(ix).Value[0].Length;
putUInt32(p, len);
memcpy(p, primaryKeyAttrs.at(ix).Value[0].Data, len);
p += len;
}
}
CssmClient::DbCursor
PrimaryKeyImpl::createCursor(const Keychain &keychain)
{
DbCursor cursor(keychain->database());
uint8 *p = Data;
uint32 left = Length;
if (left < sizeof(*p))
MacOSError::throwMe(errSecNoSuchAttr);
CSSM_DB_RECORDTYPE rt = getUInt32(p, left);
const CssmAutoDbRecordAttributeInfo &infos = keychain->primaryKeyInfosFor(rt);
cursor->recordType(rt);
cursor->conjunctive(CSSM_DB_AND);
for (uint32 ix = 0; ix < infos.size(); ++ix)
{
uint32 len = getUInt32(p, left);
if (left < len)
MacOSError::throwMe(errSecNoSuchAttr);
CssmData value(p, len);
left -= len;
p += len;
cursor->add(CSSM_DB_EQUAL, infos.at(ix), value);
}
return cursor;
}
void
PrimaryKeyImpl::putUInt32(uint8 *&p, uint32 value)
{
*p++ = (value >> 24);
*p++ = (value >> 16) & 0xff;
*p++ = (value >> 8) & 0xff;
*p++ = value & 0xff;
}
uint32
PrimaryKeyImpl::getUInt32(uint8 *&p, uint32 &left) const
{
if (left < sizeof(uint32))
MacOSError::throwMe(errSecNoSuchAttr);
uint32 value = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
p += sizeof(uint32);
left -= sizeof(uint32);
return value;
}
CSSM_DB_RECORDTYPE
PrimaryKeyImpl::recordType() const
{
uint8 *data = Data;
uint32 length = Length;
return getUInt32(data, length);
}