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 #define IOKIT_ENABLE_SHARED_PTR
33
34 #include <libkern/c++/OSArray.h>
35 #include <libkern/c++/OSCollectionIterator.h>
36 #include <libkern/c++/OSDictionary.h>
37 #include <libkern/c++/OSLib.h>
38 #include <libkern/c++/OSSerialize.h>
39 #include <libkern/c++/OSSharedPtr.h>
40 #include <libkern/c++/OSSymbol.h>
41 #include <os/cpp_util.h>
42
43 #define super OSCollection
44
45 OSDefineMetaClassAndStructorsWithZone(OSDictionary, OSCollection,
46 (zone_create_flags_t) (ZC_CACHING | ZC_ZFREE_CLEARMEM))
47 OSMetaClassDefineReservedUnused(OSDictionary, 0);
48 OSMetaClassDefineReservedUnused(OSDictionary, 1);
49 OSMetaClassDefineReservedUnused(OSDictionary, 2);
50 OSMetaClassDefineReservedUnused(OSDictionary, 3);
51 OSMetaClassDefineReservedUnused(OSDictionary, 4);
52 OSMetaClassDefineReservedUnused(OSDictionary, 5);
53 OSMetaClassDefineReservedUnused(OSDictionary, 6);
54 OSMetaClassDefineReservedUnused(OSDictionary, 7);
55
56 #define EXT_CAST(obj) \
57 reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj))
58
59 extern "C" {
60 void qsort(void *, size_t, size_t, int (*)(const void *, const void *));
61 }
62
63 int
compare(const void * _e1,const void * _e2)64 OSDictionary::dictEntry::compare(const void *_e1, const void *_e2)
65 {
66 const OSDictionary::dictEntry *e1 = (const OSDictionary::dictEntry *)_e1;
67 const OSDictionary::dictEntry *e2 = (const OSDictionary::dictEntry *)_e2;
68
69 if ((uintptr_t)e1->key.get() == (uintptr_t)e2->key.get()) {
70 return 0;
71 }
72
73 return (uintptr_t)e1->key.get() > (uintptr_t)e2->key.get() ? 1 : -1;
74 }
75
76 void
sortBySymbol(void)77 OSDictionary::sortBySymbol(void)
78 {
79 qsort(dictionary, count, sizeof(OSDictionary::dictEntry),
80 &OSDictionary::dictEntry::compare);
81 }
82
83 bool
initWithCapacity(unsigned int inCapacity)84 OSDictionary::initWithCapacity(unsigned int inCapacity)
85 {
86 if (!super::init()) {
87 return false;
88 }
89
90 if (inCapacity > (UINT_MAX / sizeof(dictEntry))) {
91 return false;
92 }
93
94 //fOptions |= kSort;
95
96 dictionary = kalloc_type_tag_bt(dictEntry, inCapacity, Z_WAITOK_ZERO,
97 VM_KERN_MEMORY_LIBKERN);
98 if (!dictionary) {
99 return false;
100 }
101
102 os::uninitialized_value_construct(dictionary, dictionary + inCapacity);
103 OSCONTAINER_ACCUMSIZE(inCapacity * sizeof(dictEntry));
104
105 count = 0;
106 capacity = inCapacity;
107 capacityIncrement = (inCapacity)? inCapacity : 16;
108
109 return true;
110 }
111
112 bool
initWithObjects(const OSObject * objects[],const OSSymbol * keys[],unsigned int theCount,unsigned int theCapacity)113 OSDictionary::initWithObjects(const OSObject *objects[],
114 const OSSymbol *keys[],
115 unsigned int theCount,
116 unsigned int theCapacity)
117 {
118 unsigned int newCapacity = theCount;
119
120 if (!objects || !keys) {
121 return false;
122 }
123
124 if (theCapacity) {
125 if (theCount > theCapacity) {
126 return false;
127 }
128
129 newCapacity = theCapacity;
130 }
131
132 if (!initWithCapacity(newCapacity)) {
133 return false;
134 }
135
136 for (unsigned int i = 0; i < theCount; i++) {
137 const OSMetaClassBase *newObject = *objects++;
138
139 if (!newObject || !keys[i] || !setObject(keys[i], newObject)) {
140 return false;
141 }
142 }
143
144 return true;
145 }
146
147 bool
initWithObjects(const OSObject * objects[],const OSString * keys[],unsigned int theCount,unsigned int theCapacity)148 OSDictionary::initWithObjects(const OSObject *objects[],
149 const OSString *keys[],
150 unsigned int theCount,
151 unsigned int theCapacity)
152 {
153 unsigned int newCapacity = theCount;
154
155 if (!objects || !keys) {
156 return false;
157 }
158
159 if (theCapacity) {
160 if (theCount > theCapacity) {
161 return false;
162 }
163
164 newCapacity = theCapacity;
165 }
166
167 if (!initWithCapacity(newCapacity)) {
168 return false;
169 }
170
171 for (unsigned int i = 0; i < theCount; i++) {
172 OSSharedPtr<const OSSymbol> key = OSSymbol::withString(*keys++);
173 const OSMetaClassBase *newObject = *objects++;
174
175 if (!key) {
176 return false;
177 }
178
179 if (!newObject || !setObject(key.get(), newObject)) {
180 return false;
181 }
182 }
183
184 return true;
185 }
186
187 bool
initWithDictionary(const OSDictionary * dict,unsigned int theCapacity)188 OSDictionary::initWithDictionary(const OSDictionary *dict,
189 unsigned int theCapacity)
190 {
191 unsigned int newCapacity;
192
193 if (!dict) {
194 return false;
195 }
196
197 newCapacity = dict->count;
198
199 if (theCapacity) {
200 if (dict->count > theCapacity) {
201 return false;
202 }
203
204 newCapacity = theCapacity;
205 }
206
207 if (!initWithCapacity(newCapacity)) {
208 return false;
209 }
210
211 count = dict->count;
212 for (unsigned int i = 0; i < count; i++) {
213 dictionary[i].key = dict->dictionary[i].key;
214 dictionary[i].value = dict->dictionary[i].value;
215 }
216
217 if ((kSort & fOptions) && !(kSort & dict->fOptions)) {
218 sortBySymbol();
219 }
220
221 return true;
222 }
223
224 OSSharedPtr<OSDictionary>
withCapacity(unsigned int capacity)225 OSDictionary::withCapacity(unsigned int capacity)
226 {
227 OSSharedPtr<OSDictionary> me = OSMakeShared<OSDictionary>();
228
229 if (me && !me->initWithCapacity(capacity)) {
230 return nullptr;
231 }
232
233 return me;
234 }
235
236 OSSharedPtr<OSDictionary>
withObjects(const OSObject * objects[],const OSSymbol * keys[],unsigned int count,unsigned int capacity)237 OSDictionary::withObjects(const OSObject *objects[],
238 const OSSymbol *keys[],
239 unsigned int count,
240 unsigned int capacity)
241 {
242 OSSharedPtr<OSDictionary> me = OSMakeShared<OSDictionary>();
243
244 if (me && !me->initWithObjects(objects, keys, count, capacity)) {
245 return nullptr;
246 }
247
248 return me;
249 }
250
251 OSSharedPtr<OSDictionary>
withObjects(const OSObject * objects[],const OSString * keys[],unsigned int count,unsigned int capacity)252 OSDictionary::withObjects(const OSObject *objects[],
253 const OSString *keys[],
254 unsigned int count,
255 unsigned int capacity)
256 {
257 OSSharedPtr<OSDictionary> me = OSMakeShared<OSDictionary>();
258
259 if (me && !me->initWithObjects(objects, keys, count, capacity)) {
260 return nullptr;
261 }
262
263 return me;
264 }
265
266 OSSharedPtr<OSDictionary>
withDictionary(const OSDictionary * dict,unsigned int capacity)267 OSDictionary::withDictionary(const OSDictionary *dict,
268 unsigned int capacity)
269 {
270 OSSharedPtr<OSDictionary> me = OSMakeShared<OSDictionary>();
271
272 if (me && !me->initWithDictionary(dict, capacity)) {
273 return nullptr;
274 }
275
276 return me;
277 }
278
279 void
free()280 OSDictionary::free()
281 {
282 (void) super::setOptions(0, kImmutable);
283 flushCollection();
284 if (dictionary) {
285 kfree_type(dictEntry, capacity, dictionary);
286 OSCONTAINER_ACCUMSIZE( -(capacity * sizeof(dictEntry)));
287 }
288
289 super::free();
290 }
291
292 unsigned int
getCount() const293 OSDictionary::getCount() const
294 {
295 return count;
296 }
297 unsigned int
getCapacity() const298 OSDictionary::getCapacity() const
299 {
300 return capacity;
301 }
302
303 unsigned int
getCapacityIncrement() const304 OSDictionary::getCapacityIncrement() const
305 {
306 return capacityIncrement;
307 }
308
309 unsigned int
setCapacityIncrement(unsigned int increment)310 OSDictionary::setCapacityIncrement(unsigned int increment)
311 {
312 capacityIncrement = (increment)? increment : 16;
313
314 return capacityIncrement;
315 }
316
317 unsigned int
ensureCapacity(unsigned int newCapacity)318 OSDictionary::ensureCapacity(unsigned int newCapacity)
319 {
320 dictEntry *newDict;
321 vm_size_t finalCapacity;
322
323 if (newCapacity <= capacity) {
324 return capacity;
325 }
326
327 // round up
328 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1)
329 * capacityIncrement;
330
331 // integer overflow check
332 if (finalCapacity < newCapacity) {
333 return capacity;
334 }
335
336 newDict = kallocp_type_tag_bt(dictEntry, &finalCapacity, Z_WAITOK,
337 VM_KERN_MEMORY_LIBKERN);
338 if (newDict) {
339 // use all of the actual allocation size
340 if (finalCapacity > UINT_MAX) {
341 // failure, too large
342 kfree_type(dictEntry, finalCapacity, newDict);
343 return capacity;
344 }
345
346 os::uninitialized_move(dictionary, dictionary + capacity, newDict);
347 os::uninitialized_value_construct(newDict + capacity, newDict + finalCapacity);
348 os::destroy(dictionary, dictionary + capacity);
349
350 OSCONTAINER_ACCUMSIZE(sizeof(dictEntry) * (finalCapacity - capacity));
351
352 kfree_type(dictEntry, capacity, dictionary);
353 dictionary = newDict;
354 capacity = (unsigned int) finalCapacity;
355 }
356
357 return capacity;
358 }
359
360 void
flushCollection()361 OSDictionary::flushCollection()
362 {
363 haveUpdated();
364
365 for (unsigned int i = 0; i < count; i++) {
366 dictionary[i].key->taggedRelease(OSTypeID(OSCollection));
367 dictionary[i].value->taggedRelease(OSTypeID(OSCollection));
368 }
369 count = 0;
370 }
371
372 bool
373 OSDictionary::
setObject(const OSSymbol * aKey,const OSMetaClassBase * anObject,bool onlyAdd)374 setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject, bool onlyAdd)
375 {
376 unsigned int i;
377 bool exists;
378
379 if (!anObject || !aKey) {
380 return false;
381 }
382
383 // if the key exists, replace the object
384
385 if (fOptions & kSort) {
386 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
387 exists = (i < count) && (aKey == dictionary[i].key);
388 } else {
389 for (exists = false, i = 0; i < count; i++) {
390 if ((exists = (aKey == dictionary[i].key))) {
391 break;
392 }
393 }
394 }
395
396 if (exists) {
397 if (onlyAdd) {
398 return false;
399 }
400
401 OSTaggedSharedPtr<const OSMetaClassBase, OSCollection> oldObject;
402
403 haveUpdated();
404
405 dictionary[i].value.reset(anObject, OSRetain);
406 return true;
407 }
408
409 // add new key, possibly extending our capacity
410 if (count >= capacity && count >= ensureCapacity(count + 1)) {
411 return false;
412 }
413
414 haveUpdated();
415
416 new (&dictionary[count]) dictEntry();
417 os::move_backward(&dictionary[i], &dictionary[count], &dictionary[count + 1]);
418
419 dictionary[i].key.reset(aKey, OSRetain);
420 dictionary[i].value.reset(anObject, OSRetain);
421 count++;
422
423 return true;
424 }
425
426 bool
427 OSDictionary::
setObject(const OSSymbol * aKey,const OSMetaClassBase * anObject)428 setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject)
429 {
430 return setObject(aKey, anObject, false);
431 }
432
433 bool
setObject(OSSharedPtr<const OSSymbol> const & aKey,OSSharedPtr<const OSMetaClassBase> const & anObject)434 OSDictionary::setObject(OSSharedPtr<const OSSymbol> const& aKey, OSSharedPtr<const OSMetaClassBase> const& anObject)
435 {
436 return setObject(aKey.get(), anObject.get());
437 }
438
439 bool
setObject(const OSString * aKey,OSSharedPtr<const OSMetaClassBase> const & anObject)440 OSDictionary::setObject(const OSString* aKey, OSSharedPtr<const OSMetaClassBase> const& anObject)
441 {
442 return setObject(aKey, anObject.get());
443 }
444
445 bool
setObject(const char * aKey,OSSharedPtr<const OSMetaClassBase> const & anObject)446 OSDictionary::setObject(const char* aKey, OSSharedPtr<const OSMetaClassBase> const& anObject)
447 {
448 return setObject(aKey, anObject.get());
449 }
450
451 void
removeObject(const OSSymbol * aKey)452 OSDictionary::removeObject(const OSSymbol *aKey)
453 {
454 unsigned int i;
455 bool exists;
456
457 if (!aKey) {
458 return;
459 }
460
461 // if the key exists, remove the object
462
463 if (fOptions & kSort) {
464 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
465 exists = (i < count) && (aKey == dictionary[i].key);
466 } else {
467 for (exists = false, i = 0; i < count; i++) {
468 if ((exists = (aKey == dictionary[i].key))) {
469 break;
470 }
471 }
472 }
473
474 if (exists) {
475 dictEntry oldEntry = dictionary[i];
476
477 haveUpdated();
478
479 count--;
480 bcopy(&dictionary[i + 1], &dictionary[i], (count - i) * sizeof(dictionary[0]));
481
482 oldEntry.key->taggedRelease(OSTypeID(OSCollection));
483 oldEntry.value->taggedRelease(OSTypeID(OSCollection));
484 return;
485 }
486 }
487
488
489 // Returns true on success, false on an error condition.
490 bool
merge(const OSDictionary * srcDict)491 OSDictionary::merge(const OSDictionary *srcDict)
492 {
493 const OSSymbol * sym;
494 OSSharedPtr<OSCollectionIterator> iter;
495
496 if (!OSDynamicCast(OSDictionary, srcDict)) {
497 return false;
498 }
499
500 iter = OSCollectionIterator::withCollection(const_cast<OSDictionary *>(srcDict));
501 if (!iter) {
502 return false;
503 }
504
505 while ((sym = (const OSSymbol *)iter->getNextObject())) {
506 const OSMetaClassBase * obj;
507
508 obj = srcDict->getObject(sym);
509 if (!setObject(sym, obj)) {
510 return false;
511 }
512 }
513
514 return true;
515 }
516
517 OSObject *
getObject(const OSSymbol * aKey) const518 OSDictionary::getObject(const OSSymbol *aKey) const
519 {
520 unsigned int i, l = 0, r = count;
521
522 if (!aKey) {
523 return NULL;
524 }
525
526 // if the key exists, return the object
527 //
528 // inline OSSymbol::bsearch in this performance critical codepath
529 // for performance, the compiler can't do that due to the genericity
530 // of OSSymbol::bsearch
531 //
532 // If we have less than 4 objects, scanning is faster.
533 if (count > 4 && (fOptions & kSort)) {
534 while (l < r) {
535 i = (l + r) / 2;
536 if (aKey == dictionary[i].key) {
537 return const_cast<OSObject *> ((const OSObject *)dictionary[i].value.get());
538 }
539
540 if ((uintptr_t)aKey < (uintptr_t)dictionary[i].key.get()) {
541 r = i;
542 } else {
543 l = i + 1;
544 }
545 }
546 } else {
547 for (i = l; i < r; i++) {
548 if (aKey == dictionary[i].key) {
549 return const_cast<OSObject *> ((const OSObject *)dictionary[i].value.get());
550 }
551 }
552 }
553
554 return NULL;
555 }
556
557 // Wrapper macros
558 #define OBJECT_WRAP_1(cmd, k) \
559 { \
560 OSSharedPtr<const OSSymbol> tmpKey = k; \
561 OSObject *retObj = NULL; \
562 if (tmpKey) { \
563 retObj = cmd(tmpKey.get()); \
564 } \
565 return retObj; \
566 }
567
568 #define OBJECT_WRAP_2(cmd, k, o) \
569 { \
570 OSSharedPtr<const OSSymbol> tmpKey = k; \
571 bool ret = cmd(tmpKey.get(), o); \
572 \
573 return ret; \
574 }
575
576 #define OBJECT_WRAP_3(cmd, k) \
577 { \
578 OSSharedPtr<const OSSymbol> tmpKey = k; \
579 if (tmpKey) { \
580 cmd(tmpKey.get()); \
581 } \
582 }
583
584
585 bool
setObject(const OSString * aKey,const OSMetaClassBase * anObject)586 OSDictionary::setObject(const OSString *aKey, const OSMetaClassBase *anObject)
587 OBJECT_WRAP_2(setObject, OSSymbol::withString(aKey), anObject)
588 bool
589 OSDictionary::setObject(const char *aKey, const OSMetaClassBase *anObject)
590 OBJECT_WRAP_2(setObject, OSSymbol::withCString(aKey), anObject)
591
592 OSObject *OSDictionary::getObject(const OSString * aKey) const
593 OBJECT_WRAP_1(getObject, OSSymbol::existingSymbolForString(aKey))
594 OSObject *OSDictionary::getObject(const char *aKey) const
595 OBJECT_WRAP_1(getObject, OSSymbol::existingSymbolForCString(aKey))
596
597 void
598 OSDictionary::removeObject(const OSString *aKey)
599 OBJECT_WRAP_3(removeObject, OSSymbol::existingSymbolForString(aKey))
600 void
601 OSDictionary::removeObject(const char *aKey)
602 OBJECT_WRAP_3(removeObject, OSSymbol::existingSymbolForCString(aKey))
603
604 bool
605 OSDictionary::isEqualTo(const OSDictionary *srcDict, const OSCollection *keys) const
606 {
607 OSSharedPtr<OSCollectionIterator> iter;
608 unsigned int keysCount;
609 const OSMetaClassBase * obj1;
610 const OSMetaClassBase * obj2;
611 OSString * aKey;
612 bool ret;
613
614 if (this == srcDict) {
615 return true;
616 }
617
618 keysCount = keys->getCount();
619 if ((count < keysCount) || (srcDict->getCount() < keysCount)) {
620 return false;
621 }
622
623 iter = OSCollectionIterator::withCollection(keys);
624 if (!iter) {
625 return false;
626 }
627
628 ret = true;
629 while ((aKey = OSDynamicCast(OSString, iter->getNextObject()))) {
630 obj1 = getObject(aKey);
631 obj2 = srcDict->getObject(aKey);
632 if (!obj1 || !obj2) {
633 ret = false;
634 break;
635 }
636
637 if (!obj1->isEqualTo(obj2)) {
638 ret = false;
639 break;
640 }
641 }
642
643 return ret;
644 }
645
646 bool
isEqualTo(const OSDictionary * srcDict) const647 OSDictionary::isEqualTo(const OSDictionary *srcDict) const
648 {
649 unsigned int i;
650 const OSMetaClassBase * obj;
651
652 if (this == srcDict) {
653 return true;
654 }
655
656 if (count != srcDict->getCount()) {
657 return false;
658 }
659
660 for (i = 0; i < count; i++) {
661 obj = srcDict->getObject(dictionary[i].key.get());
662 if (!obj) {
663 return false;
664 }
665
666 if (!dictionary[i].value->isEqualTo(obj)) {
667 return false;
668 }
669 }
670
671 return true;
672 }
673
674 bool
isEqualTo(const OSMetaClassBase * anObject) const675 OSDictionary::isEqualTo(const OSMetaClassBase *anObject) const
676 {
677 OSDictionary *dict;
678
679 dict = OSDynamicCast(OSDictionary, anObject);
680 if (dict) {
681 return isEqualTo(dict);
682 } else {
683 return false;
684 }
685 }
686
687 unsigned int
iteratorSize() const688 OSDictionary::iteratorSize() const
689 {
690 return sizeof(unsigned int);
691 }
692
693 bool
initIterator(void * inIterator) const694 OSDictionary::initIterator(void *inIterator) const
695 {
696 unsigned int *iteratorP = (unsigned int *) inIterator;
697
698 *iteratorP = 0;
699 return true;
700 }
701
702 bool
getNextObjectForIterator(void * inIterator,OSObject ** ret) const703 OSDictionary::getNextObjectForIterator(void *inIterator, OSObject **ret) const
704 {
705 unsigned int *iteratorP = (unsigned int *) inIterator;
706 unsigned int index = (*iteratorP)++;
707
708 if (index < count) {
709 *ret = const_cast<OSSymbol*>(dictionary[index].key.get());
710 } else {
711 *ret = NULL;
712 }
713
714 return *ret != NULL;
715 }
716
717 bool
serialize(OSSerialize * s) const718 OSDictionary::serialize(OSSerialize *s) const
719 {
720 if (s->previouslySerialized(this)) {
721 return true;
722 }
723
724 if (!s->addXMLStartTag(this, "dict")) {
725 return false;
726 }
727
728 for (unsigned i = 0; i < count; i++) {
729 const OSSymbol *key = dictionary[i].key.get();
730
731 // due the nature of the XML syntax, this must be a symbol
732 if (!key->metaCast("OSSymbol")) {
733 return false;
734 }
735 if (!s->addString("<key>")) {
736 return false;
737 }
738 const char *c = key->getCStringNoCopy();
739 while (*c) {
740 if (*c == '<') {
741 if (!s->addString("<")) {
742 return false;
743 }
744 } else if (*c == '>') {
745 if (!s->addString(">")) {
746 return false;
747 }
748 } else if (*c == '&') {
749 if (!s->addString("&")) {
750 return false;
751 }
752 } else {
753 if (!s->addChar(*c)) {
754 return false;
755 }
756 }
757 c++;
758 }
759 if (!s->addXMLEndTag("key")) {
760 return false;
761 }
762
763 if (!dictionary[i].value->serialize(s)) {
764 return false;
765 }
766 }
767
768 return s->addXMLEndTag("dict");
769 }
770
771 unsigned
setOptions(unsigned options,unsigned mask,void *)772 OSDictionary::setOptions(unsigned options, unsigned mask, void *)
773 {
774 unsigned old = super::setOptions(options, mask);
775 if ((old ^ options) & mask) {
776 // Value changed need to recurse over all of the child collections
777 for (unsigned i = 0; i < count; i++) {
778 OSCollection *v = OSDynamicCast(OSCollection, dictionary[i].value.get());
779 if (v) {
780 v->setOptions(options, mask);
781 }
782 }
783 }
784
785 if (!(old & kSort) && (fOptions & kSort)) {
786 sortBySymbol();
787 }
788
789 return old;
790 }
791
792 OSSharedPtr<OSCollection>
copyCollection(OSDictionary * cycleDict)793 OSDictionary::copyCollection(OSDictionary *cycleDict)
794 {
795 OSSharedPtr<OSDictionary> ourCycleDict;
796 OSSharedPtr<OSCollection> ret;
797 OSSharedPtr<OSDictionary> newDict;
798
799 if (!cycleDict) {
800 ourCycleDict = OSDictionary::withCapacity(16);
801 if (!ourCycleDict) {
802 return nullptr;
803 }
804 cycleDict = ourCycleDict.get();
805 }
806
807 do {
808 // Check for a cycle
809 ret = super::copyCollection(cycleDict);
810 if (ret) {
811 continue;
812 }
813
814 newDict = OSDictionary::withDictionary(this);
815 if (!newDict) {
816 continue;
817 }
818
819 // Insert object into cycle Dictionary
820 cycleDict->setObject((const OSSymbol *) this, newDict.get());
821
822 for (unsigned int i = 0; i < count; i++) {
823 const OSMetaClassBase *obj = dictionary[i].value.get();
824 OSTaggedSharedPtr<OSCollection, OSCollection> coll(OSDynamicCast(OSCollection, EXT_CAST(obj)), OSNoRetain);
825
826 if (coll) {
827 OSSharedPtr<OSCollection> newColl = coll->copyCollection(cycleDict);
828 if (!newColl) {
829 return ret;
830 }
831 newDict->dictionary[i].value.detach();
832 newDict->dictionary[i].value.reset(newColl.get(), OSRetain);
833 }
834 }
835
836 ret = os::move(newDict);
837 } while (false);
838
839 return ret;
840 }
841
842 OSSharedPtr<OSArray>
copyKeys(void)843 OSDictionary::copyKeys(void)
844 {
845 OSSharedPtr<OSArray> array;
846
847 array = OSArray::withCapacity(count);
848 if (!array) {
849 return nullptr;
850 }
851
852 for (unsigned int i = 0; i < count; i++) {
853 if (!array->setObject(i, dictionary[i].key.get())) {
854 return nullptr;
855 }
856 }
857 return array;
858 }
859
860 bool
iterateObjects(void * refcon,bool (* callback)(void * refcon,const OSSymbol * key,OSObject * object))861 OSDictionary::iterateObjects(void * refcon, bool (*callback)(void * refcon, const OSSymbol * key, OSObject * object))
862 {
863 unsigned int initialUpdateStamp;
864 bool done;
865
866 initialUpdateStamp = updateStamp;
867 done = false;
868 for (unsigned int i = 0; i < count; i++) {
869 done = callback(refcon, dictionary[i].key.get(), EXT_CAST(dictionary[i].value.get()));
870 if (done) {
871 break;
872 }
873 if (initialUpdateStamp != updateStamp) {
874 break;
875 }
876 }
877
878 return initialUpdateStamp == updateStamp;
879 }
880
881 static bool
OSDictionaryIterateObjectsBlock(void * refcon,const OSSymbol * key,OSObject * object)882 OSDictionaryIterateObjectsBlock(void * refcon, const OSSymbol * key, OSObject * object)
883 {
884 bool (^block)(const OSSymbol * key, OSObject * object) = (typeof(block))refcon;
885 return block(key, object);
886 }
887
888 bool
889 OSDictionary::iterateObjects(bool (^block)(const OSSymbol * key, OSObject * object))
890 {
891 return iterateObjects((void *)block, &OSDictionaryIterateObjectsBlock);
892 }
893