]> git.saurik.com Git - apple/security.git/blob - libsecurity_filedb/lib/DbValue.cpp
Security-55471.tar.gz
[apple/security.git] / libsecurity_filedb / lib / DbValue.cpp
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
30 DbValue::~DbValue()
31 {
32 }
33
34 //
35 // UInt32Value
36 //
37
38 UInt32Value::UInt32Value(const ReadSection &rs, uint32 &offset)
39 : BasicValue<uint32>(rs.at(offset))
40 {
41 offset += size();
42 }
43
44 UInt32Value::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
62 UInt32Value::~UInt32Value()
63 {
64 }
65
66 void
67 UInt32Value::pack(WriteSection &ws, uint32 &offset) const
68 {
69 offset = ws.put(offset, mValue);
70 }
71
72 //
73 // SInt32Value
74 //
75
76 SInt32Value::SInt32Value(const ReadSection &rs, uint32 &offset)
77 : BasicValue<sint32>(static_cast<sint32>(rs.at(offset)))
78 {
79 offset += size();
80 }
81
82 SInt32Value::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
100 SInt32Value::~SInt32Value()
101 {
102 }
103
104 void
105 SInt32Value::pack(WriteSection &ws, uint32 &offset) const
106 {
107 offset = ws.put(offset, static_cast<uint32>(mValue));
108 }
109
110 //
111 // DoubleValue
112 //
113
114 DoubleValue::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
121 DoubleValue::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
136 DoubleValue::~DoubleValue()
137 {
138 }
139
140 void
141 DoubleValue::pack(WriteSection &ws, uint32 &offset) const
142 {
143 offset = ws.put(offset, (uint32)size(), bytes());
144 }
145
146 //
147 // BlobValue
148 //
149
150 BlobValue::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
157 BlobValue::BlobValue(const CSSM_DATA &data)
158 : CssmData(CssmData::overlay(data))
159 {
160 }
161
162 BlobValue::~BlobValue()
163 {
164 }
165
166 void
167 BlobValue::pack(WriteSection &ws, uint32 &offset) const
168 {
169 offset = ws.put(offset, (uint32)Length);
170 offset = ws.put(offset, (uint32)Length, Data);
171 }
172
173 BlobValue::Comparator::~Comparator()
174 {
175 }
176
177 int
178 BlobValue::Comparator::operator () (const uint8 *ptr1, const uint8 *ptr2, uint32 length)
179 {
180 return memcmp(ptr1, ptr2, length);
181 }
182
183 bool
184 BlobValue::evaluate(const BlobValue &other, CSSM_DB_OPERATOR op) const
185 {
186 return evaluate(*this, other, op, Comparator());
187 }
188
189 bool
190 BlobValue::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
262 TimeDateValue::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
269 TimeDateValue::TimeDateValue(const CSSM_DATA &data)
270 : BlobValue(data)
271 {
272 if (Length != kTimeDateSize || !isValidDate())
273 CssmError::throwMe(CSSMERR_DL_INVALID_VALUE);
274 }
275
276 TimeDateValue::~TimeDateValue()
277 {
278 }
279
280 void
281 TimeDateValue::pack(WriteSection &ws, uint32 &offset) const
282 {
283 offset = ws.put(offset, (uint32)Length, Data);
284 }
285
286 bool
287 TimeDateValue::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
320 uint32
321 TimeDateValue::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
333 StringValue::StringValue(const ReadSection &rs, uint32 &offset)
334 : BlobValue(rs, offset)
335 {
336 }
337
338 StringValue::StringValue(const CSSM_DATA &data)
339 : BlobValue(data)
340 {
341 }
342
343 StringValue::~StringValue()
344 {
345 }
346
347 int
348 StringValue::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
354 bool
355 StringValue::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
364 BigNumValue::BigNumValue(const ReadSection &rs, uint32 &offset)
365 : BlobValue(rs, offset)
366 {
367 }
368
369 BigNumValue::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
381 BigNumValue::~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
389 int
390 BigNumValue::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
403 bool
404 BigNumValue::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
453 MultiUInt32Value::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
468 MultiUInt32Value::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
478 MultiUInt32Value::~MultiUInt32Value()
479 {
480 if (mOwnsValues)
481 delete [] mValues;
482 }
483
484 void
485 MultiUInt32Value::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
492 static inline int
493 uint32cmp(const uint32 *a, const uint32 *b, uint32 length)
494 {
495 return memcmp(a, b, length * sizeof(uint32));
496 }
497
498 bool
499 MultiUInt32Value::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