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