]> git.saurik.com Git - apple/xnu.git/blame - libkern/c++/OSDictionary.cpp
xnu-3247.1.106.tar.gz
[apple/xnu.git] / libkern / c++ / OSDictionary.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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
42OSDefineMetaClassAndStructors(OSDictionary, OSCollection)
43OSMetaClassDefineReservedUnused(OSDictionary, 0);
44OSMetaClassDefineReservedUnused(OSDictionary, 1);
45OSMetaClassDefineReservedUnused(OSDictionary, 2);
46OSMetaClassDefineReservedUnused(OSDictionary, 3);
47OSMetaClassDefineReservedUnused(OSDictionary, 4);
48OSMetaClassDefineReservedUnused(OSDictionary, 5);
49OSMetaClassDefineReservedUnused(OSDictionary, 6);
50OSMetaClassDefineReservedUnused(OSDictionary, 7);
51
91447636
A
52#define EXT_CAST(obj) \
53 reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj))
54
1c79356b
A
55bool OSDictionary::initWithCapacity(unsigned int inCapacity)
56{
57 if (!super::init())
58 return false;
59
fe8ab488
A
60 if (inCapacity > (UINT_MAX / sizeof(dictEntry)))
61 return false;
1c79356b 62
fe8ab488 63 unsigned int size = inCapacity * sizeof(dictEntry);
316670eb
A
64//fOptions |= kSort;
65
3e170ce0 66 dictionary = (dictEntry *) kalloc_container(size);
1c79356b
A
67 if (!dictionary)
68 return false;
69
70 bzero(dictionary, size);
3e170ce0 71 OSCONTAINER_ACCUMSIZE(size);
1c79356b
A
72
73 count = 0;
74 capacity = inCapacity;
75 capacityIncrement = (inCapacity)? inCapacity : 16;
76
77 return true;
78}
79
80bool OSDictionary::initWithObjects(const OSObject *objects[],
81 const OSSymbol *keys[],
82 unsigned int theCount,
55e303ae 83 unsigned int theCapacity)
1c79356b 84{
b0d623f7 85 unsigned int newCapacity = theCount;
1c79356b
A
86
87 if (!objects || !keys)
88 return false;
89
90 if ( theCapacity ) {
91 if (theCount > theCapacity)
92 return false;
93
b0d623f7 94 newCapacity = theCapacity;
1c79356b
A
95 }
96
b0d623f7 97 if (!initWithCapacity(newCapacity))
1c79356b
A
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
110bool OSDictionary::initWithObjects(const OSObject *objects[],
111 const OSString *keys[],
112 unsigned int theCount,
55e303ae 113 unsigned int theCapacity)
1c79356b 114{
b0d623f7 115 unsigned int newCapacity = theCount;
1c79356b
A
116
117 if (!objects || !keys)
118 return false;
119
120 if ( theCapacity ) {
121 if (theCount > theCapacity)
122 return false;
123
b0d623f7 124 newCapacity = theCapacity;
1c79356b
A
125 }
126
b0d623f7 127 if (!initWithCapacity(newCapacity))
1c79356b
A
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
148bool OSDictionary::initWithDictionary(const OSDictionary *dict,
55e303ae 149 unsigned int theCapacity)
1c79356b 150{
b0d623f7 151 unsigned int newCapacity;
1c79356b
A
152
153 if ( !dict )
154 return false;
155
b0d623f7 156 newCapacity = dict->count;
1c79356b
A
157
158 if ( theCapacity ) {
159 if ( dict->count > theCapacity )
160 return false;
161
b0d623f7 162 newCapacity = theCapacity;
1c79356b
A
163 }
164
b0d623f7 165 if (!initWithCapacity(newCapacity))
1c79356b
A
166 return false;
167
316670eb
A
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
1c79356b
A
177 count = dict->count;
178 bcopy(dict->dictionary, dictionary, count * sizeof(dictEntry));
179 for (unsigned int i = 0; i < count; i++) {
9bccf70c
A
180 dictionary[i].key->taggedRetain(OSTypeID(OSCollection));
181 dictionary[i].value->taggedRetain(OSTypeID(OSCollection));
1c79356b
A
182 }
183
184 return true;
185}
186
187OSDictionary *OSDictionary::withCapacity(unsigned int capacity)
188{
189 OSDictionary *me = new OSDictionary;
190
191 if (me && !me->initWithCapacity(capacity)) {
55e303ae 192 me->release();
1c79356b
A
193 return 0;
194 }
195
196 return me;
197}
198
199OSDictionary *OSDictionary::withObjects(const OSObject *objects[],
200 const OSSymbol *keys[],
201 unsigned int count,
55e303ae 202 unsigned int capacity)
1c79356b
A
203{
204 OSDictionary *me = new OSDictionary;
205
206 if (me && !me->initWithObjects(objects, keys, count, capacity)) {
55e303ae 207 me->release();
1c79356b
A
208 return 0;
209 }
210
211 return me;
212}
213
214OSDictionary *OSDictionary::withObjects(const OSObject *objects[],
215 const OSString *keys[],
216 unsigned int count,
55e303ae 217 unsigned int capacity)
1c79356b
A
218{
219 OSDictionary *me = new OSDictionary;
220
221 if (me && !me->initWithObjects(objects, keys, count, capacity)) {
55e303ae 222 me->release();
1c79356b
A
223 return 0;
224 }
225
226 return me;
227}
228
229OSDictionary *OSDictionary::withDictionary(const OSDictionary *dict,
55e303ae 230 unsigned int capacity)
1c79356b
A
231{
232 OSDictionary *me = new OSDictionary;
233
234 if (me && !me->initWithDictionary(dict, capacity)) {
55e303ae 235 me->release();
1c79356b
A
236 return 0;
237 }
238
239 return me;
240}
241
242void OSDictionary::free()
243{
91447636 244 (void) super::setOptions(0, kImmutable);
1c79356b
A
245 flushCollection();
246 if (dictionary) {
0c530ab8 247 kfree(dictionary, capacity * sizeof(dictEntry));
3e170ce0 248 OSCONTAINER_ACCUMSIZE( -(capacity * sizeof(dictEntry)) );
1c79356b
A
249 }
250
251 super::free();
252}
253
254unsigned int OSDictionary::getCount() const { return count; }
255unsigned int OSDictionary::getCapacity() const { return capacity; }
256
257unsigned int OSDictionary::getCapacityIncrement() const
258{
259 return capacityIncrement;
260}
261
262unsigned int OSDictionary::setCapacityIncrement(unsigned int increment)
263{
264 capacityIncrement = (increment)? increment : 16;
265
266 return capacityIncrement;
267}
268
269unsigned int OSDictionary::ensureCapacity(unsigned int newCapacity)
270{
271 dictEntry *newDict;
fe8ab488 272 unsigned int finalCapacity, oldSize, newSize;
1c79356b
A
273
274 if (newCapacity <= capacity)
275 return capacity;
276
277 // round up
fe8ab488 278 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1)
1c79356b 279 * capacityIncrement;
fe8ab488
A
280
281 // integer overflow check
282 if (finalCapacity < newCapacity || (finalCapacity > (UINT_MAX / sizeof(dictEntry))))
283 return capacity;
284
285 newSize = sizeof(dictEntry) * finalCapacity;
1c79356b 286
3e170ce0 287 newDict = (dictEntry *) kalloc_container(newSize);
1c79356b
A
288 if (newDict) {
289 oldSize = sizeof(dictEntry) * capacity;
290
291 bcopy(dictionary, newDict, oldSize);
292 bzero(&newDict[capacity], newSize - oldSize);
293
3e170ce0 294 OSCONTAINER_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize));
0c530ab8 295 kfree(dictionary, oldSize);
1c79356b
A
296
297 dictionary = newDict;
fe8ab488 298 capacity = finalCapacity;
1c79356b
A
299 }
300
301 return capacity;
302}
303
304void OSDictionary::flushCollection()
305{
306 haveUpdated();
307
308 for (unsigned int i = 0; i < count; i++) {
9bccf70c
A
309 dictionary[i].key->taggedRelease(OSTypeID(OSCollection));
310 dictionary[i].value->taggedRelease(OSTypeID(OSCollection));
1c79356b
A
311 }
312 count = 0;
313}
314
315bool OSDictionary::
316setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject)
317{
316670eb
A
318 unsigned int i;
319 bool exists;
320
1c79356b
A
321 if (!anObject || !aKey)
322 return false;
323
324 // if the key exists, replace the object
91447636 325
316670eb
A
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 }
1c79356b 332
316670eb
A
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;
1c79356b
A
343 }
344
345 // add new key, possibly extending our capacity
346 if (count >= capacity && count >= ensureCapacity(count+1))
316670eb 347 return false;
1c79356b 348
91447636
A
349 haveUpdated();
350
316670eb
A
351 bcopy(&dictionary[i], &dictionary[i+1], (count - i) * sizeof(dictionary[0]));
352
9bccf70c
A
353 aKey->taggedRetain(OSTypeID(OSCollection));
354 anObject->taggedRetain(OSTypeID(OSCollection));
316670eb
A
355 dictionary[i].key = aKey;
356 dictionary[i].value = anObject;
1c79356b
A
357 count++;
358
1c79356b
A
359 return true;
360}
361
362void OSDictionary::removeObject(const OSSymbol *aKey)
363{
316670eb
A
364 unsigned int i;
365 bool exists;
366
1c79356b
A
367 if (!aKey)
368 return;
369
370 // if the key exists, remove the object
1c79356b 371
316670eb
A
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 }
1c79356b 378
316670eb
A
379 if (exists) {
380 dictEntry oldEntry = dictionary[i];
1c79356b 381
316670eb
A
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 }
1c79356b
A
391}
392
393
394// Returns true on success, false on an error condition.
9bccf70c 395bool OSDictionary::merge(const OSDictionary *srcDict)
1c79356b
A
396{
397 const OSSymbol * sym;
398 OSCollectionIterator * iter;
399
9bccf70c 400 if ( !OSDynamicCast(OSDictionary, srcDict) )
1c79356b 401 return false;
9bccf70c 402
b0d623f7 403 iter = OSCollectionIterator::withCollection(const_cast<OSDictionary *>(srcDict));
1c79356b
A
404 if ( !iter )
405 return false;
406
407 while ( (sym = (const OSSymbol *)iter->getNextObject()) ) {
408 const OSMetaClassBase * obj;
409
9bccf70c 410 obj = srcDict->getObject(sym);
1c79356b
A
411 if ( !setObject(sym, obj) ) {
412 iter->release();
413 return false;
414 }
415 }
416 iter->release();
417
418 return true;
419}
420
421OSObject *OSDictionary::getObject(const OSSymbol *aKey) const
422{
316670eb
A
423 unsigned int i;
424 bool exists;
425
1c79356b
A
426 if (!aKey)
427 return 0;
428
316670eb
A
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 }
1c79356b
A
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
472bool OSDictionary::setObject(const OSString *aKey, const OSMetaClassBase *anObject)
473 OBJECT_WRAP_2(setObject, OSSymbol::withString(aKey), anObject)
474bool OSDictionary::setObject(const char *aKey, const OSMetaClassBase *anObject)
475 OBJECT_WRAP_2(setObject, OSSymbol::withCString(aKey), anObject)
476
477OSObject *OSDictionary::getObject(const OSString *aKey) const
478 OBJECT_WRAP_1(getObject, OSSymbol::withString(aKey))
479OSObject *OSDictionary::getObject(const char *aKey) const
480 OBJECT_WRAP_1(getObject, OSSymbol::withCString(aKey))
481
482void OSDictionary::removeObject(const OSString *aKey)
483 OBJECT_WRAP_3(removeObject, OSSymbol::withString(aKey))
484void OSDictionary::removeObject(const char *aKey)
485 OBJECT_WRAP_3(removeObject, OSSymbol::withCString(aKey))
486
487bool
9bccf70c 488OSDictionary::isEqualTo(const OSDictionary *srcDict, const OSCollection *keys) const
1c79356b
A
489{
490 OSCollectionIterator * iter;
491 unsigned int keysCount;
492 const OSMetaClassBase * obj1;
493 const OSMetaClassBase * obj2;
494 OSString * aKey;
495 bool ret;
496
9bccf70c 497 if ( this == srcDict )
1c79356b
A
498 return true;
499
500 keysCount = keys->getCount();
9bccf70c 501 if ( (count < keysCount) || (srcDict->getCount() < keysCount) )
1c79356b
A
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);
9bccf70c 511 obj2 = srcDict->getObject(aKey);
1c79356b
A
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
9bccf70c 527bool OSDictionary::isEqualTo(const OSDictionary *srcDict) const
1c79356b
A
528{
529 unsigned int i;
530 const OSMetaClassBase * obj;
531
9bccf70c 532 if ( this == srcDict )
1c79356b
A
533 return true;
534
9bccf70c 535 if ( count != srcDict->getCount() )
1c79356b
A
536 return false;
537
538 for ( i = 0; i < count; i++ ) {
9bccf70c 539 obj = srcDict->getObject(dictionary[i].key);
1c79356b
A
540 if ( !obj )
541 return false;
542
543 if ( !dictionary[i].value->isEqualTo(obj) )
544 return false;
545 }
546
547 return true;
548}
549
550bool 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
561unsigned int OSDictionary::iteratorSize() const
562{
563 return sizeof(unsigned int);
564}
565
566bool OSDictionary::initIterator(void *inIterator) const
567{
568 unsigned int *iteratorP = (unsigned int *) inIterator;
569
570 *iteratorP = 0;
571 return true;
572}
573
574bool 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
587bool 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}
91447636
A
621
622unsigned 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
638OSCollection * 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
685abortCopy:
686 if (newDict)
687 newDict->release();
688
689 if (allocDict)
690 cycleDict->release();
691
692 return ret;
693}
694