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 |
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 |
77 | OSDictionary::sortBySymbol(void) |
78 | { |
79 | qsort(dictionary, count, sizeof(OSDictionary::dictEntry), |
80 | &OSDictionary::dictEntry::compare); |
81 | } |
82 | |
83 | bool |
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 |
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(inCapacity: 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(aKey: keys[i], anObject: newObject)) { |
138 | return false; |
139 | } |
140 | } |
141 | |
142 | return true; |
143 | } |
144 | |
145 | bool |
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(inCapacity: newCapacity)) { |
166 | return false; |
167 | } |
168 | |
169 | for (unsigned int i = 0; i < theCount; i++) { |
170 | OSSharedPtr<const OSSymbol> key = OSSymbol::withString(aString: *keys++); |
171 | const OSMetaClassBase *newObject = *objects++; |
172 | |
173 | if (!key) { |
174 | return false; |
175 | } |
176 | |
177 | if (!newObject || !setObject(aKey: key.get(), anObject: newObject)) { |
178 | return false; |
179 | } |
180 | } |
181 | |
182 | return true; |
183 | } |
184 | |
185 | bool |
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(inCapacity: 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> |
223 | OSDictionary::withCapacity(unsigned int capacity) |
224 | { |
225 | OSSharedPtr<OSDictionary> me = OSMakeShared<OSDictionary>(); |
226 | |
227 | if (me && !me->initWithCapacity(inCapacity: capacity)) { |
228 | return nullptr; |
229 | } |
230 | |
231 | return me; |
232 | } |
233 | |
234 | OSSharedPtr<OSDictionary> |
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, theCount: count, theCapacity: capacity)) { |
243 | return nullptr; |
244 | } |
245 | |
246 | return me; |
247 | } |
248 | |
249 | OSSharedPtr<OSDictionary> |
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, theCount: count, theCapacity: capacity)) { |
258 | return nullptr; |
259 | } |
260 | |
261 | return me; |
262 | } |
263 | |
264 | OSSharedPtr<OSDictionary> |
265 | OSDictionary::withDictionary(const OSDictionary *dict, |
266 | unsigned int capacity) |
267 | { |
268 | OSSharedPtr<OSDictionary> me = OSMakeShared<OSDictionary>(); |
269 | |
270 | if (me && !me->initWithDictionary(dict, theCapacity: capacity)) { |
271 | return nullptr; |
272 | } |
273 | |
274 | return me; |
275 | } |
276 | |
277 | void |
278 | OSDictionary::free() |
279 | { |
280 | (void) super::setOptions(options: 0, mask: 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 |
291 | OSDictionary::getCount() const |
292 | { |
293 | return count; |
294 | } |
295 | unsigned int |
296 | OSDictionary::getCapacity() const |
297 | { |
298 | return capacity; |
299 | } |
300 | |
301 | unsigned int |
302 | OSDictionary::getCapacityIncrement() const |
303 | { |
304 | return capacityIncrement; |
305 | } |
306 | |
307 | unsigned int |
308 | OSDictionary::setCapacityIncrement(unsigned int increment) |
309 | { |
310 | capacityIncrement = (increment)? increment : 16; |
311 | |
312 | return capacityIncrement; |
313 | } |
314 | |
315 | unsigned int |
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 |
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:: |
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(key: aKey, array: &dictionary[0], arrayCount: count, memberSize: 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(p: anObject, OSRetain); |
391 | return true; |
392 | } |
393 | |
394 | // add new key, possibly extending our capacity |
395 | if (count >= capacity && count >= ensureCapacity(newCapacity: count + 1)) { |
396 | return false; |
397 | } |
398 | |
399 | haveUpdated(); |
400 | |
401 | new (&dictionary[count]) dictEntry(); |
402 | os::move_backward(first: &dictionary[i], last: &dictionary[count], d_last: &dictionary[count + 1]); |
403 | |
404 | dictionary[i].key.reset(p: aKey, OSRetain); |
405 | dictionary[i].value.reset(p: anObject, OSRetain); |
406 | count++; |
407 | |
408 | return true; |
409 | } |
410 | |
411 | bool |
412 | OSDictionary:: |
413 | setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject) |
414 | { |
415 | return setObject(aKey, anObject, onlyAdd: false); |
416 | } |
417 | |
418 | bool |
419 | OSDictionary::setObject(OSSharedPtr<const OSSymbol> const& aKey, OSSharedPtr<const OSMetaClassBase> const& anObject) |
420 | { |
421 | return setObject(aKey: aKey.get(), anObject: anObject.get()); |
422 | } |
423 | |
424 | bool |
425 | OSDictionary::setObject(const OSString* aKey, OSSharedPtr<const OSMetaClassBase> const& anObject) |
426 | { |
427 | return setObject(aKey, anObject: anObject.get()); |
428 | } |
429 | |
430 | bool |
431 | OSDictionary::setObject(const char* aKey, OSSharedPtr<const OSMetaClassBase> const& anObject) |
432 | { |
433 | return setObject(aKey, anObject: anObject.get()); |
434 | } |
435 | |
436 | void |
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(key: aKey, array: &dictionary[0], arrayCount: count, memberSize: 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(src: &dictionary[i + 1], dst: &dictionary[i], n: (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 |
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(inColl: 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(aKey: sym); |
494 | if (!setObject(aKey: sym, anObject: obj)) { |
495 | return false; |
496 | } |
497 | } |
498 | |
499 | return true; |
500 | } |
501 | |
502 | OSObject * |
503 | 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 |
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(inColl: 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(anObject: obj2)) { |
623 | ret = false; |
624 | break; |
625 | } |
626 | } |
627 | |
628 | return ret; |
629 | } |
630 | |
631 | bool |
632 | 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(aKey: dictionary[i].key.get()); |
647 | if (!obj) { |
648 | return false; |
649 | } |
650 | |
651 | if (!dictionary[i].value->isEqualTo(anObject: obj)) { |
652 | return false; |
653 | } |
654 | } |
655 | |
656 | return true; |
657 | } |
658 | |
659 | bool |
660 | OSDictionary::isEqualTo(const OSMetaClassBase *anObject) const |
661 | { |
662 | OSDictionary *dict; |
663 | |
664 | dict = OSDynamicCast(OSDictionary, anObject); |
665 | if (dict) { |
666 | return isEqualTo(srcDict: dict); |
667 | } else { |
668 | return false; |
669 | } |
670 | } |
671 | |
672 | unsigned int |
673 | OSDictionary::iteratorSize() const |
674 | { |
675 | return sizeof(unsigned int); |
676 | } |
677 | |
678 | bool |
679 | OSDictionary::initIterator(void *inIterator) const |
680 | { |
681 | unsigned int *iteratorP = (unsigned int *) inIterator; |
682 | |
683 | *iteratorP = 0; |
684 | return true; |
685 | } |
686 | |
687 | bool |
688 | 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 |
703 | OSDictionary::serialize(OSSerialize *s) const |
704 | { |
705 | if (s->previouslySerialized(object: this)) { |
706 | return true; |
707 | } |
708 | |
709 | if (!s->addXMLStartTag(object: this, tagString: "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(toMeta: "OSSymbol" )) { |
718 | return false; |
719 | } |
720 | if (!s->addString(cString: "<key>" )) { |
721 | return false; |
722 | } |
723 | const char *c = key->getCStringNoCopy(); |
724 | while (*c) { |
725 | if (*c == '<') { |
726 | if (!s->addString(cString: "<" )) { |
727 | return false; |
728 | } |
729 | } else if (*c == '>') { |
730 | if (!s->addString(cString: ">" )) { |
731 | return false; |
732 | } |
733 | } else if (*c == '&') { |
734 | if (!s->addString(cString: "&" )) { |
735 | return false; |
736 | } |
737 | } else { |
738 | if (!s->addChar(aChar: *c)) { |
739 | return false; |
740 | } |
741 | } |
742 | c++; |
743 | } |
744 | if (!s->addXMLEndTag(tagString: "key" )) { |
745 | return false; |
746 | } |
747 | |
748 | if (!dictionary[i].value->serialize(serializer: s)) { |
749 | return false; |
750 | } |
751 | } |
752 | |
753 | return s->addXMLEndTag(tagString: "dict" ); |
754 | } |
755 | |
756 | unsigned |
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> |
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(capacity: 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(dict: this); |
800 | if (!newDict) { |
801 | continue; |
802 | } |
803 | |
804 | // Insert object into cycle Dictionary |
805 | cycleDict->setObject(aKey: (const OSSymbol *) this, anObject: 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(p: newColl.get(), OSRetain); |
818 | } |
819 | } |
820 | |
821 | ret = os::move(t&: newDict); |
822 | } while (false); |
823 | |
824 | return ret; |
825 | } |
826 | |
827 | OSSharedPtr<OSArray> |
828 | OSDictionary::copyKeys(void) |
829 | { |
830 | OSSharedPtr<OSArray> array; |
831 | |
832 | array = OSArray::withCapacity(capacity: count); |
833 | if (!array) { |
834 | return nullptr; |
835 | } |
836 | |
837 | for (unsigned int i = 0; i < count; i++) { |
838 | if (!array->setObject(index: i, anObject: dictionary[i].key.get())) { |
839 | return nullptr; |
840 | } |
841 | } |
842 | return array; |
843 | } |
844 | |
845 | bool |
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 |
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(refcon: (void *)block, callback: &OSDictionaryIterateObjectsBlock); |
877 | } |
878 | |