1/*
2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include "Relation.h"
25#include <time.h>
26#include "CommonCode.h"
27
28Value::Value (CSSM_DB_ATTRIBUTE_FORMAT format) : mBaseFormat (format)
29{
30}
31
32
33
34Value::~Value ()
35{
36}
37
38
39
40Value* Value::MakeValueFromAttributeData (const CSSM_DB_ATTRIBUTE_DATA& info)
41{
42	switch (info.Info.AttributeFormat) {
43	case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
44		return new StringValue ((char*) info.Value->Data, info.Value->Length);
45
46	case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
47		return new SInt32Value (*(sint32*) info.Value->Data);
48
49	case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
50		return new UInt32Value (*(uint32*) info.Value->Data);
51
52	case CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM:
53		return new BigNumValue (info.Value->Data, info.Value->Length);
54
55	case CSSM_DB_ATTRIBUTE_FORMAT_REAL:
56		return new RealValue (*(double*) info.Value->Data);
57
58	case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE:
59		return new TimeDateValue ((char*) info.Value->Data);
60
61	case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
62		return new BlobValue (info.Value->Data, info.Value->Length);
63	}
64	CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_FIELD_FORMAT);
65}
66
67
68
69StringValue::StringValue (const char* value) : Value (CSSM_DB_ATTRIBUTE_FORMAT_STRING), mValue (value)
70{
71}
72
73
74
75StringValue::StringValue (const char* value, uint32 length) : Value (CSSM_DB_ATTRIBUTE_FORMAT_STRING), mValue (value, length)
76{
77}
78
79
80
81uint8* StringValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size)
82{
83	// clone the string
84	size = mValue.length ();
85	char* s = (char*) ai->malloc (size + 1);
86	strcpy (s, mValue.c_str ());
87	numberOfItems = 1;
88	return (uint8*) s;
89}
90
91
92
93bool StringValue::Compare (Value* v, CSSM_DB_OPERATOR op)
94{
95	if (v->GetValueType () != mBaseFormat)
96		CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
97
98	StringValue* sv = (StringValue*) v;
99
100	const char* vRaw = sv->GetRawValue ();
101	const char* myRaw = GetRawValue ();
102
103	switch (op) {
104	case CSSM_DB_EQUAL:
105		return strcmp (myRaw, vRaw) == 0;
106	case CSSM_DB_NOT_EQUAL:
107		return strcmp (myRaw, vRaw) != 0;
108	case CSSM_DB_LESS_THAN:
109		return strcmp (myRaw, vRaw) < 0;
110	case CSSM_DB_GREATER_THAN:
111		return strcmp (myRaw, vRaw) > 0;
112	default:
113		break;
114	}
115
116	const char* strLocation = strstr (vRaw, myRaw);
117
118	switch (op) {
119	case CSSM_DB_CONTAINS:
120		return strLocation != NULL;
121	case CSSM_DB_CONTAINS_INITIAL_SUBSTRING:
122		return strLocation == myRaw;
123	case CSSM_DB_CONTAINS_FINAL_SUBSTRING:
124		int vRawLen = strlen (vRaw);
125		int myRawLen = strlen (myRaw);
126		return strLocation == myRaw + myRawLen - vRawLen;
127	}
128
129	CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR);
130}
131
132
133
134SInt32Value::SInt32Value (const sint32 value) : Value (CSSM_DB_ATTRIBUTE_FORMAT_SINT32), mValue (value) {}
135
136
137
138bool SInt32Value::Compare (Value* v, CSSM_DB_OPERATOR op)
139{
140	if (v->GetValueType () != mBaseFormat)
141		CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
142
143	SInt32Value* sv = (SInt32Value*) v;
144
145	sint32 vRaw = sv->GetRawValue ();
146	sint32 myRaw = GetRawValue ();
147
148	switch (op) {
149	case CSSM_DB_EQUAL:
150		return vRaw == myRaw;
151	case CSSM_DB_NOT_EQUAL:
152		return vRaw != myRaw;
153	case CSSM_DB_LESS_THAN:
154		return myRaw < vRaw;
155	case CSSM_DB_GREATER_THAN:
156		return myRaw > vRaw;
157	}
158
159	CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR);
160}
161
162
163
164uint8* SInt32Value::CloneContents (AttachedInstance* ai, uint32 &numberOfItems, uint32 &size)
165{
166	sint32* result = (sint32*) ai->malloc (sizeof (sint32));
167	*result = mValue;
168	size = sizeof (sint32);
169	numberOfItems = 1;
170	return (uint8*) result;
171}
172
173
174
175UInt32Value::UInt32Value (const uint32 value) : Value (CSSM_DB_ATTRIBUTE_FORMAT_UINT32)
176{
177	mValue = value;
178}
179
180
181
182uint8* UInt32Value::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size)
183{
184	uint32* result = (uint32*) ai->malloc (sizeof (uint32));
185	*result = mValue;
186	size = sizeof (uint32);
187	numberOfItems = 1;
188	return (uint8*) result;
189}
190
191
192
193bool UInt32Value::Compare (Value* v, CSSM_DB_OPERATOR op)
194{
195	if (v->GetValueType () != mBaseFormat)
196		CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
197
198	UInt32Value* sv = (UInt32Value*) v;
199
200	uint32 vRaw = sv->GetRawValue ();
201	uint32 myRaw = GetRawValue ();
202
203	switch (op) {
204		case CSSM_DB_EQUAL:
205			return vRaw == myRaw;
206		case CSSM_DB_NOT_EQUAL:
207			return vRaw != myRaw;
208		case CSSM_DB_LESS_THAN:
209			return myRaw < vRaw;
210		case CSSM_DB_GREATER_THAN:
211			return myRaw > vRaw;
212	}
213
214	CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR);
215}
216
217
218
219BigNumValue::BigNumValue (const uint8* value, size_t size) : Value (CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM), mLengthCache (-1)
220{
221	mSize = size;
222	mValue = new uint8[size];
223	memmove (mValue, value, size);
224}
225
226
227
228BigNumValue::~BigNumValue ()
229{
230	delete mValue;
231}
232
233
234
235uint8* BigNumValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size)
236{
237	uint8* returnValue = (uint8*) ai->malloc (mSize);
238	size = mSize;
239	memmove (returnValue, mValue, size);
240	numberOfItems = 1;
241	return (uint8*) returnValue;
242}
243
244
245
246
247bool BigNumValue::GetSignBit ()
248{
249	return mValue[mSize - 1] & 0x80 != 0;
250}
251
252
253
254int BigNumValue::GetAdjustedLength ()
255{
256	if (mLengthCache != -1)
257		return mLengthCache;
258
259	// find the first non-zero byte.
260
261	// Handle the sign bit properly
262	int i = mSize - 1;
263	int value = mValue[i--] & 0x7F;
264
265	// search for the first non-zero byte
266	while (i >= 0 && value == 0)
267		value = mValue[i--];
268
269	i += 1;
270	if (i == 0) // zero length?
271		mLengthCache = 1;
272	else
273		mLengthCache = i;
274
275	return mLengthCache;
276}
277
278
279
280int BigNumValue::GetByte (int i)
281{
282	// return the bytes of the bignum, compensating for the sign bit
283	if (i == (int) (mSize - 1))
284		return mValue[i] & 0x7F;
285	return mValue[i];
286}
287
288
289
290bool BigNumValue::CompareSignBits (BigNumValue *v, int &result)
291{
292	bool compareSignBit = v->GetSignBit ();
293	bool mySignBit = GetSignBit ();
294
295	if (!compareSignBit && mySignBit) {
296		result = 1;
297		return true;
298	} else if (compareSignBit && !mySignBit) {
299		result = -1;
300		return true;
301	}
302
303	return false;
304}
305
306
307
308bool BigNumValue::CompareLengths (BigNumValue *v, int &result)
309{
310	int vSize = v->GetAdjustedLength ();
311	int mySize = GetAdjustedLength ();
312
313	if (vSize == mySize)
314		return false;
315
316	result = vSize - mySize;
317	return true;
318}
319
320
321
322bool BigNumValue::CompareValues (BigNumValue *v, int &result)
323{
324	// handle the first byte specially, since it contains the sign bit
325	int offset = GetAdjustedLength () - 1;
326
327	result = v->GetByte(offset) - GetByte (offset);
328	offset -= 1;
329
330	while (offset >= 0 && result == 0)
331		result = v->GetByte(offset) - GetByte (offset);
332		offset -= 1;
333
334	return true;
335}
336
337
338
339bool BigNumValue::Compare (Value *v, CSSM_DB_OPERATOR op)
340{
341	if (v->GetValueType () != mBaseFormat)
342		CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
343
344	BigNumValue* sv = (BigNumValue*) v;
345
346	int result;
347
348	if (!CompareSignBits (sv, result))
349		if (!CompareLengths (sv, result))
350			CompareValues (sv, result);
351
352	switch (op) {
353	case CSSM_DB_EQUAL:
354		return result == 0;
355	case CSSM_DB_NOT_EQUAL:
356		return result != 0;
357	case CSSM_DB_LESS_THAN:
358		return result < 0;
359	case CSSM_DB_GREATER_THAN:
360		return result > 0;
361	}
362
363	CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR);
364}
365
366
367
368RealValue::RealValue (double value) : Value (CSSM_DB_ATTRIBUTE_FORMAT_REAL), mValue (value) {}
369
370
371
372uint8* RealValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size)
373{
374	double* result = (double*) ai->malloc (sizeof (double));
375	*result = (double) mValue;
376	size = sizeof (double);
377	numberOfItems = 1;
378	return (uint8*) result;
379}
380
381
382
383bool RealValue::Compare (Value* v, CSSM_DB_OPERATOR op)
384{
385	if (v->GetValueType () != mBaseFormat)
386		CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
387
388	RealValue* sv = (RealValue*) v;
389
390	double vRaw = sv->GetRawValue ();
391	double myRaw = GetRawValue ();
392
393	switch (op) {
394	case CSSM_DB_EQUAL:
395		return vRaw == myRaw;
396	case CSSM_DB_NOT_EQUAL:
397		return vRaw != myRaw;
398	case CSSM_DB_LESS_THAN:
399		return myRaw < vRaw;
400	case CSSM_DB_GREATER_THAN:
401		return myRaw > vRaw;
402	}
403
404	CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR);
405}
406
407
408
409TimeDateValue::TimeDateValue (time_t tv) : Value (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE), mValue (tv) {}
410
411
412
413int CharToNum (char c)
414{
415	return c - '0';
416}
417
418
419
420TimeDateValue::TimeDateValue (const char* td) : Value (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
421{
422	struct tm tmStruct;
423	memset (&tmStruct, 0, sizeof (tmStruct));
424
425	tmStruct.tm_year = CharToNum (td[0]) * 1000 + CharToNum (td[1]) * 100 + CharToNum (td[2]) * 10 + CharToNum (td[3]) - 1900;
426	tmStruct.tm_mon = CharToNum (td[4]) * 10 + CharToNum (td[5]) - 1;
427	tmStruct.tm_mday = CharToNum (td[6]) * 10 + CharToNum (td[7]);
428	tmStruct.tm_hour = CharToNum (td[8]) * 10 + CharToNum (td[9]);
429	tmStruct.tm_min = CharToNum (td[10]) * 10 + CharToNum (td[11]);
430	tmStruct.tm_sec = CharToNum (td[12]) * 10 + CharToNum (td[13]);
431
432	mValue = timegm (&tmStruct);
433}
434
435
436
437uint8* TimeDateValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size)
438{
439	struct tm timeStruct;
440	gmtime_r (&mValue, &timeStruct);
441
442	char buffer[32];
443	sprintf (buffer, "%04d%02d%02d%0d2%0d%02dZ", timeStruct.tm_year,
444												 timeStruct.tm_mon + 1,
445												 timeStruct.tm_mday,
446												 timeStruct.tm_hour,
447												 timeStruct.tm_min,
448												 timeStruct.tm_sec);
449	size = strlen (buffer);
450	char* result = (char*) ai->malloc (size + 1);
451	strcpy (result, buffer);
452	numberOfItems = 1;
453	return (uint8*) result;
454}
455
456
457
458bool TimeDateValue::Compare (Value* v, CSSM_DB_OPERATOR op)
459{
460	if (v->GetValueType () != mBaseFormat)
461	{
462		CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
463	}
464
465	TimeDateValue* sv = (TimeDateValue*) v;
466
467	time_t vRaw = sv->GetRawValue ();
468	time_t myRaw = GetRawValue ();
469
470	switch (op) {
471	case CSSM_DB_EQUAL:
472		return vRaw == myRaw;
473	case CSSM_DB_NOT_EQUAL:
474		return vRaw != myRaw;
475	case CSSM_DB_LESS_THAN:
476		return myRaw < vRaw;
477	case CSSM_DB_GREATER_THAN:
478		return myRaw > vRaw;
479	}
480
481	CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR);
482}
483
484
485
486BlobValue::BlobValue (const uint8* value, size_t size) : Value (CSSM_DB_ATTRIBUTE_FORMAT_BLOB), mSize (size)
487{
488	mValue = new uint8[size];
489	memmove (mValue, value, size);
490}
491
492
493
494BlobValue::BlobValue (CSSM_DATA	data) : Value (CSSM_DB_ATTRIBUTE_FORMAT_BLOB), mSize (data.Length)
495{
496	mValue = new uint8[data.Length];
497	memmove (mValue, data.Data, data.Length);
498}
499
500
501BlobValue::BlobValue (CFDataRef	data) : Value (CSSM_DB_ATTRIBUTE_FORMAT_BLOB), mSize (CFDataGetLength(data))
502{
503	mSize = CFDataGetLength(data);
504	mValue = new uint8[mSize];
505	memmove (mValue, CFDataGetBytePtr(data), mSize);
506}
507
508BlobValue::BlobValue (CFStringRef	data) : Value (CSSM_DB_ATTRIBUTE_FORMAT_BLOB), mSize (CFStringGetLength(data))
509{
510	mValue = new uint8[mSize+1];
511	CFStringGetCString(data, (char *)mValue, mSize+1, kCFStringEncodingASCII);
512}
513
514
515BlobValue::~BlobValue ()
516{
517	delete mValue;
518}
519
520
521#ifdef NEVER
522template<class T> void ComputeKMPNext (const T* substring, int64_t* nextArray, size_t substringLength)
523{
524	int i, j;
525	nextArray[0] = -1;
526	for (i = 0, j = -1; i < (ssize_t) substringLength; i++, j++, nextArray[i] = j)
527	{
528		while ((j >= 0) && (substring[i] != substring[j]))
529		{
530			j = nextArray[j];
531		}
532	}
533}
534
535
536
537template<class T> int KMPSearch (const T* substring, size_t subLength, const T* mainString, size_t mainLength)
538{
539	int i, j;
540
541	// make a "next" array
542	int64_t* nextArray = new int64_t[subLength];
543	ComputeKMPNext (substring, nextArray, subLength);
544
545	for (i = 0, j = 0; j < (ssize_t) subLength && i < (ssize_t) mainLength; ++i, ++j)
546	{
547		while ((j >= 0) && (mainString[i] != substring[j]))
548		{
549			j = nextArray[j];
550		}
551	}
552
553	delete [] nextArray;
554
555	if (j == (ssize_t) subLength)
556	{
557		return i - subLength;
558	}
559
560	return i;
561}
562#endif
563
564
565static bool CompareBlobs (const uint8* a, size_t aLength, const uint8* b, size_t bLength)
566{
567	if (aLength != bLength) return false;
568	for (size_t i = 0; i < aLength; ++i)
569		if (a[i] != b[i]) return false;
570	return true;
571}
572
573
574
575uint8* BlobValue::CloneContents (AttachedInstance *ai, uint32 &numberOfItems, uint32 &size)
576{
577	// clone the data
578	size = mSize;
579	uint8* returnValue = (uint8*) ai->malloc (mSize);
580	memmove (returnValue, mValue, mSize);
581	numberOfItems = 1;
582	return (uint8*) returnValue;
583}
584
585
586
587bool BlobValue::Compare (Value* v, CSSM_DB_OPERATOR op)
588{
589	if (v->GetValueType () != mBaseFormat)
590		CSSMError::ThrowCSSMError (CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
591
592	BlobValue* sv = (BlobValue*) v;
593
594	const uint8 *vRaw, *myRaw;
595	size_t vLength, myLength;
596
597	vRaw = sv->GetRawValue (vLength);
598	myRaw = GetRawValue (myLength);
599
600	switch (op)
601	{
602		case CSSM_DB_CONTAINS:
603		case CSSM_DB_EQUAL:
604		case CSSM_DB_CONTAINS_INITIAL_SUBSTRING:
605		case CSSM_DB_CONTAINS_FINAL_SUBSTRING:
606			return CompareBlobs (vRaw, vLength, myRaw, myLength);
607
608		case CSSM_DB_NOT_EQUAL:
609			return !CompareBlobs (vRaw, vLength, myRaw, myLength);
610	}
611
612	CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_OPERATOR);
613}
614
615
616
617Tuple::Tuple () {}
618Tuple::~Tuple () {}
619
620
621
622Query::Query (Relation* relation, const CSSM_QUERY *queryBase) : mSelectionPredicates (NULL), mRelation (relation)
623{
624	mConjunction = queryBase->Conjunctive;
625
626	// fill out the rest of the fields based on queryBase
627
628	mNumSelectionPredicates = queryBase->NumSelectionPredicates;
629	if (mNumSelectionPredicates >= 2 && mConjunction == CSSM_DB_NONE)
630		CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_QUERY);
631
632	if (mNumSelectionPredicates >= 1) {
633		mSelectionPredicates = new CssmSelectionPredicate[mNumSelectionPredicates];
634
635		// copy the selection predicates
636		unsigned i;
637		for (i = 0; i < mNumSelectionPredicates; ++i)
638			mSelectionPredicates[i] = *(CssmSelectionPredicate*) (queryBase->SelectionPredicate + i);
639
640		// lookup the number of selection
641		mColumnIDs = new int [mNumSelectionPredicates];
642		for (i = 0; i < mNumSelectionPredicates; ++i) {
643			uint32 columnID;
644
645			switch (mSelectionPredicates[i].GetAttributeNameFormat ()) {
646			case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
647				// if we have an attribute name format of CSSM_
648				columnID = relation->GetColumnNumber (mSelectionPredicates[i].GetAttributeName ());
649				break;
650			case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
651				columnID = mSelectionPredicates[i].GetAttributeID ();
652				break;
653			case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
654			default:
655				CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_QUERY);
656				break;
657			}
658
659			mColumnIDs[i] = columnID;
660		}
661
662		mValues = new Value*[mNumSelectionPredicates];
663		for (i = 0; i < mNumSelectionPredicates; ++i)
664			mValues[i] = Value::MakeValueFromAttributeData (mSelectionPredicates[i].Attribute);
665	} else {
666		mSelectionPredicates = NULL;
667	}
668}
669
670
671
672Query::~Query ()
673{
674	if (mSelectionPredicates != NULL) {
675		delete [] mSelectionPredicates;
676		delete [] mColumnIDs;
677
678		unsigned i;
679		for (i = 0; i < mNumSelectionPredicates; ++i)
680			delete mValues[i];
681
682		delete [] mValues;
683	}
684}
685
686
687
688bool Query::EvaluateTuple (Tuple *t)
689{
690	// do the easy case first
691	if(!t) return false;
692	if (mNumSelectionPredicates <= 0) return true;
693
694	for(uint i=0; i < mNumSelectionPredicates; i++) {
695		Value* v = t->GetValue (mColumnIDs[i]);
696		if (v != NULL && v->Compare (mValues[i], mSelectionPredicates[i].DbOperator)){
697			if(mConjunction != CSSM_DB_AND) return true;
698		} else if(mConjunction == CSSM_DB_AND) return false;
699	}
700
701	return true;
702}
703
704
705
706Relation::Relation (CSSM_DB_RECORDTYPE recordType) : mRecordType (recordType) {}
707Relation::~Relation () {}
708
709
710
711UniqueIdentifier::UniqueIdentifier (CSSM_DB_RECORDTYPE recordType) : mRecordType (recordType) {}
712UniqueIdentifier::~UniqueIdentifier () {}
713
714
715
716void CssmSelectionPredicate::CloneCssmSelectionPredicate (CssmSelectionPredicate &a, const CssmSelectionPredicate &b)
717{
718	a.DbOperator = b.DbOperator;
719	a.Attribute.NumberOfValues = b.Attribute.NumberOfValues;
720
721	// clone the data
722	a.Attribute.Value = new CSSM_DATA;
723	a.Attribute.Value->Length = b.Attribute.Value->Length;
724	if (b.Attribute.Value->Data != NULL) {
725		a.Attribute.Value->Data = (uint8*) malloc (b.Attribute.Value->Length);
726		memcpy (a.Attribute.Value->Data, b.Attribute.Value->Data, b.Attribute.Value->Length);
727	} else {
728		b.Attribute.Value->Data = NULL;
729	}
730
731	// clone the attribute info
732	a.Attribute.Info.AttributeNameFormat = b.Attribute.Info.AttributeNameFormat;
733	a.Attribute.Info.AttributeFormat = b.Attribute.Info.AttributeFormat;
734
735	switch (b.Attribute.Info.AttributeNameFormat) {
736	case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
737		a.Attribute.Info.Label.AttributeName = strdup (b.Attribute.Info.Label.AttributeName);
738		break;
739
740	case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
741		a.Attribute.Info.Label.AttributeOID.Length = b.Attribute.Info.Label.AttributeOID.Length;
742		a.Attribute.Info.Label.AttributeOID.Data = (uint8*) malloc (b.Attribute.Info.Label.AttributeOID.Length);
743		memcpy (a.Attribute.Info.Label.AttributeOID.Data, b.Attribute.Info.Label.AttributeOID.Data, b.Attribute.Info.Label.AttributeOID.Length);
744		break;
745
746	case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
747		a.Attribute.Info.Label.AttributeID = b.Attribute.Info.Label.AttributeID;
748		break;
749	}
750}
751
752
753
754CssmSelectionPredicate::CssmSelectionPredicate (const CssmSelectionPredicate& pred)
755{
756	CloneCssmSelectionPredicate (*this, pred);
757}
758
759
760
761CssmSelectionPredicate::~CssmSelectionPredicate ()
762{
763	if (Attribute.Value != NULL) {
764		free (Attribute.Value->Data);
765		delete Attribute.Value;
766	}
767
768	switch (Attribute.Info.AttributeNameFormat) {
769	case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
770		free (Attribute.Info.Label.AttributeName);
771		break;
772	case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
773		free (Attribute.Info.Label.AttributeOID.Data);
774		break;
775	}
776}
777
778
779
780void CssmSelectionPredicate::operator= (const CssmSelectionPredicate& pred)
781{
782	CloneCssmSelectionPredicate (*this, pred);
783}
784
785