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