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