]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSDictionary.cpp
a53f23ad730eb1889591f733c826e963f177e4f0
[apple/xnu.git] / libkern / c++ / OSDictionary.cpp
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 bool OSDictionary::initWithCapacity(unsigned int inCapacity)
56 {
57 if (!super::init())
58 return false;
59
60 if (inCapacity > (UINT_MAX / sizeof(dictEntry)))
61 return false;
62
63 unsigned int size = inCapacity * sizeof(dictEntry);
64 //fOptions |= kSort;
65
66 dictionary = (dictEntry *) kalloc_container(size);
67 if (!dictionary)
68 return false;
69
70 bzero(dictionary, size);
71 OSCONTAINER_ACCUMSIZE(size);
72
73 count = 0;
74 capacity = inCapacity;
75 capacityIncrement = (inCapacity)? inCapacity : 16;
76
77 return true;
78 }
79
80 bool OSDictionary::initWithObjects(const OSObject *objects[],
81 const OSSymbol *keys[],
82 unsigned int theCount,
83 unsigned int theCapacity)
84 {
85 unsigned int newCapacity = theCount;
86
87 if (!objects || !keys)
88 return false;
89
90 if ( theCapacity ) {
91 if (theCount > theCapacity)
92 return false;
93
94 newCapacity = theCapacity;
95 }
96
97 if (!initWithCapacity(newCapacity))
98 return false;
99
100 for (unsigned int i = 0; i < theCount; i++) {
101 const OSMetaClassBase *newObject = *objects++;
102
103 if (!newObject || !keys[i] || !setObject(keys[i], newObject))
104 return false;
105 }
106
107 return true;
108 }
109
110 bool OSDictionary::initWithObjects(const OSObject *objects[],
111 const OSString *keys[],
112 unsigned int theCount,
113 unsigned int theCapacity)
114 {
115 unsigned int newCapacity = theCount;
116
117 if (!objects || !keys)
118 return false;
119
120 if ( theCapacity ) {
121 if (theCount > theCapacity)
122 return false;
123
124 newCapacity = theCapacity;
125 }
126
127 if (!initWithCapacity(newCapacity))
128 return false;
129
130 for (unsigned int i = 0; i < theCount; i++) {
131 const OSSymbol *key = OSSymbol::withString(*keys++);
132 const OSMetaClassBase *newObject = *objects++;
133
134 if (!key)
135 return false;
136
137 if (!newObject || !setObject(key, newObject)) {
138 key->release();
139 return false;
140 }
141
142 key->release();
143 }
144
145 return true;
146 }
147
148 bool OSDictionary::initWithDictionary(const OSDictionary *dict,
149 unsigned int theCapacity)
150 {
151 unsigned int newCapacity;
152
153 if ( !dict )
154 return false;
155
156 newCapacity = dict->count;
157
158 if ( theCapacity ) {
159 if ( dict->count > theCapacity )
160 return false;
161
162 newCapacity = theCapacity;
163 }
164
165 if (!initWithCapacity(newCapacity))
166 return false;
167
168 if ((kSort & fOptions) && !(kSort & dict->fOptions)) {
169 for (unsigned int i = 0; i < dict->count; i++) {
170 if (!setObject(dict->dictionary[i].key, dict->dictionary[i].value)) {
171 return false;
172 }
173 }
174 return true;
175 }
176
177 count = dict->count;
178 bcopy(dict->dictionary, dictionary, count * sizeof(dictEntry));
179 for (unsigned int i = 0; i < count; i++) {
180 dictionary[i].key->taggedRetain(OSTypeID(OSCollection));
181 dictionary[i].value->taggedRetain(OSTypeID(OSCollection));
182 }
183
184 return true;
185 }
186
187 OSDictionary *OSDictionary::withCapacity(unsigned int capacity)
188 {
189 OSDictionary *me = new OSDictionary;
190
191 if (me && !me->initWithCapacity(capacity)) {
192 me->release();
193 return 0;
194 }
195
196 return me;
197 }
198
199 OSDictionary *OSDictionary::withObjects(const OSObject *objects[],
200 const OSSymbol *keys[],
201 unsigned int count,
202 unsigned int capacity)
203 {
204 OSDictionary *me = new OSDictionary;
205
206 if (me && !me->initWithObjects(objects, keys, count, capacity)) {
207 me->release();
208 return 0;
209 }
210
211 return me;
212 }
213
214 OSDictionary *OSDictionary::withObjects(const OSObject *objects[],
215 const OSString *keys[],
216 unsigned int count,
217 unsigned int capacity)
218 {
219 OSDictionary *me = new OSDictionary;
220
221 if (me && !me->initWithObjects(objects, keys, count, capacity)) {
222 me->release();
223 return 0;
224 }
225
226 return me;
227 }
228
229 OSDictionary *OSDictionary::withDictionary(const OSDictionary *dict,
230 unsigned int capacity)
231 {
232 OSDictionary *me = new OSDictionary;
233
234 if (me && !me->initWithDictionary(dict, capacity)) {
235 me->release();
236 return 0;
237 }
238
239 return me;
240 }
241
242 void OSDictionary::free()
243 {
244 (void) super::setOptions(0, kImmutable);
245 flushCollection();
246 if (dictionary) {
247 kfree(dictionary, capacity * sizeof(dictEntry));
248 OSCONTAINER_ACCUMSIZE( -(capacity * sizeof(dictEntry)) );
249 }
250
251 super::free();
252 }
253
254 unsigned int OSDictionary::getCount() const { return count; }
255 unsigned int OSDictionary::getCapacity() const { return capacity; }
256
257 unsigned int OSDictionary::getCapacityIncrement() const
258 {
259 return capacityIncrement;
260 }
261
262 unsigned int OSDictionary::setCapacityIncrement(unsigned int increment)
263 {
264 capacityIncrement = (increment)? increment : 16;
265
266 return capacityIncrement;
267 }
268
269 unsigned int OSDictionary::ensureCapacity(unsigned int newCapacity)
270 {
271 dictEntry *newDict;
272 unsigned int finalCapacity, oldSize, newSize;
273
274 if (newCapacity <= capacity)
275 return capacity;
276
277 // round up
278 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1)
279 * capacityIncrement;
280
281 // integer overflow check
282 if (finalCapacity < newCapacity || (finalCapacity > (UINT_MAX / sizeof(dictEntry))))
283 return capacity;
284
285 newSize = sizeof(dictEntry) * finalCapacity;
286
287 newDict = (dictEntry *) kalloc_container(newSize);
288 if (newDict) {
289 oldSize = sizeof(dictEntry) * capacity;
290
291 bcopy(dictionary, newDict, oldSize);
292 bzero(&newDict[capacity], newSize - oldSize);
293
294 OSCONTAINER_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize));
295 kfree(dictionary, oldSize);
296
297 dictionary = newDict;
298 capacity = finalCapacity;
299 }
300
301 return capacity;
302 }
303
304 void OSDictionary::flushCollection()
305 {
306 haveUpdated();
307
308 for (unsigned int i = 0; i < count; i++) {
309 dictionary[i].key->taggedRelease(OSTypeID(OSCollection));
310 dictionary[i].value->taggedRelease(OSTypeID(OSCollection));
311 }
312 count = 0;
313 }
314
315 bool OSDictionary::
316 setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject, bool onlyAdd)
317 {
318 unsigned int i;
319 bool exists;
320
321 if (!anObject || !aKey)
322 return false;
323
324 // if the key exists, replace the object
325
326 if (fOptions & kSort) {
327 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
328 exists = (i < count) && (aKey == dictionary[i].key);
329 } else for (exists = false, i = 0; i < count; i++) {
330 if ((exists = (aKey == dictionary[i].key))) break;
331 }
332
333 if (exists) {
334
335 if (onlyAdd) return false;
336
337 const OSMetaClassBase *oldObject = dictionary[i].value;
338
339 haveUpdated();
340
341 anObject->taggedRetain(OSTypeID(OSCollection));
342 dictionary[i].value = anObject;
343
344 oldObject->taggedRelease(OSTypeID(OSCollection));
345 return true;
346 }
347
348 // add new key, possibly extending our capacity
349 if (count >= capacity && count >= ensureCapacity(count+1))
350 return false;
351
352 haveUpdated();
353
354 bcopy(&dictionary[i], &dictionary[i+1], (count - i) * sizeof(dictionary[0]));
355
356 aKey->taggedRetain(OSTypeID(OSCollection));
357 anObject->taggedRetain(OSTypeID(OSCollection));
358 dictionary[i].key = aKey;
359 dictionary[i].value = anObject;
360 count++;
361
362 return true;
363 }
364
365 bool OSDictionary::
366 setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject)
367 {
368 return (setObject(aKey, anObject, false));
369 }
370
371 void OSDictionary::removeObject(const OSSymbol *aKey)
372 {
373 unsigned int i;
374 bool exists;
375
376 if (!aKey)
377 return;
378
379 // if the key exists, remove the object
380
381 if (fOptions & kSort) {
382 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
383 exists = (i < count) && (aKey == dictionary[i].key);
384 } else for (exists = false, i = 0; i < count; i++) {
385 if ((exists = (aKey == dictionary[i].key))) break;
386 }
387
388 if (exists) {
389 dictEntry oldEntry = dictionary[i];
390
391 haveUpdated();
392
393 count--;
394 bcopy(&dictionary[i+1], &dictionary[i], (count - i) * sizeof(dictionary[0]));
395
396 oldEntry.key->taggedRelease(OSTypeID(OSCollection));
397 oldEntry.value->taggedRelease(OSTypeID(OSCollection));
398 return;
399 }
400 }
401
402
403 // Returns true on success, false on an error condition.
404 bool OSDictionary::merge(const OSDictionary *srcDict)
405 {
406 const OSSymbol * sym;
407 OSCollectionIterator * iter;
408
409 if ( !OSDynamicCast(OSDictionary, srcDict) )
410 return false;
411
412 iter = OSCollectionIterator::withCollection(const_cast<OSDictionary *>(srcDict));
413 if ( !iter )
414 return false;
415
416 while ( (sym = (const OSSymbol *)iter->getNextObject()) ) {
417 const OSMetaClassBase * obj;
418
419 obj = srcDict->getObject(sym);
420 if ( !setObject(sym, obj) ) {
421 iter->release();
422 return false;
423 }
424 }
425 iter->release();
426
427 return true;
428 }
429
430 OSObject *OSDictionary::getObject(const OSSymbol *aKey) const
431 {
432 unsigned int i;
433 bool exists;
434
435 if (!aKey)
436 return 0;
437
438 // if the key exists, return the object
439
440 if (fOptions & kSort) {
441 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
442 exists = (i < count) && (aKey == dictionary[i].key);
443 } else for (exists = false, i = 0; i < count; i++) {
444 if ((exists = (aKey == dictionary[i].key))) break;
445 }
446
447 if (exists) {
448 return (const_cast<OSObject *> ((const OSObject *)dictionary[i].value));
449 }
450
451 return 0;
452 }
453
454 // Wrapper macros
455 #define OBJECT_WRAP_1(cmd, k) \
456 { \
457 const OSSymbol *tmpKey = k; \
458 OSObject *retObj = cmd(tmpKey); \
459 \
460 tmpKey->release(); \
461 return retObj; \
462 }
463
464 #define OBJECT_WRAP_2(cmd, k, o) \
465 { \
466 const OSSymbol *tmpKey = k; \
467 bool ret = cmd(tmpKey, o); \
468 \
469 tmpKey->release(); \
470 return ret; \
471 }
472
473 #define OBJECT_WRAP_3(cmd, k) \
474 { \
475 const OSSymbol *tmpKey = k; \
476 cmd(tmpKey); \
477 tmpKey->release(); \
478 }
479
480
481 bool OSDictionary::setObject(const OSString *aKey, const OSMetaClassBase *anObject)
482 OBJECT_WRAP_2(setObject, OSSymbol::withString(aKey), anObject)
483 bool OSDictionary::setObject(const char *aKey, const OSMetaClassBase *anObject)
484 OBJECT_WRAP_2(setObject, OSSymbol::withCString(aKey), anObject)
485
486 OSObject *OSDictionary::getObject(const OSString *aKey) const
487 OBJECT_WRAP_1(getObject, OSSymbol::withString(aKey))
488 OSObject *OSDictionary::getObject(const char *aKey) const
489 OBJECT_WRAP_1(getObject, OSSymbol::withCString(aKey))
490
491 void OSDictionary::removeObject(const OSString *aKey)
492 OBJECT_WRAP_3(removeObject, OSSymbol::withString(aKey))
493 void OSDictionary::removeObject(const char *aKey)
494 OBJECT_WRAP_3(removeObject, OSSymbol::withCString(aKey))
495
496 bool
497 OSDictionary::isEqualTo(const OSDictionary *srcDict, const OSCollection *keys) const
498 {
499 OSCollectionIterator * iter;
500 unsigned int keysCount;
501 const OSMetaClassBase * obj1;
502 const OSMetaClassBase * obj2;
503 OSString * aKey;
504 bool ret;
505
506 if ( this == srcDict )
507 return true;
508
509 keysCount = keys->getCount();
510 if ( (count < keysCount) || (srcDict->getCount() < keysCount) )
511 return false;
512
513 iter = OSCollectionIterator::withCollection(keys);
514 if ( !iter )
515 return false;
516
517 ret = true;
518 while ( (aKey = OSDynamicCast(OSString, iter->getNextObject())) ) {
519 obj1 = getObject(aKey);
520 obj2 = srcDict->getObject(aKey);
521 if ( !obj1 || !obj2 ) {
522 ret = false;
523 break;
524 }
525
526 if ( !obj1->isEqualTo(obj2) ) {
527 ret = false;
528 break;
529 }
530 }
531 iter->release();
532
533 return ret;
534 }
535
536 bool OSDictionary::isEqualTo(const OSDictionary *srcDict) const
537 {
538 unsigned int i;
539 const OSMetaClassBase * obj;
540
541 if ( this == srcDict )
542 return true;
543
544 if ( count != srcDict->getCount() )
545 return false;
546
547 for ( i = 0; i < count; i++ ) {
548 obj = srcDict->getObject(dictionary[i].key);
549 if ( !obj )
550 return false;
551
552 if ( !dictionary[i].value->isEqualTo(obj) )
553 return false;
554 }
555
556 return true;
557 }
558
559 bool OSDictionary::isEqualTo(const OSMetaClassBase *anObject) const
560 {
561 OSDictionary *dict;
562
563 dict = OSDynamicCast(OSDictionary, anObject);
564 if ( dict )
565 return isEqualTo(dict);
566 else
567 return false;
568 }
569
570 unsigned int OSDictionary::iteratorSize() const
571 {
572 return sizeof(unsigned int);
573 }
574
575 bool OSDictionary::initIterator(void *inIterator) const
576 {
577 unsigned int *iteratorP = (unsigned int *) inIterator;
578
579 *iteratorP = 0;
580 return true;
581 }
582
583 bool OSDictionary::getNextObjectForIterator(void *inIterator, OSObject **ret) const
584 {
585 unsigned int *iteratorP = (unsigned int *) inIterator;
586 unsigned int index = (*iteratorP)++;
587
588 if (index < count)
589 *ret = (OSObject *) dictionary[index].key;
590 else
591 *ret = 0;
592
593 return (*ret != 0);
594 }
595
596 bool OSDictionary::serialize(OSSerialize *s) const
597 {
598 if (s->previouslySerialized(this)) return true;
599
600 if (!s->addXMLStartTag(this, "dict")) return false;
601
602 for (unsigned i = 0; i < count; i++) {
603 const OSSymbol *key = dictionary[i].key;
604
605 // due the nature of the XML syntax, this must be a symbol
606 if (!key->metaCast("OSSymbol")) {
607 return false;
608 }
609 if (!s->addString("<key>")) return false;
610 const char *c = key->getCStringNoCopy();
611 while (*c) {
612 if (*c == '<') {
613 if (!s->addString("&lt;")) return false;
614 } else if (*c == '>') {
615 if (!s->addString("&gt;")) return false;
616 } else if (*c == '&') {
617 if (!s->addString("&amp;")) return false;
618 } else {
619 if (!s->addChar(*c)) return false;
620 }
621 c++;
622 }
623 if (!s->addXMLEndTag("key")) return false;
624
625 if (!dictionary[i].value->serialize(s)) return false;
626 }
627
628 return s->addXMLEndTag("dict");
629 }
630
631 unsigned OSDictionary::setOptions(unsigned options, unsigned mask, void *)
632 {
633 unsigned old = super::setOptions(options, mask);
634 if ((old ^ options) & mask) {
635
636 // Value changed need to recurse over all of the child collections
637 for ( unsigned i = 0; i < count; i++ ) {
638 OSCollection *v = OSDynamicCast(OSCollection, dictionary[i].value);
639 if (v)
640 v->setOptions(options, mask);
641 }
642 }
643
644 return old;
645 }
646
647 OSCollection * OSDictionary::copyCollection(OSDictionary *cycleDict)
648 {
649 bool allocDict = !cycleDict;
650 OSCollection *ret = 0;
651 OSDictionary *newDict = 0;
652
653 if (allocDict) {
654 cycleDict = OSDictionary::withCapacity(16);
655 if (!cycleDict)
656 return 0;
657 }
658
659 do {
660 // Check for a cycle
661 ret = super::copyCollection(cycleDict);
662 if (ret)
663 continue;
664
665 newDict = OSDictionary::withDictionary(this);
666 if (!newDict)
667 continue;
668
669 // Insert object into cycle Dictionary
670 cycleDict->setObject((const OSSymbol *) this, newDict);
671
672 for (unsigned int i = 0; i < count; i++) {
673 const OSMetaClassBase *obj = dictionary[i].value;
674 OSCollection *coll = OSDynamicCast(OSCollection, EXT_CAST(obj));
675
676 if (coll) {
677 OSCollection *newColl = coll->copyCollection(cycleDict);
678 if (!newColl)
679 goto abortCopy;
680
681 newDict->dictionary[i].value = newColl;
682
683 coll->taggedRelease(OSTypeID(OSCollection));
684 newColl->taggedRetain(OSTypeID(OSCollection));
685 newColl->release();
686 };
687 }
688
689 ret = newDict;
690 newDict = 0;
691
692 } while (false);
693
694 abortCopy:
695 if (newDict)
696 newDict->release();
697
698 if (allocDict)
699 cycleDict->release();
700
701 return ret;
702 }
703