xref: /xnu-11215/libkern/c++/OSDictionary.cpp (revision 5c2921b0)
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("&lt;")) {
727 					return false;
728 				}
729 			} else if (*c == '>') {
730 				if (!s->addString("&gt;")) {
731 					return false;
732 				}
733 			} else if (*c == '&') {
734 				if (!s->addString("&amp;")) {
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