/* * Copyright (c) 2004 Apple Computer, 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@ */ #include "Relation.h" #include #include "CommonCode.h" Value::Value (CSSM_DB_ATTRIBUTE_FORMAT format) : mBaseFormat (format) { } Value::~Value () { } Value* Value::MakeValueFromAttributeData (const CSSM_DB_ATTRIBUTE_DATA& info) { switch (info.Info.AttributeFormat) { case CSSM_DB_ATTRIBUTE_FORMAT_STRING: { return new StringValue ((char*) info.Value->Data, info.Value->Length); } case CSSM_DB_ATTRIBUTE_FORMAT_SINT32: { return new SInt32Value (*(sint32*) info.Value->Data); } case CSSM_DB_ATTRIBUTE_FORMAT_UINT32: { return new UInt32Value (*(uint32*) info.Value->Data); } case CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM: { return new BigNumValue (info.Value->Data, info.Value->Length); } case CSSM_DB_ATTRIBUTE_FORMAT_REAL: { return new RealValue (*(double*) info.Value->Data); } case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE: { return new TimeDateValue ((char*) info.Value->Data); } case CSSM_DB_ATTRIBUTE_FORMAT_BLOB: { return new BlobValue (info.Value->Data, info.Value->Length); } } CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_FIELD_FORMAT); } StringValue::StringValue (const char* value) : Value (CSSM_DB_ATTRIBUTE_FORMAT_STRING), mValue (value) { } StringValue::StringValue (const char* value, uint32 length) : Value (CSSM_DB_ATTRIBUTE_FORMAT_STRING), mValue (value, length) { } uint8* StringValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size) { // clone the string size = mValue.length (); char* s = (char*) ai->malloc (size + 1); strcpy (s, mValue.c_str ()); numberOfItems = 1; return (uint8*) s; } bool StringValue::Compare (Value* v, CSSM_DB_OPERATOR op) { if (v->GetValueType () != mBaseFormat) { CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); } StringValue* sv = (StringValue*) v; const char* vRaw = sv->GetRawValue (); const char* myRaw = GetRawValue (); switch (op) { case CSSM_DB_EQUAL: return strcmp (myRaw, vRaw) == 0; case CSSM_DB_NOT_EQUAL: return strcmp (myRaw, vRaw) != 0; case CSSM_DB_LESS_THAN: return strcmp (myRaw, vRaw) < 0; case CSSM_DB_GREATER_THAN: return strcmp (myRaw, vRaw) > 0; default: break; } const char* strLocation = strstr (vRaw, myRaw); switch (op) { case CSSM_DB_CONTAINS: return strLocation != NULL; case CSSM_DB_CONTAINS_INITIAL_SUBSTRING: return strLocation == myRaw; case CSSM_DB_CONTAINS_FINAL_SUBSTRING: { int vRawLen = strlen (vRaw); int myRawLen = strlen (myRaw); return strLocation == myRaw + myRawLen - vRawLen; } } CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR); } SInt32Value::SInt32Value (const sint32 value) : Value (CSSM_DB_ATTRIBUTE_FORMAT_SINT32), mValue (value) {} bool SInt32Value::Compare (Value* v, CSSM_DB_OPERATOR op) { if (v->GetValueType () != mBaseFormat) { CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); } SInt32Value* sv = (SInt32Value*) v; sint32 vRaw = sv->GetRawValue (); sint32 myRaw = GetRawValue (); switch (op) { case CSSM_DB_EQUAL: return vRaw == myRaw; case CSSM_DB_NOT_EQUAL: return vRaw != myRaw; case CSSM_DB_LESS_THAN: return myRaw < vRaw; case CSSM_DB_GREATER_THAN: return myRaw > vRaw; } CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR); } uint8* SInt32Value::CloneContents (AttachedInstance* ai, uint32 &numberOfItems, uint32 &size) { sint32* result = (sint32*) ai->malloc (sizeof (sint32)); *result = mValue; size = sizeof (sint32); numberOfItems = 1; return (uint8*) result; } UInt32Value::UInt32Value (const uint32 value) : Value (CSSM_DB_ATTRIBUTE_FORMAT_UINT32) { mValue = value; } uint8* UInt32Value::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size) { uint32* result = (uint32*) ai->malloc (sizeof (uint32)); *result = mValue; size = sizeof (uint32); numberOfItems = 1; return (uint8*) result; } bool UInt32Value::Compare (Value* v, CSSM_DB_OPERATOR op) { if (v->GetValueType () != mBaseFormat) { CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); } UInt32Value* sv = (UInt32Value*) v; uint32 vRaw = sv->GetRawValue (); uint32 myRaw = GetRawValue (); switch (op) { case CSSM_DB_EQUAL: return vRaw == myRaw; case CSSM_DB_NOT_EQUAL: return vRaw != myRaw; case CSSM_DB_LESS_THAN: return myRaw < vRaw; case CSSM_DB_GREATER_THAN: return myRaw > vRaw; } CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR); } BigNumValue::BigNumValue (const uint8* value, size_t size) : Value (CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM), mLengthCache (-1) { mSize = size; mValue = new uint8[size]; memmove (mValue, value, size); } BigNumValue::~BigNumValue () { delete mValue; } uint8* BigNumValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size) { uint8* returnValue = (uint8*) ai->malloc (mSize); size = mSize; memmove (returnValue, mValue, size); numberOfItems = 1; return (uint8*) returnValue; } bool BigNumValue::GetSignBit () { return mValue[mSize - 1] & 0x80 != 0; } int BigNumValue::GetAdjustedLength () { if (mLengthCache != -1) { return mLengthCache; } // find the first non-zero byte. // Handle the sign bit properly int i = mSize - 1; int value = mValue[i--] & 0x7F; // search for the first non-zero byte while (i >= 0 && value == 0) { value = mValue[i--]; } i += 1; if (i == 0) // zero length? { mLengthCache = 1; } else { mLengthCache = i; } return mLengthCache; } int BigNumValue::GetByte (int i) { // return the bytes of the bignum, compensating for the sign bit if (i == (int) (mSize - 1)) { return mValue[i] & 0x7F; } else { return mValue[i]; } } bool BigNumValue::CompareSignBits (BigNumValue *v, int &result) { bool compareSignBit = v->GetSignBit (); bool mySignBit = GetSignBit (); if (!compareSignBit && mySignBit) { result = 1; return true; } else if (compareSignBit && !mySignBit) { result = -1; return true; } return false; } bool BigNumValue::CompareLengths (BigNumValue *v, int &result) { int vSize = v->GetAdjustedLength (); int mySize = GetAdjustedLength (); if (vSize == mySize) { return false; } result = vSize - mySize; return true; } bool BigNumValue::CompareValues (BigNumValue *v, int &result) { // handle the first byte specially, since it contains the sign bit int offset = GetAdjustedLength () - 1; result = v->GetByte(offset) - GetByte (offset); offset -= 1; while (offset >= 0 && result == 0) { result = v->GetByte(offset) - GetByte (offset); offset -= 1; } return true; } bool BigNumValue::Compare (Value *v, CSSM_DB_OPERATOR op) { if (v->GetValueType () != mBaseFormat) { CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); } BigNumValue* sv = (BigNumValue*) v; int result; if (!CompareSignBits (sv, result)) { if (!CompareLengths (sv, result)) { CompareValues (sv, result); } } switch (op) { case CSSM_DB_EQUAL: return result == 0; case CSSM_DB_NOT_EQUAL: return result != 0; case CSSM_DB_LESS_THAN: return result < 0; case CSSM_DB_GREATER_THAN: return result > 0; } CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR); } RealValue::RealValue (double value) : Value (CSSM_DB_ATTRIBUTE_FORMAT_REAL), mValue (value) {} uint8* RealValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size) { double* result = (double*) ai->malloc (sizeof (double)); *result = (double) mValue; size = sizeof (double); numberOfItems = 1; return (uint8*) result; } bool RealValue::Compare (Value* v, CSSM_DB_OPERATOR op) { if (v->GetValueType () != mBaseFormat) { CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); } RealValue* sv = (RealValue*) v; double vRaw = sv->GetRawValue (); double myRaw = GetRawValue (); switch (op) { case CSSM_DB_EQUAL: return vRaw == myRaw; case CSSM_DB_NOT_EQUAL: return vRaw != myRaw; case CSSM_DB_LESS_THAN: return myRaw < vRaw; case CSSM_DB_GREATER_THAN: return myRaw > vRaw; } CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR); } TimeDateValue::TimeDateValue (time_t tv) : Value (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE), mValue (tv) {} int CharToNum (char c) { return c - '0'; } TimeDateValue::TimeDateValue (const char* td) : Value (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE) { struct tm tmStruct; memset (&tmStruct, 0, sizeof (tmStruct)); tmStruct.tm_year = CharToNum (td[0]) * 1000 + CharToNum (td[1]) * 100 + CharToNum (td[2]) * 10 + CharToNum (td[3]) - 1900; tmStruct.tm_mon = CharToNum (td[4]) * 10 + CharToNum (td[5]) - 1; tmStruct.tm_mday = CharToNum (td[6]) * 10 + CharToNum (td[7]); tmStruct.tm_hour = CharToNum (td[8]) * 10 + CharToNum (td[9]); tmStruct.tm_min = CharToNum (td[10]) * 10 + CharToNum (td[11]); tmStruct.tm_sec = CharToNum (td[12]) * 10 + CharToNum (td[13]); mValue = timegm (&tmStruct); } uint8* TimeDateValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size) { struct tm timeStruct; gmtime_r (&mValue, &timeStruct); char buffer[32]; sprintf (buffer, "%04d%02d%02d%0d2%0d%02dZ", timeStruct.tm_year, timeStruct.tm_mon + 1, timeStruct.tm_mday, timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec); size = strlen (buffer); char* result = (char*) ai->malloc (size + 1); strcpy (result, buffer); numberOfItems = 1; return (uint8*) result; } bool TimeDateValue::Compare (Value* v, CSSM_DB_OPERATOR op) { if (v->GetValueType () != mBaseFormat) { CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); } TimeDateValue* sv = (TimeDateValue*) v; time_t vRaw = sv->GetRawValue (); time_t myRaw = GetRawValue (); switch (op) { case CSSM_DB_EQUAL: return vRaw == myRaw; case CSSM_DB_NOT_EQUAL: return vRaw != myRaw; case CSSM_DB_LESS_THAN: return myRaw < vRaw; case CSSM_DB_GREATER_THAN: return myRaw > vRaw; } CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR); } BlobValue::BlobValue (const uint8* value, size_t size) : Value (CSSM_DB_ATTRIBUTE_FORMAT_BLOB), mSize (size) { mValue = new uint8[size]; memmove (mValue, value, size); } BlobValue::~BlobValue () { delete mValue; } template void ComputeKMPNext (const T* substring, int64_t* nextArray, size_t substringLength) { int i, j; nextArray[0] = -1; for (i = 0, j = -1; i < (ssize_t) substringLength; i++, j++, nextArray[i] = j) { while ((j >= 0) && (substring[i] != substring[j])) { j = nextArray[j]; } } } template int KMPSearch (const T* substring, size_t subLength, const T* mainString, size_t mainLength) { int i, j; // make a "next" array int64_t* nextArray = new int64_t[subLength]; ComputeKMPNext (substring, nextArray, subLength); for (i = 0, j = 0; j < (ssize_t) subLength && i < (ssize_t) mainLength; ++i, ++j) { while ((j >= 0) && (mainString[i] != substring[j])) { j = nextArray[j]; } } delete [] nextArray; if (j == (ssize_t) subLength) { return i - subLength; } return i; } template bool CompareBlobs (const T* a, size_t aLength, const T* b, size_t bLength) { if (aLength != bLength) { return false; } unsigned i; for (i = 0; i < aLength; ++i) { if (a[i] != b[i]) { return false; } } return true; } uint8* BlobValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size) { // clone the data size = mSize; uint8* returnValue = (uint8*) ai->malloc (mSize); memmove (returnValue, mValue, mSize); numberOfItems = 1; return (uint8*) returnValue; } bool BlobValue::Compare (Value* v, CSSM_DB_OPERATOR op) { if (v->GetValueType () != mBaseFormat) { CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); } BlobValue* sv = (BlobValue*) v; const uint8 *vRaw, *myRaw; size_t vLength, myLength; vRaw = sv->GetRawValue (vLength); myRaw = GetRawValue (myLength); switch (op) { case CSSM_DB_EQUAL: return CompareBlobs (vRaw, vLength, myRaw, myLength); case CSSM_DB_NOT_EQUAL: return !CompareBlobs (vRaw, vLength, myRaw, myLength); case CSSM_DB_CONTAINS: return KMPSearch (vRaw, vLength, myRaw, myLength) >= 0; case CSSM_DB_CONTAINS_INITIAL_SUBSTRING: return KMPSearch (vRaw, vLength, myRaw, myLength) == 0; case CSSM_DB_CONTAINS_FINAL_SUBSTRING: return KMPSearch (vRaw, vLength, myRaw, myLength) == (ssize_t) (myLength - vLength); } CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR); } Tuple::Tuple () {} Tuple::~Tuple () {} Query::Query (Relation* relation, const CSSM_QUERY *queryBase) : mSelectionPredicates (NULL), mRelation (relation) { mConjunction = queryBase->Conjunctive; // fill out the rest of the fields based on queryBase mNumSelectionPredicates = queryBase->NumSelectionPredicates; if (mNumSelectionPredicates >= 2 && mConjunction == CSSM_DB_NONE) { CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_QUERY); } if (mNumSelectionPredicates >= 1) { mSelectionPredicates = new CssmSelectionPredicate[mNumSelectionPredicates]; // copy the selection predicates unsigned i; for (i = 0; i < mNumSelectionPredicates; ++i) { mSelectionPredicates[i] = *(CssmSelectionPredicate*) (queryBase->SelectionPredicate + i); } // lookup the number of selection mColumnIDs = new int [mNumSelectionPredicates]; for (i = 0; i < mNumSelectionPredicates; ++i) { uint32 columnID; switch (mSelectionPredicates[i].GetAttributeNameFormat ()) { case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: // if we have an attribute name format of CSSM_ columnID = relation->GetColumnNumber (mSelectionPredicates[i].GetAttributeName ()); break; case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: columnID = mSelectionPredicates[i].GetAttributeID (); break; case CSSM_DB_ATTRIBUTE_NAME_AS_OID: CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_QUERY); break; } mColumnIDs[i] = columnID; } mValues = new Value*[mNumSelectionPredicates]; for (i = 0; i < mNumSelectionPredicates; ++i) { mValues[i] = Value::MakeValueFromAttributeData (mSelectionPredicates[i].Attribute); } } else { mSelectionPredicates = NULL; } } Query::~Query () { if (mSelectionPredicates != NULL) { delete [] mSelectionPredicates; delete [] mColumnIDs; unsigned i; for (i = 0; i < mNumSelectionPredicates; ++i) { delete mValues[i]; } delete [] mValues; } } bool Query::EvaluateTuple (Tuple *t) { // do the easy case first if (mNumSelectionPredicates == 0) { return true; } bool exitValue, functionValue; if (mConjunction == CSSM_DB_AND || mNumSelectionPredicates < 2) { exitValue = false; functionValue = true; } else { exitValue = true; functionValue = false; } unsigned i = 0; while (i < mNumSelectionPredicates && exitValue != functionValue) { Value* v = t->GetValue (mColumnIDs[i]); if (v == NULL) // the cert didn't have the field we were looking for? { return false; } functionValue = v->Compare (mValues[i], mSelectionPredicates[i].DbOperator); i += 1; } return functionValue; } Relation::Relation (CSSM_DB_RECORDTYPE recordType) : mRecordType (recordType) {} Relation::~Relation () {} UniqueIdentifier::UniqueIdentifier (CSSM_DB_RECORDTYPE recordType) : mRecordType (recordType) {} UniqueIdentifier::~UniqueIdentifier () {} void CssmSelectionPredicate::CloneCssmSelectionPredicate (CssmSelectionPredicate &a, const CssmSelectionPredicate &b) { a.DbOperator = b.DbOperator; a.Attribute.NumberOfValues = b.Attribute.NumberOfValues; // clone the data a.Attribute.Value = new CSSM_DATA; a.Attribute.Value->Length = b.Attribute.Value->Length; if (b.Attribute.Value->Data != NULL) { a.Attribute.Value->Data = (uint8*) malloc (b.Attribute.Value->Length); memcpy (a.Attribute.Value->Data, b.Attribute.Value->Data, b.Attribute.Value->Length); } else { b.Attribute.Value->Data = NULL; } // clone the attribute info a.Attribute.Info.AttributeNameFormat = b.Attribute.Info.AttributeNameFormat; a.Attribute.Info.AttributeFormat = b.Attribute.Info.AttributeFormat; switch (b.Attribute.Info.AttributeNameFormat) { case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: { a.Attribute.Info.Label.AttributeName = strdup (b.Attribute.Info.Label.AttributeName); break; } case CSSM_DB_ATTRIBUTE_NAME_AS_OID: { a.Attribute.Info.Label.AttributeOID.Length = b.Attribute.Info.Label.AttributeOID.Length; a.Attribute.Info.Label.AttributeOID.Data = (uint8*) malloc (b.Attribute.Info.Label.AttributeOID.Length); memcpy (a.Attribute.Info.Label.AttributeOID.Data, b.Attribute.Info.Label.AttributeOID.Data, b.Attribute.Info.Label.AttributeOID.Length); break; } case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: { a.Attribute.Info.Label.AttributeID = b.Attribute.Info.Label.AttributeID; break; } } } CssmSelectionPredicate::CssmSelectionPredicate (const CssmSelectionPredicate& pred) { CloneCssmSelectionPredicate (*this, pred); } CssmSelectionPredicate::~CssmSelectionPredicate () { if (Attribute.Value != NULL) { free (Attribute.Value->Data); delete Attribute.Value; } switch (Attribute.Info.AttributeNameFormat) { case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: { free (Attribute.Info.Label.AttributeName); break; } case CSSM_DB_ATTRIBUTE_NAME_AS_OID: { free (Attribute.Info.Label.AttributeOID.Data); break; } } } void CssmSelectionPredicate::operator= (const CssmSelectionPredicate& pred) { CloneCssmSelectionPredicate (*this, pred); }