#include "DbValue.h"
DbValue::~DbValue()
{
}
UInt32Value::UInt32Value(const ReadSection &rs, uint32 &offset)
: BasicValue<uint32>(rs.at(offset))
{
offset += size();
}
UInt32Value::UInt32Value(const CSSM_DATA &data)
{
switch (data.Length)
{
case 1:
mValue = *reinterpret_cast<uint8 *>(data.Data);
break;
case 2:
mValue = *reinterpret_cast<uint16 *>(data.Data);
break;
case 4:
mValue = *reinterpret_cast<uint32 *>(data.Data);
break;
default:
CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
}
}
UInt32Value::~UInt32Value()
{
}
void
UInt32Value::pack(WriteSection &ws, uint32 &offset) const
{
offset = ws.put(offset, mValue);
}
SInt32Value::SInt32Value(const ReadSection &rs, uint32 &offset)
: BasicValue<sint32>(static_cast<sint32>(rs.at(offset)))
{
offset += size();
}
SInt32Value::SInt32Value(const CSSM_DATA &data)
{
switch (data.Length)
{
case 1:
mValue = *reinterpret_cast<sint8 *>(data.Data);
break;
case 2:
mValue = *reinterpret_cast<sint16 *>(data.Data);
break;
case 4:
mValue = *reinterpret_cast<sint32 *>(data.Data);
break;
default:
CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
}
}
SInt32Value::~SInt32Value()
{
}
void
SInt32Value::pack(WriteSection &ws, uint32 &offset) const
{
offset = ws.put(offset, static_cast<uint32>(mValue));
}
DoubleValue::DoubleValue(const ReadSection &rs, uint32 &offset)
{
Range r(offset, size());
mValue = *reinterpret_cast<const double *>(rs.range(r));
offset += size();
}
DoubleValue::DoubleValue(const CSSM_DATA &data)
{
switch (data.Length)
{
case 4:
mValue = *reinterpret_cast<float *>(data.Data);
break;
case 8:
mValue = *reinterpret_cast<double *>(data.Data);
break;
default:
CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
}
}
DoubleValue::~DoubleValue()
{
}
void
DoubleValue::pack(WriteSection &ws, uint32 &offset) const
{
offset = ws.put(offset, size(), bytes());
}
BlobValue::BlobValue(const ReadSection &rs, uint32 &offset)
{
Length = rs.at(offset);
Data = const_cast<uint8 *>(rs.range(Range(offset + AtomSize, Length)));
offset = ReadSection::align(offset + Length + AtomSize);
}
BlobValue::BlobValue(const CSSM_DATA &data)
: CssmData(CssmData::overlay(data))
{
}
BlobValue::~BlobValue()
{
}
void
BlobValue::pack(WriteSection &ws, uint32 &offset) const
{
offset = ws.put(offset, Length);
offset = ws.put(offset, Length, Data);
}
BlobValue::Comparator::~Comparator()
{
}
int
BlobValue::Comparator::operator () (const uint8 *ptr1, const uint8 *ptr2, uint32 length)
{
return memcmp(ptr1, ptr2, length);
}
bool
BlobValue::evaluate(const BlobValue &other, CSSM_DB_OPERATOR op) const
{
return evaluate(*this, other, op, Comparator());
}
bool
BlobValue::evaluate(const CssmData &inData1, const CssmData &inData2, CSSM_DB_OPERATOR op,
Comparator compare)
{
uint32 length1 = inData1.Length, length2 = inData2.Length;
const uint8 *data1 = inData1.Data;
const uint8 *data2 = inData2.Data;
switch (op) {
case CSSM_DB_CONTAINS_INITIAL_SUBSTRING:
if (length1 > length2)
return false;
length2 = length1;
goto DB_EQUAL;
case CSSM_DB_CONTAINS_FINAL_SUBSTRING:
if (length1 > length2)
return false;
data2 += (length2 - length1);
length2 = length1;
case CSSM_DB_EQUAL:
DB_EQUAL:
if (length1 != length2)
return false;
if (length1 == 0)
return true;
return compare(data1, data2, length1) == 0;
case CSSM_DB_NOT_EQUAL:
if (length1 != length2)
return true;
if (length1 == 0)
return false;
return compare(data1, data2, length1) != 0;
case CSSM_DB_LESS_THAN:
case CSSM_DB_GREATER_THAN:
{
uint32 length = min(length1, length2);
int result = (length == 0) ? 0 : compare(data1, data2, length);
if (result < 0 || (result == 0 && length1 < length2))
return op == CSSM_DB_LESS_THAN;
else if (result > 0 || (result == 0 && length1 > length2))
return op == CSSM_DB_GREATER_THAN;
break;
}
case CSSM_DB_CONTAINS:
if (length1 > length2)
return false;
if (length1 == 0)
return true;
for (const uint8 *data = data2; data + length1 <= data2 + length2; data++)
if (compare(data1, data, length1) == 0)
return true;
break;
default:
CssmError::throwMe(CSSMERR_DL_UNSUPPORTED_QUERY);
}
return false;
}
TimeDateValue::TimeDateValue(const ReadSection &rs, uint32 &offset)
{
Length = kTimeDateSize;
Data = const_cast<uint8 *>(rs.range(Range(offset, Length)));
offset = ReadSection::align(offset + Length);
}
TimeDateValue::TimeDateValue(const CSSM_DATA &data)
: BlobValue(data)
{
if (Length != kTimeDateSize || !isValidDate())
CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
}
TimeDateValue::~TimeDateValue()
{
}
void
TimeDateValue::pack(WriteSection &ws, uint32 &offset) const
{
offset = ws.put(offset, Length, Data);
}
bool
TimeDateValue::isValidDate() const
{
if (Length != kTimeDateSize || Data[kTimeDateSize - 1] != 0 ||
Data[kTimeDateSize - 2] != 'Z')
return false;
for (uint32 i = 0; i < kTimeDateSize - 2; i++)
if (!isdigit(Data[i]))
return false;
uint32 month = rangeValue(4, 2);
if (month < 1 || month > 12)
return false;
uint32 day = rangeValue(6, 2);
if (day < 1 || day > 31)
return false;
uint32 hour = rangeValue(8, 2);
if (hour < 0 || hour > 23)
return false;
uint32 minute = rangeValue(10, 2);
if (minute < 0 || minute > 59)
return false;
uint32 second = rangeValue(12, 2);
if (second < 0 || second > 59)
return false;
return true;
}
uint32
TimeDateValue::rangeValue(uint32 start, uint32 length) const
{
uint32 value = 0;
for (uint32 i = 0; i < length; i++)
value = value * 10 + Data[start + i] - '0';
return value;
}
StringValue::StringValue(const ReadSection &rs, uint32 &offset)
: BlobValue(rs, offset)
{
}
StringValue::StringValue(const CSSM_DATA &data)
: BlobValue(data)
{
}
StringValue::~StringValue()
{
}
int
StringValue::Comparator::operator () (const uint8 *ptr1, const uint8 *ptr2, uint32 length)
{
return strncmp(reinterpret_cast<const char *>(ptr1),
reinterpret_cast<const char *>(ptr2), length);
}
bool
StringValue::evaluate(const StringValue &other, CSSM_DB_OPERATOR op) const
{
return BlobValue::evaluate(*this, other, op, StringValue::Comparator());
}
BigNumValue::BigNumValue(const ReadSection &rs, uint32 &offset)
: BlobValue(rs, offset)
{
}
BigNumValue::BigNumValue(const CSSM_DATA &data)
: BlobValue(data)
{
while (Length > 1 && Data[Length - 1] == 0)
Length--;
if (Length == 1 && (Data[0] & ~kSignBit) == 0)
Length = 0;
}
BigNumValue::~BigNumValue()
{
}
int
BigNumValue::compare(const uint8 *a, const uint8 *b, int length)
{
for (int diff, i = length - 1; i >= 1; i--)
if (diff = a[i] - b[i])
return diff;
return (a[0] & ~kSignBit) - (b[0] & ~kSignBit);
}
bool
BigNumValue::evaluate(const BigNumValue &other, CSSM_DB_OPERATOR op) const
{
uint32 length1 = Length, length2 = other.Length;
uint8 sign1 = length1 ? (Data[0] & kSignBit) : 0;
uint8 sign2 = length2 ? (other.Data[0] & kSignBit) : 0;
switch (op)
{
case CSSM_DB_EQUAL:
case CSSM_DB_NOT_EQUAL:
return BlobValue::evaluate(other, op);
case CSSM_DB_LESS_THAN:
if (sign1 ^ sign2)
return sign1;
else if (length1 != length2)
return sign1 ? (length1 > length2) : (length1 < length2);
else {
int c = compare(Data, other.Data, length1);
return sign1 ? (c > 0) : (c < 0);
}
break;
case CSSM_DB_GREATER_THAN:
if (sign1 ^ sign2)
return sign2;
else if (length1 != length2)
return sign1 ? (length1 < length2) : (length1 > length2);
else {
int c = compare(Data, other.Data, length1);
return sign1 ? (c < 0) : (c > 0);
}
break;
case CSSM_DB_CONTAINS:
case CSSM_DB_CONTAINS_INITIAL_SUBSTRING:
case CSSM_DB_CONTAINS_FINAL_SUBSTRING:
default:
CssmError::throwMe(CSSMERR_DL_UNSUPPORTED_QUERY);
}
}
MultiUInt32Value::MultiUInt32Value(const ReadSection &rs, uint32 &offset)
{
mNumValues = rs.at(offset);
mValues = new uint32[mNumValues];
for (uint32 i = 0; i < mNumValues; i++)
mValues[i] = rs.at(offset + (i + 1) * AtomSize);
offset = ReadSection::align(offset + (mNumValues + 1) * AtomSize);
mOwnsValues = true;
}
MultiUInt32Value::MultiUInt32Value(const CSSM_DATA &data)
{
if (data.Length & (sizeof(uint32) - 1))
CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
mNumValues = data.Length / sizeof(uint32);
mValues = reinterpret_cast<uint32 *>(data.Data);
mOwnsValues = false;
}
MultiUInt32Value::~MultiUInt32Value()
{
if (mOwnsValues)
delete [] mValues;
}
void
MultiUInt32Value::pack(WriteSection &ws, uint32 &offset) const
{
offset = ws.put(offset, mNumValues);
for (uint32 i = 0; i < mNumValues; i++)
offset = ws.put(offset, mValues[i]);
}
static inline int
uint32cmp(const uint32 *a, const uint32 *b, uint32 length)
{
return memcmp(a, b, length * sizeof(uint32));
}
bool
MultiUInt32Value::evaluate(const MultiUInt32Value &other, CSSM_DB_OPERATOR op) const
{
uint32 length1 = mNumValues, length2 = other.mNumValues;
const uint32 *values1 = mValues;
const uint32 *values2 = other.mValues;
switch (op)
{
case CSSM_DB_EQUAL:
if (length1 == length2)
return uint32cmp(values1, values2, length1) == 0;
break;
case CSSM_DB_NOT_EQUAL:
if (length1 != length2 || uint32cmp(values1, values2, length1))
return true;
break;
case CSSM_DB_CONTAINS_INITIAL_SUBSTRING:
if (length1 <= length2)
return uint32cmp(values1, values2, length1) == 0;
break;
case CSSM_DB_CONTAINS_FINAL_SUBSTRING:
if (length1 <= length2)
return uint32cmp(values1, values2 + (length2 - length1), length1) == 0;
break;
case CSSM_DB_CONTAINS:
if (length1 <= length2) {
if (length1 == 0)
return true;
for (const uint32 *values = values2; values + length1 < values2 + length2; values++)
if (uint32cmp(values1, values, length1) == 0)
return true;
}
break;
case CSSM_DB_LESS_THAN:
if (length1 < length2)
return true;
else if (length1 == length2)
return uint32cmp(values1, values2, length1) < 0;
break;
default:
CssmError::throwMe(CSSMERR_DL_UNSUPPORTED_QUERY);
}
return false;
}