xref: /xnu-11215/libkern/c++/OSDictionary.cpp (revision 8dd02465)
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)
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 	const OSMetaClassBase *oldObject = dictionary[i].value;
335 
336 	haveUpdated();
337 
338 	anObject->taggedRetain(OSTypeID(OSCollection));
339 	dictionary[i].value = anObject;
340 
341 	oldObject->taggedRelease(OSTypeID(OSCollection));
342 	return true;
343     }
344 
345     // add new key, possibly extending our capacity
346     if (count >= capacity && count >= ensureCapacity(count+1))
347         return false;
348 
349     haveUpdated();
350 
351     bcopy(&dictionary[i], &dictionary[i+1], (count - i) * sizeof(dictionary[0]));
352 
353     aKey->taggedRetain(OSTypeID(OSCollection));
354     anObject->taggedRetain(OSTypeID(OSCollection));
355     dictionary[i].key = aKey;
356     dictionary[i].value = anObject;
357     count++;
358 
359     return true;
360 }
361 
362 void OSDictionary::removeObject(const OSSymbol *aKey)
363 {
364     unsigned int i;
365     bool exists;
366 
367     if (!aKey)
368         return;
369 
370     // if the key exists, remove the object
371 
372     if (fOptions & kSort) {
373     	i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
374 	exists = (i < count) && (aKey == dictionary[i].key);
375     } else for (exists = false, i = 0; i < count; i++) {
376         if ((exists = (aKey == dictionary[i].key))) break;
377     }
378 
379     if (exists) {
380 	dictEntry oldEntry = dictionary[i];
381 
382 	haveUpdated();
383 
384 	count--;
385 	bcopy(&dictionary[i+1], &dictionary[i], (count - i) * sizeof(dictionary[0]));
386 
387 	oldEntry.key->taggedRelease(OSTypeID(OSCollection));
388 	oldEntry.value->taggedRelease(OSTypeID(OSCollection));
389 	return;
390     }
391 }
392 
393 
394 // Returns true on success, false on an error condition.
395 bool OSDictionary::merge(const OSDictionary *srcDict)
396 {
397     const OSSymbol * sym;
398     OSCollectionIterator * iter;
399 
400     if ( !OSDynamicCast(OSDictionary, srcDict) )
401         return false;
402 
403     iter = OSCollectionIterator::withCollection(const_cast<OSDictionary *>(srcDict));
404     if ( !iter )
405         return false;
406 
407     while ( (sym = (const OSSymbol *)iter->getNextObject()) ) {
408         const OSMetaClassBase * obj;
409 
410         obj = srcDict->getObject(sym);
411         if ( !setObject(sym, obj) ) {
412             iter->release();
413             return false;
414         }
415     }
416     iter->release();
417 
418     return true;
419 }
420 
421 OSObject *OSDictionary::getObject(const OSSymbol *aKey) const
422 {
423     unsigned int i;
424     bool exists;
425 
426     if (!aKey)
427         return 0;
428 
429     // if the key exists, return the object
430 
431     if (fOptions & kSort) {
432     	i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
433 	exists = (i < count) && (aKey == dictionary[i].key);
434     } else for (exists = false, i = 0; i < count; i++) {
435         if ((exists = (aKey == dictionary[i].key))) break;
436     }
437 
438     if (exists) {
439 	return (const_cast<OSObject *> ((const OSObject *)dictionary[i].value));
440     }
441 
442     return 0;
443 }
444 
445 // Wrapper macros
446 #define OBJECT_WRAP_1(cmd, k)						\
447 {									\
448     const OSSymbol *tmpKey = k;						\
449     OSObject *retObj = cmd(tmpKey);					\
450 									\
451     tmpKey->release();							\
452     return retObj;							\
453 }
454 
455 #define OBJECT_WRAP_2(cmd, k, o)					\
456 {									\
457     const OSSymbol *tmpKey = k;						\
458     bool ret = cmd(tmpKey, o);						\
459 									\
460     tmpKey->release();							\
461     return ret;								\
462 }
463 
464 #define OBJECT_WRAP_3(cmd, k)						\
465 {									\
466     const OSSymbol *tmpKey = k;						\
467     cmd(tmpKey);							\
468     tmpKey->release();							\
469 }
470 
471 
472 bool OSDictionary::setObject(const OSString *aKey, const OSMetaClassBase *anObject)
473     OBJECT_WRAP_2(setObject, OSSymbol::withString(aKey), anObject)
474 bool OSDictionary::setObject(const char *aKey, const OSMetaClassBase *anObject)
475     OBJECT_WRAP_2(setObject, OSSymbol::withCString(aKey), anObject)
476 
477 OSObject *OSDictionary::getObject(const OSString *aKey) const
478     OBJECT_WRAP_1(getObject, OSSymbol::withString(aKey))
479 OSObject *OSDictionary::getObject(const char *aKey) const
480     OBJECT_WRAP_1(getObject, OSSymbol::withCString(aKey))
481 
482 void OSDictionary::removeObject(const OSString *aKey)
483     OBJECT_WRAP_3(removeObject, OSSymbol::withString(aKey))
484 void OSDictionary::removeObject(const char *aKey)
485     OBJECT_WRAP_3(removeObject, OSSymbol::withCString(aKey))
486 
487 bool
488 OSDictionary::isEqualTo(const OSDictionary *srcDict, const OSCollection *keys) const
489 {
490     OSCollectionIterator * iter;
491     unsigned int keysCount;
492     const OSMetaClassBase * obj1;
493     const OSMetaClassBase * obj2;
494     OSString * aKey;
495     bool ret;
496 
497     if ( this == srcDict )
498         return true;
499 
500     keysCount = keys->getCount();
501     if ( (count < keysCount) || (srcDict->getCount() < keysCount) )
502         return false;
503 
504     iter = OSCollectionIterator::withCollection(keys);
505     if ( !iter )
506         return false;
507 
508     ret = true;
509     while ( (aKey = OSDynamicCast(OSString, iter->getNextObject())) ) {
510         obj1 = getObject(aKey);
511         obj2 = srcDict->getObject(aKey);
512         if ( !obj1 || !obj2 ) {
513             ret = false;
514             break;
515         }
516 
517         if ( !obj1->isEqualTo(obj2) ) {
518             ret = false;
519             break;
520         }
521     }
522     iter->release();
523 
524     return ret;
525 }
526 
527 bool OSDictionary::isEqualTo(const OSDictionary *srcDict) const
528 {
529     unsigned int i;
530     const OSMetaClassBase * obj;
531 
532     if ( this == srcDict )
533         return true;
534 
535     if ( count != srcDict->getCount() )
536         return false;
537 
538     for ( i = 0; i < count; i++ ) {
539         obj = srcDict->getObject(dictionary[i].key);
540         if ( !obj )
541             return false;
542 
543         if ( !dictionary[i].value->isEqualTo(obj) )
544             return false;
545     }
546 
547     return true;
548 }
549 
550 bool OSDictionary::isEqualTo(const OSMetaClassBase *anObject) const
551 {
552     OSDictionary *dict;
553 
554     dict = OSDynamicCast(OSDictionary, anObject);
555     if ( dict )
556         return isEqualTo(dict);
557     else
558         return false;
559 }
560 
561 unsigned int OSDictionary::iteratorSize() const
562 {
563     return sizeof(unsigned int);
564 }
565 
566 bool OSDictionary::initIterator(void *inIterator) const
567 {
568     unsigned int *iteratorP = (unsigned int *) inIterator;
569 
570     *iteratorP = 0;
571     return true;
572 }
573 
574 bool OSDictionary::getNextObjectForIterator(void *inIterator, OSObject **ret) const
575 {
576     unsigned int *iteratorP = (unsigned int *) inIterator;
577     unsigned int index = (*iteratorP)++;
578 
579     if (index < count)
580         *ret = (OSObject *) dictionary[index].key;
581     else
582         *ret = 0;
583 
584     return (*ret != 0);
585 }
586 
587 bool OSDictionary::serialize(OSSerialize *s) const
588 {
589     if (s->previouslySerialized(this)) return true;
590 
591     if (!s->addXMLStartTag(this, "dict")) return false;
592 
593     for (unsigned i = 0; i < count; i++) {
594         const OSSymbol *key = dictionary[i].key;
595 
596         // due the nature of the XML syntax, this must be a symbol
597         if (!key->metaCast("OSSymbol")) {
598             return false;
599         }
600         if (!s->addString("<key>")) return false;
601         const char *c = key->getCStringNoCopy();
602 	while (*c) {
603 	    if (*c == '<') {
604 		if (!s->addString("&lt;")) return false;
605 	    } else if (*c == '>') {
606 		if (!s->addString("&gt;")) return false;
607 	    } else if (*c == '&') {
608 		if (!s->addString("&amp;")) return false;
609 	    } else {
610 		if (!s->addChar(*c)) return false;
611 	    }
612 	    c++;
613 	}
614         if (!s->addXMLEndTag("key")) return false;
615 
616         if (!dictionary[i].value->serialize(s)) return false;
617     }
618 
619     return s->addXMLEndTag("dict");
620 }
621 
622 unsigned OSDictionary::setOptions(unsigned options, unsigned mask, void *)
623 {
624     unsigned old = super::setOptions(options, mask);
625     if ((old ^ options) & mask) {
626 
627 	// Value changed need to recurse over all of the child collections
628 	for ( unsigned i = 0; i < count; i++ ) {
629 	    OSCollection *v = OSDynamicCast(OSCollection, dictionary[i].value);
630 	    if (v)
631 		v->setOptions(options, mask);
632 	}
633     }
634 
635     return old;
636 }
637 
638 OSCollection * OSDictionary::copyCollection(OSDictionary *cycleDict)
639 {
640     bool allocDict = !cycleDict;
641     OSCollection *ret = 0;
642     OSDictionary *newDict = 0;
643 
644     if (allocDict) {
645 	cycleDict = OSDictionary::withCapacity(16);
646 	if (!cycleDict)
647 	    return 0;
648     }
649 
650     do {
651 	// Check for a cycle
652 	ret = super::copyCollection(cycleDict);
653 	if (ret)
654 	    continue;
655 
656 	newDict = OSDictionary::withDictionary(this);
657 	if (!newDict)
658 	    continue;
659 
660 	// Insert object into cycle Dictionary
661 	cycleDict->setObject((const OSSymbol *) this, newDict);
662 
663 	for (unsigned int i = 0; i < count; i++) {
664 	    const OSMetaClassBase *obj = dictionary[i].value;
665 	    OSCollection *coll = OSDynamicCast(OSCollection, EXT_CAST(obj));
666 
667 	    if (coll) {
668 		OSCollection *newColl = coll->copyCollection(cycleDict);
669 		if (!newColl)
670 		    goto abortCopy;
671 
672 		newDict->dictionary[i].value = newColl;
673 
674 		coll->taggedRelease(OSTypeID(OSCollection));
675 		newColl->taggedRetain(OSTypeID(OSCollection));
676 		newColl->release();
677 	    };
678 	}
679 
680 	ret = newDict;
681 	newDict = 0;
682 
683     } while (false);
684 
685 abortCopy:
686     if (newDict)
687 	newDict->release();
688 
689     if (allocDict)
690 	cycleDict->release();
691 
692     return ret;
693 }
694 
695