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