1 /* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 /* OSDictionary.m created by rsulack on Fri 12-Sep-1997 */ 29 /* OSDictionary.cpp converted to C++ by gvdl on Fri 1998-10-30 */ 30 /* OSDictionary.cpp rewritten by gvdl on Fri 1998-10-30 */ 31 32 33 #include <libkern/c++/OSDictionary.h> 34 #include <libkern/c++/OSArray.h> 35 #include <libkern/c++/OSSymbol.h> 36 #include <libkern/c++/OSSerialize.h> 37 #include <libkern/c++/OSLib.h> 38 #include <libkern/c++/OSCollectionIterator.h> 39 40 #define super OSCollection 41 42 OSDefineMetaClassAndStructors(OSDictionary, OSCollection) 43 OSMetaClassDefineReservedUnused(OSDictionary, 0); 44 OSMetaClassDefineReservedUnused(OSDictionary, 1); 45 OSMetaClassDefineReservedUnused(OSDictionary, 2); 46 OSMetaClassDefineReservedUnused(OSDictionary, 3); 47 OSMetaClassDefineReservedUnused(OSDictionary, 4); 48 OSMetaClassDefineReservedUnused(OSDictionary, 5); 49 OSMetaClassDefineReservedUnused(OSDictionary, 6); 50 OSMetaClassDefineReservedUnused(OSDictionary, 7); 51 52 #define EXT_CAST(obj) \ 53 reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj)) 54 55 bool OSDictionary::initWithCapacity(unsigned int inCapacity) 56 { 57 if (!super::init()) 58 return false; 59 60 if (inCapacity > (UINT_MAX / sizeof(dictEntry))) 61 return false; 62 63 unsigned int size = inCapacity * sizeof(dictEntry); 64 //fOptions |= kSort; 65 66 dictionary = (dictEntry *) kalloc_container(size); 67 if (!dictionary) 68 return false; 69 70 bzero(dictionary, size); 71 OSCONTAINER_ACCUMSIZE(size); 72 73 count = 0; 74 capacity = inCapacity; 75 capacityIncrement = (inCapacity)? inCapacity : 16; 76 77 return true; 78 } 79 80 bool OSDictionary::initWithObjects(const OSObject *objects[], 81 const OSSymbol *keys[], 82 unsigned int theCount, 83 unsigned int theCapacity) 84 { 85 unsigned int newCapacity = theCount; 86 87 if (!objects || !keys) 88 return false; 89 90 if ( theCapacity ) { 91 if (theCount > theCapacity) 92 return false; 93 94 newCapacity = theCapacity; 95 } 96 97 if (!initWithCapacity(newCapacity)) 98 return false; 99 100 for (unsigned int i = 0; i < theCount; i++) { 101 const OSMetaClassBase *newObject = *objects++; 102 103 if (!newObject || !keys[i] || !setObject(keys[i], newObject)) 104 return false; 105 } 106 107 return true; 108 } 109 110 bool OSDictionary::initWithObjects(const OSObject *objects[], 111 const OSString *keys[], 112 unsigned int theCount, 113 unsigned int theCapacity) 114 { 115 unsigned int newCapacity = theCount; 116 117 if (!objects || !keys) 118 return false; 119 120 if ( theCapacity ) { 121 if (theCount > theCapacity) 122 return false; 123 124 newCapacity = theCapacity; 125 } 126 127 if (!initWithCapacity(newCapacity)) 128 return false; 129 130 for (unsigned int i = 0; i < theCount; i++) { 131 const OSSymbol *key = OSSymbol::withString(*keys++); 132 const OSMetaClassBase *newObject = *objects++; 133 134 if (!key) 135 return false; 136 137 if (!newObject || !setObject(key, newObject)) { 138 key->release(); 139 return false; 140 } 141 142 key->release(); 143 } 144 145 return true; 146 } 147 148 bool OSDictionary::initWithDictionary(const OSDictionary *dict, 149 unsigned int theCapacity) 150 { 151 unsigned int newCapacity; 152 153 if ( !dict ) 154 return false; 155 156 newCapacity = dict->count; 157 158 if ( theCapacity ) { 159 if ( dict->count > theCapacity ) 160 return false; 161 162 newCapacity = theCapacity; 163 } 164 165 if (!initWithCapacity(newCapacity)) 166 return false; 167 168 if ((kSort & fOptions) && !(kSort & dict->fOptions)) { 169 for (unsigned int i = 0; i < dict->count; i++) { 170 if (!setObject(dict->dictionary[i].key, dict->dictionary[i].value)) { 171 return false; 172 } 173 } 174 return true; 175 } 176 177 count = dict->count; 178 bcopy(dict->dictionary, dictionary, count * sizeof(dictEntry)); 179 for (unsigned int i = 0; i < count; i++) { 180 dictionary[i].key->taggedRetain(OSTypeID(OSCollection)); 181 dictionary[i].value->taggedRetain(OSTypeID(OSCollection)); 182 } 183 184 return true; 185 } 186 187 OSDictionary *OSDictionary::withCapacity(unsigned int capacity) 188 { 189 OSDictionary *me = new OSDictionary; 190 191 if (me && !me->initWithCapacity(capacity)) { 192 me->release(); 193 return 0; 194 } 195 196 return me; 197 } 198 199 OSDictionary *OSDictionary::withObjects(const OSObject *objects[], 200 const OSSymbol *keys[], 201 unsigned int count, 202 unsigned int capacity) 203 { 204 OSDictionary *me = new OSDictionary; 205 206 if (me && !me->initWithObjects(objects, keys, count, capacity)) { 207 me->release(); 208 return 0; 209 } 210 211 return me; 212 } 213 214 OSDictionary *OSDictionary::withObjects(const OSObject *objects[], 215 const OSString *keys[], 216 unsigned int count, 217 unsigned int capacity) 218 { 219 OSDictionary *me = new OSDictionary; 220 221 if (me && !me->initWithObjects(objects, keys, count, capacity)) { 222 me->release(); 223 return 0; 224 } 225 226 return me; 227 } 228 229 OSDictionary *OSDictionary::withDictionary(const OSDictionary *dict, 230 unsigned int capacity) 231 { 232 OSDictionary *me = new OSDictionary; 233 234 if (me && !me->initWithDictionary(dict, capacity)) { 235 me->release(); 236 return 0; 237 } 238 239 return me; 240 } 241 242 void OSDictionary::free() 243 { 244 (void) super::setOptions(0, kImmutable); 245 flushCollection(); 246 if (dictionary) { 247 kfree(dictionary, capacity * sizeof(dictEntry)); 248 OSCONTAINER_ACCUMSIZE( -(capacity * sizeof(dictEntry)) ); 249 } 250 251 super::free(); 252 } 253 254 unsigned int OSDictionary::getCount() const { return count; } 255 unsigned int OSDictionary::getCapacity() const { return capacity; } 256 257 unsigned int OSDictionary::getCapacityIncrement() const 258 { 259 return capacityIncrement; 260 } 261 262 unsigned int OSDictionary::setCapacityIncrement(unsigned int increment) 263 { 264 capacityIncrement = (increment)? increment : 16; 265 266 return capacityIncrement; 267 } 268 269 unsigned int OSDictionary::ensureCapacity(unsigned int newCapacity) 270 { 271 dictEntry *newDict; 272 unsigned int finalCapacity, oldSize, newSize; 273 274 if (newCapacity <= capacity) 275 return capacity; 276 277 // round up 278 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1) 279 * capacityIncrement; 280 281 // integer overflow check 282 if (finalCapacity < newCapacity || (finalCapacity > (UINT_MAX / sizeof(dictEntry)))) 283 return capacity; 284 285 newSize = sizeof(dictEntry) * finalCapacity; 286 287 newDict = (dictEntry *) kalloc_container(newSize); 288 if (newDict) { 289 oldSize = sizeof(dictEntry) * capacity; 290 291 bcopy(dictionary, newDict, oldSize); 292 bzero(&newDict[capacity], newSize - oldSize); 293 294 OSCONTAINER_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize)); 295 kfree(dictionary, oldSize); 296 297 dictionary = newDict; 298 capacity = finalCapacity; 299 } 300 301 return capacity; 302 } 303 304 void OSDictionary::flushCollection() 305 { 306 haveUpdated(); 307 308 for (unsigned int i = 0; i < count; i++) { 309 dictionary[i].key->taggedRelease(OSTypeID(OSCollection)); 310 dictionary[i].value->taggedRelease(OSTypeID(OSCollection)); 311 } 312 count = 0; 313 } 314 315 bool OSDictionary:: 316 setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject) 317 { 318 unsigned int i; 319 bool exists; 320 321 if (!anObject || !aKey) 322 return false; 323 324 // if the key exists, replace the object 325 326 if (fOptions & kSort) { 327 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0])); 328 exists = (i < count) && (aKey == dictionary[i].key); 329 } else for (exists = false, i = 0; i < count; i++) { 330 if ((exists = (aKey == dictionary[i].key))) break; 331 } 332 333 if (exists) { 334 const OSMetaClassBase *oldObject = dictionary[i].value; 335 336 haveUpdated(); 337 338 anObject->taggedRetain(OSTypeID(OSCollection)); 339 dictionary[i].value = anObject; 340 341 oldObject->taggedRelease(OSTypeID(OSCollection)); 342 return true; 343 } 344 345 // add new key, possibly extending our capacity 346 if (count >= capacity && count >= ensureCapacity(count+1)) 347 return false; 348 349 haveUpdated(); 350 351 bcopy(&dictionary[i], &dictionary[i+1], (count - i) * sizeof(dictionary[0])); 352 353 aKey->taggedRetain(OSTypeID(OSCollection)); 354 anObject->taggedRetain(OSTypeID(OSCollection)); 355 dictionary[i].key = aKey; 356 dictionary[i].value = anObject; 357 count++; 358 359 return true; 360 } 361 362 void OSDictionary::removeObject(const OSSymbol *aKey) 363 { 364 unsigned int i; 365 bool exists; 366 367 if (!aKey) 368 return; 369 370 // if the key exists, remove the object 371 372 if (fOptions & kSort) { 373 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0])); 374 exists = (i < count) && (aKey == dictionary[i].key); 375 } else for (exists = false, i = 0; i < count; i++) { 376 if ((exists = (aKey == dictionary[i].key))) break; 377 } 378 379 if (exists) { 380 dictEntry oldEntry = dictionary[i]; 381 382 haveUpdated(); 383 384 count--; 385 bcopy(&dictionary[i+1], &dictionary[i], (count - i) * sizeof(dictionary[0])); 386 387 oldEntry.key->taggedRelease(OSTypeID(OSCollection)); 388 oldEntry.value->taggedRelease(OSTypeID(OSCollection)); 389 return; 390 } 391 } 392 393 394 // Returns true on success, false on an error condition. 395 bool OSDictionary::merge(const OSDictionary *srcDict) 396 { 397 const OSSymbol * sym; 398 OSCollectionIterator * iter; 399 400 if ( !OSDynamicCast(OSDictionary, srcDict) ) 401 return false; 402 403 iter = OSCollectionIterator::withCollection(const_cast<OSDictionary *>(srcDict)); 404 if ( !iter ) 405 return false; 406 407 while ( (sym = (const OSSymbol *)iter->getNextObject()) ) { 408 const OSMetaClassBase * obj; 409 410 obj = srcDict->getObject(sym); 411 if ( !setObject(sym, obj) ) { 412 iter->release(); 413 return false; 414 } 415 } 416 iter->release(); 417 418 return true; 419 } 420 421 OSObject *OSDictionary::getObject(const OSSymbol *aKey) const 422 { 423 unsigned int i; 424 bool exists; 425 426 if (!aKey) 427 return 0; 428 429 // if the key exists, return the object 430 431 if (fOptions & kSort) { 432 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0])); 433 exists = (i < count) && (aKey == dictionary[i].key); 434 } else for (exists = false, i = 0; i < count; i++) { 435 if ((exists = (aKey == dictionary[i].key))) break; 436 } 437 438 if (exists) { 439 return (const_cast<OSObject *> ((const OSObject *)dictionary[i].value)); 440 } 441 442 return 0; 443 } 444 445 // Wrapper macros 446 #define OBJECT_WRAP_1(cmd, k) \ 447 { \ 448 const OSSymbol *tmpKey = k; \ 449 OSObject *retObj = cmd(tmpKey); \ 450 \ 451 tmpKey->release(); \ 452 return retObj; \ 453 } 454 455 #define OBJECT_WRAP_2(cmd, k, o) \ 456 { \ 457 const OSSymbol *tmpKey = k; \ 458 bool ret = cmd(tmpKey, o); \ 459 \ 460 tmpKey->release(); \ 461 return ret; \ 462 } 463 464 #define OBJECT_WRAP_3(cmd, k) \ 465 { \ 466 const OSSymbol *tmpKey = k; \ 467 cmd(tmpKey); \ 468 tmpKey->release(); \ 469 } 470 471 472 bool OSDictionary::setObject(const OSString *aKey, const OSMetaClassBase *anObject) 473 OBJECT_WRAP_2(setObject, OSSymbol::withString(aKey), anObject) 474 bool OSDictionary::setObject(const char *aKey, const OSMetaClassBase *anObject) 475 OBJECT_WRAP_2(setObject, OSSymbol::withCString(aKey), anObject) 476 477 OSObject *OSDictionary::getObject(const OSString *aKey) const 478 OBJECT_WRAP_1(getObject, OSSymbol::withString(aKey)) 479 OSObject *OSDictionary::getObject(const char *aKey) const 480 OBJECT_WRAP_1(getObject, OSSymbol::withCString(aKey)) 481 482 void OSDictionary::removeObject(const OSString *aKey) 483 OBJECT_WRAP_3(removeObject, OSSymbol::withString(aKey)) 484 void OSDictionary::removeObject(const char *aKey) 485 OBJECT_WRAP_3(removeObject, OSSymbol::withCString(aKey)) 486 487 bool 488 OSDictionary::isEqualTo(const OSDictionary *srcDict, const OSCollection *keys) const 489 { 490 OSCollectionIterator * iter; 491 unsigned int keysCount; 492 const OSMetaClassBase * obj1; 493 const OSMetaClassBase * obj2; 494 OSString * aKey; 495 bool ret; 496 497 if ( this == srcDict ) 498 return true; 499 500 keysCount = keys->getCount(); 501 if ( (count < keysCount) || (srcDict->getCount() < keysCount) ) 502 return false; 503 504 iter = OSCollectionIterator::withCollection(keys); 505 if ( !iter ) 506 return false; 507 508 ret = true; 509 while ( (aKey = OSDynamicCast(OSString, iter->getNextObject())) ) { 510 obj1 = getObject(aKey); 511 obj2 = srcDict->getObject(aKey); 512 if ( !obj1 || !obj2 ) { 513 ret = false; 514 break; 515 } 516 517 if ( !obj1->isEqualTo(obj2) ) { 518 ret = false; 519 break; 520 } 521 } 522 iter->release(); 523 524 return ret; 525 } 526 527 bool OSDictionary::isEqualTo(const OSDictionary *srcDict) const 528 { 529 unsigned int i; 530 const OSMetaClassBase * obj; 531 532 if ( this == srcDict ) 533 return true; 534 535 if ( count != srcDict->getCount() ) 536 return false; 537 538 for ( i = 0; i < count; i++ ) { 539 obj = srcDict->getObject(dictionary[i].key); 540 if ( !obj ) 541 return false; 542 543 if ( !dictionary[i].value->isEqualTo(obj) ) 544 return false; 545 } 546 547 return true; 548 } 549 550 bool OSDictionary::isEqualTo(const OSMetaClassBase *anObject) const 551 { 552 OSDictionary *dict; 553 554 dict = OSDynamicCast(OSDictionary, anObject); 555 if ( dict ) 556 return isEqualTo(dict); 557 else 558 return false; 559 } 560 561 unsigned int OSDictionary::iteratorSize() const 562 { 563 return sizeof(unsigned int); 564 } 565 566 bool OSDictionary::initIterator(void *inIterator) const 567 { 568 unsigned int *iteratorP = (unsigned int *) inIterator; 569 570 *iteratorP = 0; 571 return true; 572 } 573 574 bool OSDictionary::getNextObjectForIterator(void *inIterator, OSObject **ret) const 575 { 576 unsigned int *iteratorP = (unsigned int *) inIterator; 577 unsigned int index = (*iteratorP)++; 578 579 if (index < count) 580 *ret = (OSObject *) dictionary[index].key; 581 else 582 *ret = 0; 583 584 return (*ret != 0); 585 } 586 587 bool OSDictionary::serialize(OSSerialize *s) const 588 { 589 if (s->previouslySerialized(this)) return true; 590 591 if (!s->addXMLStartTag(this, "dict")) return false; 592 593 for (unsigned i = 0; i < count; i++) { 594 const OSSymbol *key = dictionary[i].key; 595 596 // due the nature of the XML syntax, this must be a symbol 597 if (!key->metaCast("OSSymbol")) { 598 return false; 599 } 600 if (!s->addString("<key>")) return false; 601 const char *c = key->getCStringNoCopy(); 602 while (*c) { 603 if (*c == '<') { 604 if (!s->addString("<")) return false; 605 } else if (*c == '>') { 606 if (!s->addString(">")) return false; 607 } else if (*c == '&') { 608 if (!s->addString("&")) return false; 609 } else { 610 if (!s->addChar(*c)) return false; 611 } 612 c++; 613 } 614 if (!s->addXMLEndTag("key")) return false; 615 616 if (!dictionary[i].value->serialize(s)) return false; 617 } 618 619 return s->addXMLEndTag("dict"); 620 } 621 622 unsigned OSDictionary::setOptions(unsigned options, unsigned mask, void *) 623 { 624 unsigned old = super::setOptions(options, mask); 625 if ((old ^ options) & mask) { 626 627 // Value changed need to recurse over all of the child collections 628 for ( unsigned i = 0; i < count; i++ ) { 629 OSCollection *v = OSDynamicCast(OSCollection, dictionary[i].value); 630 if (v) 631 v->setOptions(options, mask); 632 } 633 } 634 635 return old; 636 } 637 638 OSCollection * OSDictionary::copyCollection(OSDictionary *cycleDict) 639 { 640 bool allocDict = !cycleDict; 641 OSCollection *ret = 0; 642 OSDictionary *newDict = 0; 643 644 if (allocDict) { 645 cycleDict = OSDictionary::withCapacity(16); 646 if (!cycleDict) 647 return 0; 648 } 649 650 do { 651 // Check for a cycle 652 ret = super::copyCollection(cycleDict); 653 if (ret) 654 continue; 655 656 newDict = OSDictionary::withDictionary(this); 657 if (!newDict) 658 continue; 659 660 // Insert object into cycle Dictionary 661 cycleDict->setObject((const OSSymbol *) this, newDict); 662 663 for (unsigned int i = 0; i < count; i++) { 664 const OSMetaClassBase *obj = dictionary[i].value; 665 OSCollection *coll = OSDynamicCast(OSCollection, EXT_CAST(obj)); 666 667 if (coll) { 668 OSCollection *newColl = coll->copyCollection(cycleDict); 669 if (!newColl) 670 goto abortCopy; 671 672 newDict->dictionary[i].value = newColl; 673 674 coll->taggedRelease(OSTypeID(OSCollection)); 675 newColl->taggedRetain(OSTypeID(OSCollection)); 676 newColl->release(); 677 }; 678 } 679 680 ret = newDict; 681 newDict = 0; 682 683 } while (false); 684 685 abortCopy: 686 if (newDict) 687 newDict->release(); 688 689 if (allocDict) 690 cycleDict->release(); 691 692 return ret; 693 } 694 695