1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19//
20// DbValue.cpp
21//
22
23#include "DbValue.h"
24#include <ctype.h>
25
26//
27// DbValue
28//
29
30DbValue::~DbValue()
31{
32}
33
34//
35// UInt32Value
36//
37
38UInt32Value::UInt32Value(const ReadSection &rs, uint32 &offset)
39:	BasicValue<uint32>(rs.at(offset))
40{
41	offset += size();
42}
43
44UInt32Value::UInt32Value(const CSSM_DATA &data)
45{
46	switch (data.Length)
47	{
48		case 1:
49			mValue = *reinterpret_cast<uint8 *>(data.Data);
50			break;
51		case 2:
52			mValue = *reinterpret_cast<uint16 *>(data.Data);
53			break;
54		case 4:
55			mValue = *reinterpret_cast<uint32 *>(data.Data);
56			break;
57		default:
58			CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
59	}
60}
61
62UInt32Value::~UInt32Value()
63{
64}
65
66void
67UInt32Value::pack(WriteSection &ws, uint32 &offset) const
68{
69	offset = ws.put(offset, mValue);
70}
71
72//
73// SInt32Value
74//
75
76SInt32Value::SInt32Value(const ReadSection &rs, uint32 &offset)
77:	BasicValue<sint32>(static_cast<sint32>(rs.at(offset)))
78{
79	offset += size();
80}
81
82SInt32Value::SInt32Value(const CSSM_DATA &data)
83{
84	switch (data.Length)
85	{
86		case 1:
87			mValue = *reinterpret_cast<sint8 *>(data.Data);
88			break;
89		case 2:
90			mValue = *reinterpret_cast<sint16 *>(data.Data);
91			break;
92		case 4:
93			mValue = *reinterpret_cast<sint32 *>(data.Data);
94			break;
95		default:
96			CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
97	}
98}
99
100SInt32Value::~SInt32Value()
101{
102}
103
104void
105SInt32Value::pack(WriteSection &ws, uint32 &offset) const
106{
107	offset = ws.put(offset, static_cast<uint32>(mValue));
108}
109
110//
111// DoubleValue
112//
113
114DoubleValue::DoubleValue(const ReadSection &rs, uint32 &offset)
115{
116	Range r(offset, (uint32)size());
117	mValue = *reinterpret_cast<const double *>(rs.range(r));
118	offset += size();
119}
120
121DoubleValue::DoubleValue(const CSSM_DATA &data)
122{
123	switch (data.Length)
124	{
125		case 4:
126			mValue = *reinterpret_cast<float *>(data.Data);
127			break;
128		case 8:
129			mValue = *reinterpret_cast<double *>(data.Data);
130			break;
131		default:
132			CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
133	}
134}
135
136DoubleValue::~DoubleValue()
137{
138}
139
140void
141DoubleValue::pack(WriteSection &ws, uint32 &offset) const
142{
143	offset = ws.put(offset, (uint32)size(), bytes());
144}
145
146//
147// BlobValue
148//
149
150BlobValue::BlobValue(const ReadSection &rs, uint32 &offset)
151{
152	Length = rs.at(offset);
153	Data = const_cast<uint8 *>(rs.range(Range(offset + AtomSize, (uint32)Length)));
154	offset = ReadSection::align((uint32)(offset + Length + AtomSize));
155}
156
157BlobValue::BlobValue(const CSSM_DATA &data)
158:	CssmData(CssmData::overlay(data))
159{
160}
161
162BlobValue::~BlobValue()
163{
164}
165
166void
167BlobValue::pack(WriteSection &ws, uint32 &offset) const
168{
169	offset = ws.put(offset, (uint32)Length);
170	offset = ws.put(offset, (uint32)Length, Data);
171}
172
173BlobValue::Comparator::~Comparator()
174{
175}
176
177int
178BlobValue::Comparator::operator () (const uint8 *ptr1, const uint8 *ptr2, uint32 length)
179{
180	return memcmp(ptr1, ptr2, length);
181}
182
183bool
184BlobValue::evaluate(const BlobValue &other, CSSM_DB_OPERATOR op) const
185{
186	return evaluate(*this, other, op, Comparator());
187}
188
189bool
190BlobValue::evaluate(const CssmData &inData1, const CssmData &inData2, CSSM_DB_OPERATOR op,
191	Comparator compare)
192{
193	uint32 length1 = (uint32)inData1.Length, length2 = (uint32)inData2.Length;
194	const uint8 *data1 = inData1.Data;
195	const uint8 *data2 = inData2.Data;
196
197	switch (op) {
198
199	case CSSM_DB_CONTAINS_INITIAL_SUBSTRING:
200		if (length1 > length2)
201            return false;
202        length2 = length1;
203        goto DB_EQUAL;
204
205	case CSSM_DB_CONTAINS_FINAL_SUBSTRING:
206        if (length1 > length2)
207            return false;
208		data2 += (length2 - length1);
209		length2 = length1;
210        // dropthrough...
211
212    case CSSM_DB_EQUAL:
213	DB_EQUAL:
214        if (length1 != length2)
215            return false;
216        if (length1 == 0)
217            return true;
218		return compare(data1, data2, length1) == 0;
219
220    case CSSM_DB_NOT_EQUAL:
221		if (length1 != length2)
222			return true;
223		if (length1 == 0)
224			return false;
225        return compare(data1, data2, length1) != 0;
226
227    case CSSM_DB_LESS_THAN:
228    case CSSM_DB_GREATER_THAN:
229    {
230        uint32 length = min(length1, length2);
231		int result = (length == 0) ? 0 : compare(data1, data2, length);
232
233		if (result < 0 || (result == 0 && length1 < length2))
234			return op == CSSM_DB_LESS_THAN;
235		else if (result > 0 || (result == 0 && length1 > length2))
236			return op == CSSM_DB_GREATER_THAN;
237		break;
238	}
239
240    case CSSM_DB_CONTAINS:
241        if (length1 > length2)
242            return false;
243        if (length1 == 0)
244            return true;
245        // Both buffers are at least 1 byte long.
246        for (const uint8 *data = data2; data + length1 <= data2 + length2; data++)
247			if (compare(data1, data, length1) == 0)
248				return true;
249		break;
250
251    default:
252        CssmError::throwMe(CSSMERR_DL_UNSUPPORTED_QUERY);
253    }
254
255    return false;
256}
257
258//
259// TimeDateValue
260//
261
262TimeDateValue::TimeDateValue(const ReadSection &rs, uint32 &offset)
263{
264	Length = kTimeDateSize;
265	Data = const_cast<uint8 *>(rs.range(Range(offset, (uint32)Length)));
266	offset = ReadSection::align(offset + (uint32)Length);
267}
268
269TimeDateValue::TimeDateValue(const CSSM_DATA &data)
270:	BlobValue(data)
271{
272	if (Length != kTimeDateSize || !isValidDate())
273		CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
274}
275
276TimeDateValue::~TimeDateValue()
277{
278}
279
280void
281TimeDateValue::pack(WriteSection &ws, uint32 &offset) const
282{
283	offset = ws.put(offset, (uint32)Length, Data);
284}
285
286bool
287TimeDateValue::isValidDate() const
288{
289	if (Length != kTimeDateSize || Data[kTimeDateSize - 1] != 0 ||
290		Data[kTimeDateSize - 2] != 'Z')
291		return false;
292
293	for (uint32 i = 0; i < kTimeDateSize - 2; i++)
294		if (!isdigit(Data[i]))
295			return false;
296
297	uint32 month = rangeValue(4, 2);
298	if (month < 1 || month > 12)
299		return false;
300
301	uint32 day = rangeValue(6, 2);
302	if (day < 1 || day > 31)
303		return false;
304
305	uint32 hour = rangeValue(8, 2);
306	if (hour > 23)
307		return false;
308
309	uint32 minute = rangeValue(10, 2);
310	if (minute > 59)
311		return false;
312
313	uint32 second = rangeValue(12, 2);
314	if (second > 59)
315		return false;
316
317	return true;
318}
319
320uint32
321TimeDateValue::rangeValue(uint32 start, uint32 length) const
322{
323	uint32 value = 0;
324	for (uint32 i = 0; i < length; i++)
325		value = value * 10 + Data[start + i] - '0';
326	return value;
327}
328
329//
330// StringValue
331//
332
333StringValue::StringValue(const ReadSection &rs, uint32 &offset)
334:	BlobValue(rs, offset)
335{
336}
337
338StringValue::StringValue(const CSSM_DATA &data)
339:	BlobValue(data)
340{
341}
342
343StringValue::~StringValue()
344{
345}
346
347int
348StringValue::Comparator::operator () (const uint8 *ptr1, const uint8 *ptr2, uint32 length)
349{
350	return strncmp(reinterpret_cast<const char *>(ptr1),
351		reinterpret_cast<const char *>(ptr2), length);
352}
353
354bool
355StringValue::evaluate(const StringValue &other, CSSM_DB_OPERATOR op) const
356{
357	return BlobValue::evaluate(*this, other, op, StringValue::Comparator());
358}
359
360//
361// BigNumValue
362//
363
364BigNumValue::BigNumValue(const ReadSection &rs, uint32 &offset)
365:	BlobValue(rs, offset)
366{
367}
368
369BigNumValue::BigNumValue(const CSSM_DATA &data)
370:	BlobValue(data)
371{
372	// remove trailing zero bytes
373	while (Length > 1 && Data[Length - 1] == 0)
374		Length--;
375
376	// if the number is zero (positive or negative), make the length zero
377	if (Length == 1 && (Data[0] & ~kSignBit) == 0)
378		Length = 0;
379}
380
381BigNumValue::~BigNumValue()
382{
383}
384
385// Walk the contents of two equal-sized bignums, moving backward
386// from the high-order bytes, and return the comparison result
387// ala memcmp.
388
389int
390BigNumValue::compare(const uint8 *a, const uint8 *b, int length)
391{
392	for (int diff, i = length - 1; i >= 1; i--)
393		if ((diff = a[i] - b[i]))
394			return diff;
395
396	// for the last (i.e. first) byte, mask out the sign bit
397	return (a[0] & ~kSignBit) - (b[0] & ~kSignBit);
398}
399
400// Compare two bignums, assuming they are in canonical form (i.e.,
401// no bytes containing trailing zeros.
402
403bool
404BigNumValue::evaluate(const BigNumValue &other, CSSM_DB_OPERATOR op) const
405{
406	uint32 length1 = (uint32)Length, length2 = (uint32)other.Length;
407	uint8 sign1 = length1 ? (Data[0] & kSignBit) : 0;
408	uint8 sign2 = length2 ? (other.Data[0] & kSignBit) : 0;
409
410	switch (op)
411	{
412	case CSSM_DB_EQUAL:
413	case CSSM_DB_NOT_EQUAL:
414		return BlobValue::evaluate(other, op);
415
416	case CSSM_DB_LESS_THAN:
417		if (sign1 ^ sign2)
418			// different signs: return true iff left value is the negative one
419			return sign1;
420		else if (length1 != length2)
421			// in canonical form, shorter numbers have smaller absolute value
422			return sign1 ? (length1 > length2) : (length1 < length2);
423		else {
424			// same length, same sign...
425			int c = compare(Data, other.Data, length1);
426			return sign1 ? (c > 0) : (c < 0);
427		}
428		break;
429
430	case CSSM_DB_GREATER_THAN:
431		if (sign1 ^ sign2)
432			return sign2;
433		else if (length1 != length2)
434			return sign1 ? (length1 < length2) : (length1 > length2);
435		else {
436			int c = compare(Data, other.Data, length1);
437			return sign1 ? (c < 0) : (c > 0);
438		}
439		break;
440
441	case CSSM_DB_CONTAINS:
442	case CSSM_DB_CONTAINS_INITIAL_SUBSTRING:
443	case CSSM_DB_CONTAINS_FINAL_SUBSTRING:
444	default:
445		CssmError::throwMe(CSSMERR_DL_UNSUPPORTED_QUERY);
446	}
447}
448
449//
450// MultiUInt32Value
451//
452
453MultiUInt32Value::MultiUInt32Value(const ReadSection &rs, uint32 &offset)
454{
455	// this is relatively expensive, since it copies the data from the
456	// read section to get the endianness correct
457
458	mNumValues = rs.at(offset);
459	mValues = new uint32[mNumValues];
460
461	for (uint32 i = 0; i < mNumValues; i++)
462		mValues[i] = rs.at(offset + (i + 1) * AtomSize);
463
464	offset = ReadSection::align(offset + (mNumValues + 1) * AtomSize);
465	mOwnsValues = true;
466}
467
468MultiUInt32Value::MultiUInt32Value(const CSSM_DATA &data)
469{
470	if (data.Length & (sizeof(uint32) - 1))
471		CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
472
473	mNumValues = (uint32)(data.Length / sizeof(uint32));
474	mValues = reinterpret_cast<uint32 *>(data.Data);
475	mOwnsValues = false;
476}
477
478MultiUInt32Value::~MultiUInt32Value()
479{
480	if (mOwnsValues)
481		delete [] mValues;
482}
483
484void
485MultiUInt32Value::pack(WriteSection &ws, uint32 &offset) const
486{
487	offset = ws.put(offset, mNumValues);
488	for (uint32 i = 0; i < mNumValues; i++)
489		offset = ws.put(offset, mValues[i]);
490}
491
492static inline int
493uint32cmp(const uint32 *a, const uint32 *b, uint32 length)
494{
495	return memcmp(a, b, length * sizeof(uint32));
496}
497
498bool
499MultiUInt32Value::evaluate(const MultiUInt32Value &other, CSSM_DB_OPERATOR op) const
500{
501	uint32 length1 = mNumValues, length2 = other.mNumValues;
502	const uint32 *values1 = mValues;
503	const uint32 *values2 = other.mValues;
504
505	switch (op)
506	{
507	case CSSM_DB_EQUAL:
508		if (length1 == length2)
509			return uint32cmp(values1, values2, length1) == 0;
510		break;
511
512	case CSSM_DB_NOT_EQUAL:
513		if (length1 != length2 || uint32cmp(values1, values2, length1))
514			return true;
515		break;
516
517	case CSSM_DB_CONTAINS_INITIAL_SUBSTRING:
518		if (length1 <= length2)
519			return uint32cmp(values1, values2, length1) == 0;
520		break;
521
522	case CSSM_DB_CONTAINS_FINAL_SUBSTRING:
523		if (length1 <= length2)
524			return uint32cmp(values1, values2 + (length2 - length1), length1) == 0;
525		break;
526
527	case CSSM_DB_CONTAINS:
528		if (length1 <= length2) {
529
530			if (length1 == 0)
531				return true;
532
533			for (const uint32 *values = values2; values + length1 < values2 + length2; values++)
534				if (uint32cmp(values1, values, length1) == 0)
535					return true;
536		}
537		break;
538
539	case CSSM_DB_LESS_THAN:
540		// this is not required by the spec, but is required to sort indexes over
541		// multi uint32 keys...
542		if (length1 < length2)
543			return true;
544		else if (length1 == length2)
545			return uint32cmp(values1, values2, length1) < 0;
546		break;
547
548	default:
549		CssmError::throwMe(CSSMERR_DL_UNSUPPORTED_QUERY);
550	}
551
552	return false;
553}
554
555
556