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 /* IOArray.m created by rsulack on Fri 12-Sep-1997 */ 29 /* IOArray.cpp converted to C++ by gvdl on Fri 1998-10-30 */ 30 31 32 #include <libkern/c++/OSArray.h> 33 #include <libkern/c++/OSDictionary.h> 34 #include <libkern/c++/OSSerialize.h> 35 #include <libkern/c++/OSLib.h> 36 #include <libkern/OSDebug.h> 37 38 #define super OSCollection 39 40 OSDefineMetaClassAndStructors(OSArray, OSCollection) 41 OSMetaClassDefineReservedUnused(OSArray, 0); 42 OSMetaClassDefineReservedUnused(OSArray, 1); 43 OSMetaClassDefineReservedUnused(OSArray, 2); 44 OSMetaClassDefineReservedUnused(OSArray, 3); 45 OSMetaClassDefineReservedUnused(OSArray, 4); 46 OSMetaClassDefineReservedUnused(OSArray, 5); 47 OSMetaClassDefineReservedUnused(OSArray, 6); 48 OSMetaClassDefineReservedUnused(OSArray, 7); 49 50 51 #define EXT_CAST(obj) \ 52 reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj)) 53 54 bool OSArray::initWithCapacity(unsigned int inCapacity) 55 { 56 unsigned int size; 57 58 if (!super::init()) 59 return false; 60 61 // integer overflow check 62 if (inCapacity > (UINT_MAX / sizeof(const OSMetaClassBase*))) 63 return false; 64 65 size = sizeof(const OSMetaClassBase *) * inCapacity; 66 array = (const OSMetaClassBase **) kalloc_container(size); 67 if (!array) 68 return false; 69 70 count = 0; 71 capacity = inCapacity; 72 capacityIncrement = (inCapacity)? inCapacity : 16; 73 74 bzero(array, size); 75 OSCONTAINER_ACCUMSIZE(size); 76 77 return true; 78 } 79 80 bool OSArray::initWithObjects(const OSObject *objects[], 81 unsigned int theCount, 82 unsigned int theCapacity) 83 { 84 unsigned int initCapacity; 85 86 if (!theCapacity) 87 initCapacity = theCount; 88 else if (theCount > theCapacity) 89 return false; 90 else 91 initCapacity = theCapacity; 92 93 if (!objects || !initWithCapacity(initCapacity)) 94 return false; 95 96 for ( unsigned int i = 0; i < theCount; i++ ) { 97 const OSMetaClassBase *newObject = *objects++; 98 99 if (!newObject) 100 return false; 101 102 array[count++] = newObject; 103 newObject->taggedRetain(OSTypeID(OSCollection)); 104 } 105 106 return true; 107 } 108 109 bool OSArray::initWithArray(const OSArray *anArray, 110 unsigned int theCapacity) 111 { 112 if ( !anArray ) 113 return false; 114 115 return initWithObjects((const OSObject **) anArray->array, 116 anArray->count, theCapacity); 117 } 118 119 OSArray *OSArray::withCapacity(unsigned int capacity) 120 { 121 OSArray *me = new OSArray; 122 123 if (me && !me->initWithCapacity(capacity)) { 124 me->release(); 125 return 0; 126 } 127 128 return me; 129 } 130 131 OSArray *OSArray::withObjects(const OSObject *objects[], 132 unsigned int count, 133 unsigned int capacity) 134 { 135 OSArray *me = new OSArray; 136 137 if (me && !me->initWithObjects(objects, count, capacity)) { 138 me->release(); 139 return 0; 140 } 141 142 return me; 143 } 144 145 OSArray *OSArray::withArray(const OSArray *array, 146 unsigned int capacity) 147 { 148 OSArray *me = new OSArray; 149 150 if (me && !me->initWithArray(array, capacity)) { 151 me->release(); 152 return 0; 153 } 154 155 return me; 156 } 157 158 void OSArray::free() 159 { 160 // Clear immutability - assumes the container is doing the right thing 161 (void) super::setOptions(0, kImmutable); 162 163 flushCollection(); 164 165 if (array) { 166 kfree(array, sizeof(const OSMetaClassBase *) * capacity); 167 OSCONTAINER_ACCUMSIZE( -(sizeof(const OSMetaClassBase *) * capacity) ); 168 } 169 170 super::free(); 171 } 172 173 174 unsigned int OSArray::getCount() const { return count; } 175 unsigned int OSArray::getCapacity() const { return capacity; } 176 unsigned int OSArray::getCapacityIncrement() const { return capacityIncrement; } 177 unsigned int OSArray::setCapacityIncrement(unsigned int increment) 178 { 179 capacityIncrement = (increment)? increment : 16; 180 181 return capacityIncrement; 182 } 183 184 unsigned int OSArray::ensureCapacity(unsigned int newCapacity) 185 { 186 const OSMetaClassBase **newArray; 187 unsigned int finalCapacity; 188 unsigned int oldSize, newSize; 189 190 if (newCapacity <= capacity) 191 return capacity; 192 193 // round up 194 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1) 195 * capacityIncrement; 196 197 // integer overflow check 198 if ((finalCapacity < newCapacity) || (finalCapacity > (UINT_MAX / sizeof(const OSMetaClassBase*)))) 199 return capacity; 200 201 newSize = sizeof(const OSMetaClassBase *) * finalCapacity; 202 203 newArray = (const OSMetaClassBase **) kalloc_container(newSize); 204 if (newArray) { 205 oldSize = sizeof(const OSMetaClassBase *) * capacity; 206 207 OSCONTAINER_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize)); 208 209 bcopy(array, newArray, oldSize); 210 bzero(&newArray[capacity], newSize - oldSize); 211 kfree(array, oldSize); 212 array = newArray; 213 capacity = finalCapacity; 214 } 215 216 return capacity; 217 } 218 219 void OSArray::flushCollection() 220 { 221 unsigned int i; 222 223 haveUpdated(); 224 for (i = 0; i < count; i++) { 225 array[i]->taggedRelease(OSTypeID(OSCollection)); 226 } 227 count = 0; 228 } 229 230 bool OSArray::setObject(const OSMetaClassBase *anObject) 231 { 232 return setObject(count, anObject); 233 } 234 235 bool OSArray::setObject(unsigned int index, const OSMetaClassBase *anObject) 236 { 237 unsigned int i; 238 unsigned int newCount = count + 1; 239 240 if ((index > count) || !anObject) 241 return false; 242 243 // do we need more space? 244 if (newCount > capacity && newCount > ensureCapacity(newCount)) 245 return false; 246 247 haveUpdated(); 248 if (index != count) { 249 for (i = count; i > index; i--) 250 array[i] = array[i-1]; 251 } 252 array[index] = anObject; 253 anObject->taggedRetain(OSTypeID(OSCollection)); 254 count++; 255 256 return true; 257 } 258 259 bool OSArray::merge(const OSArray * otherArray) 260 { 261 unsigned int otherCount = otherArray->getCount(); 262 unsigned int newCount = count + otherCount; 263 264 if (!otherCount) 265 return true; 266 267 // do we need more space? 268 if (newCount > capacity && newCount > ensureCapacity(newCount)) 269 return false; 270 271 haveUpdated(); 272 for (unsigned int i = 0; i < otherCount; i++) { 273 const OSMetaClassBase *newObject = otherArray->getObject(i); 274 275 array[count++] = newObject; 276 newObject->taggedRetain(OSTypeID(OSCollection)); 277 } 278 279 return true; 280 } 281 282 void OSArray:: 283 replaceObject(unsigned int index, const OSMetaClassBase *anObject) 284 { 285 const OSMetaClassBase *oldObject; 286 287 if ((index >= count) || !anObject) 288 return; 289 290 haveUpdated(); 291 oldObject = array[index]; 292 array[index] = anObject; 293 anObject->taggedRetain(OSTypeID(OSCollection)); 294 295 oldObject->taggedRelease(OSTypeID(OSCollection)); 296 } 297 298 void OSArray::removeObject(unsigned int index) 299 { 300 unsigned int i; 301 const OSMetaClassBase *oldObject; 302 303 if (index >= count) 304 return; 305 306 haveUpdated(); 307 oldObject = array[index]; 308 309 count--; 310 for (i = index; i < count; i++) 311 array[i] = array[i+1]; 312 313 oldObject->taggedRelease(OSTypeID(OSCollection)); 314 } 315 316 bool OSArray::isEqualTo(const OSArray *anArray) const 317 { 318 unsigned int i; 319 320 if ( this == anArray ) 321 return true; 322 323 if ( count != anArray->getCount() ) 324 return false; 325 326 for ( i = 0; i < count; i++ ) { 327 if ( !array[i]->isEqualTo(anArray->getObject(i)) ) 328 return false; 329 } 330 331 return true; 332 } 333 334 bool OSArray::isEqualTo(const OSMetaClassBase *anObject) const 335 { 336 OSArray *otherArray; 337 338 otherArray = OSDynamicCast(OSArray, anObject); 339 if ( otherArray ) 340 return isEqualTo(otherArray); 341 else 342 return false; 343 } 344 345 OSObject *OSArray::getObject(unsigned int index) const 346 { 347 if (index >= count) 348 return 0; 349 else 350 return (OSObject *) (const_cast<OSMetaClassBase *>(array[index])); 351 } 352 353 OSObject *OSArray::getLastObject() const 354 { 355 if (count == 0) 356 return 0; 357 else 358 return ( OSObject *) (const_cast<OSMetaClassBase *>(array[count - 1])); 359 } 360 361 unsigned int OSArray::getNextIndexOfObject(const OSMetaClassBase * anObject, 362 unsigned int index) const 363 { 364 while ((index < count) && (array[index] != anObject)) 365 index++; 366 if (index >= count) 367 index = (unsigned int)-1; 368 return index; 369 } 370 371 unsigned int OSArray::iteratorSize() const 372 { 373 return sizeof(unsigned int); 374 } 375 376 bool OSArray::initIterator(void *inIterator) const 377 { 378 unsigned int *iteratorP = (unsigned int *) inIterator; 379 380 *iteratorP = 0; 381 return true; 382 } 383 384 bool OSArray::getNextObjectForIterator(void *inIterator, OSObject **ret) const 385 { 386 unsigned int *iteratorP = (unsigned int *) inIterator; 387 unsigned int index = (*iteratorP)++; 388 389 if (index < count) { 390 *ret = (OSObject *)(const_cast<OSMetaClassBase *> (array[index])); 391 return true; 392 } 393 else { 394 *ret = 0; 395 return false; 396 } 397 } 398 399 bool OSArray::serialize(OSSerialize *s) const 400 { 401 if (s->previouslySerialized(this)) return true; 402 403 if (!s->addXMLStartTag(this, "array")) return false; 404 405 for (unsigned i = 0; i < count; i++) { 406 if (array[i] == NULL || !array[i]->serialize(s)) return false; 407 } 408 409 return s->addXMLEndTag("array"); 410 } 411 412 unsigned OSArray::setOptions(unsigned options, unsigned mask, void *) 413 { 414 unsigned old = super::setOptions(options, mask); 415 if ((old ^ options) & mask) { 416 417 // Value changed need to recurse over all of the child collections 418 for ( unsigned i = 0; i < count; i++ ) { 419 OSCollection *coll = OSDynamicCast(OSCollection, array[i]); 420 if (coll) 421 coll->setOptions(options, mask); 422 } 423 } 424 425 return old; 426 } 427 428 OSCollection * OSArray::copyCollection(OSDictionary *cycleDict) 429 { 430 bool allocDict = !cycleDict; 431 OSCollection *ret = 0; 432 OSArray *newArray = 0; 433 434 if (allocDict) { 435 cycleDict = OSDictionary::withCapacity(16); 436 if (!cycleDict) 437 return 0; 438 } 439 440 do { 441 // Check for a cycle 442 ret = super::copyCollection(cycleDict); 443 if (ret) 444 continue; 445 446 newArray = OSArray::withArray(this); 447 if (!newArray) 448 continue; 449 450 // Insert object into cycle Dictionary 451 cycleDict->setObject((const OSSymbol *) this, newArray); 452 453 for (unsigned int i = 0; i < count; i++) { 454 OSCollection *coll = 455 OSDynamicCast(OSCollection, EXT_CAST(newArray->array[i])); 456 457 if (coll) { 458 OSCollection *newColl = coll->copyCollection(cycleDict); 459 if (!newColl) 460 goto abortCopy; 461 462 newArray->replaceObject(i, newColl); 463 newColl->release(); 464 }; 465 }; 466 467 ret = newArray; 468 newArray = 0; 469 470 } while (false); 471 472 abortCopy: 473 if (newArray) 474 newArray->release(); 475 476 if (allocDict) 477 cycleDict->release(); 478 479 return ret; 480 } 481 482