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 /* IOData.m created by rsulack on Thu 25-Sep-1997 */ 29 30 #include <string.h> 31 32 #include <vm/vm_kern.h> 33 34 #define IOKIT_ENABLE_SHARED_PTR 35 36 #include <libkern/c++/OSData.h> 37 #include <libkern/c++/OSSerialize.h> 38 #include <libkern/c++/OSLib.h> 39 #include <libkern/c++/OSString.h> 40 #include <IOKit/IOLib.h> 41 42 #define super OSObject 43 44 OSDefineMetaClassAndStructorsWithZone(OSData, OSObject, ZC_ZFREE_CLEARMEM) 45 OSMetaClassDefineReservedUsedX86(OSData, 0); // setDeallocFunction 46 OSMetaClassDefineReservedUnused(OSData, 1); 47 OSMetaClassDefineReservedUnused(OSData, 2); 48 OSMetaClassDefineReservedUnused(OSData, 3); 49 OSMetaClassDefineReservedUnused(OSData, 4); 50 OSMetaClassDefineReservedUnused(OSData, 5); 51 OSMetaClassDefineReservedUnused(OSData, 6); 52 OSMetaClassDefineReservedUnused(OSData, 7); 53 54 #define EXTERNAL ((unsigned int) -1) 55 56 static SECURITY_READ_ONLY_LATE(vm_map_t) alloc_map; 57 __startup_func 58 static void 59 getAllocMap(void) 60 { 61 alloc_map = KHEAP_DATA_BUFFERS->kh_fallback_map; 62 } 63 STARTUP(ZALLOC, STARTUP_RANK_LAST, getAllocMap); 64 65 bool 66 OSData::initWithCapacity(unsigned int inCapacity) 67 { 68 void *_data = NULL; 69 70 if (data) { 71 OSCONTAINER_ACCUMSIZE(-((size_t)capacity)); 72 if (!inCapacity || (capacity < inCapacity)) { 73 // clean out old data's storage if it isn't big enough 74 if (capacity < page_size) { 75 kfree_data_container(data, capacity); 76 } else { 77 kmem_free(alloc_map, (vm_offset_t)data, capacity); 78 } 79 data = NULL; 80 capacity = 0; 81 } 82 } 83 84 if (!super::init()) { 85 return false; 86 } 87 88 if (inCapacity && !data) { 89 if (inCapacity < page_size) { 90 data = (void *)kalloc_data_container(inCapacity, Z_WAITOK); 91 } else { 92 kern_return_t kr; 93 if (round_page_overflow(inCapacity, &inCapacity)) { 94 kr = KERN_RESOURCE_SHORTAGE; 95 } else { 96 kr = kmem_alloc_flags(alloc_map, (vm_offset_t *)&_data, inCapacity, 97 IOMemoryTag(alloc_map), KMA_ATOMIC); 98 data = _data; 99 } 100 if (KERN_SUCCESS != kr) { 101 data = NULL; 102 } 103 } 104 if (!data) { 105 return false; 106 } 107 capacity = inCapacity; 108 } 109 OSCONTAINER_ACCUMSIZE(capacity); 110 111 length = 0; 112 if (inCapacity < 16) { 113 capacityIncrement = 16; 114 } else { 115 capacityIncrement = inCapacity; 116 } 117 118 return true; 119 } 120 121 bool 122 OSData::initWithBytes(const void *bytes, unsigned int inLength) 123 { 124 if ((inLength && !bytes) || !initWithCapacity(inLength)) { 125 return false; 126 } 127 128 if (bytes != data) { 129 bcopy(bytes, data, inLength); 130 } 131 length = inLength; 132 133 return true; 134 } 135 136 bool 137 OSData::initWithBytesNoCopy(void *bytes, unsigned int inLength) 138 { 139 if (!super::init()) { 140 return false; 141 } 142 143 length = inLength; 144 capacity = EXTERNAL; 145 data = bytes; 146 147 return true; 148 } 149 150 bool 151 OSData::initWithData(const OSData *inData) 152 { 153 return initWithBytes(inData->data, inData->length); 154 } 155 156 bool 157 OSData::initWithData(const OSData *inData, 158 unsigned int start, unsigned int inLength) 159 { 160 const void *localData = inData->getBytesNoCopy(start, inLength); 161 162 if (localData) { 163 return initWithBytes(localData, inLength); 164 } else { 165 return false; 166 } 167 } 168 169 OSSharedPtr<OSData> 170 OSData::withCapacity(unsigned int inCapacity) 171 { 172 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 173 174 if (me && !me->initWithCapacity(inCapacity)) { 175 return nullptr; 176 } 177 178 return me; 179 } 180 181 OSSharedPtr<OSData> 182 OSData::withBytes(const void *bytes, unsigned int inLength) 183 { 184 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 185 186 if (me && !me->initWithBytes(bytes, inLength)) { 187 return nullptr; 188 } 189 return me; 190 } 191 192 OSSharedPtr<OSData> 193 OSData::withBytesNoCopy(void *bytes, unsigned int inLength) 194 { 195 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 196 197 if (me && !me->initWithBytesNoCopy(bytes, inLength)) { 198 return nullptr; 199 } 200 201 return me; 202 } 203 204 OSSharedPtr<OSData> 205 OSData::withData(const OSData *inData) 206 { 207 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 208 209 if (me && !me->initWithData(inData)) { 210 return nullptr; 211 } 212 213 return me; 214 } 215 216 OSSharedPtr<OSData> 217 OSData::withData(const OSData *inData, 218 unsigned int start, unsigned int inLength) 219 { 220 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 221 222 if (me && !me->initWithData(inData, start, inLength)) { 223 return nullptr; 224 } 225 226 return me; 227 } 228 229 void 230 OSData::free() 231 { 232 if ((capacity != EXTERNAL) && data && capacity) { 233 if (capacity < page_size) { 234 kfree_data_container(data, capacity); 235 } else { 236 kmem_free(alloc_map, (vm_offset_t)data, capacity); 237 } 238 OSCONTAINER_ACCUMSIZE( -((size_t)capacity)); 239 } else if (capacity == EXTERNAL) { 240 DeallocFunction freemem = reserved ? reserved->deallocFunction : NULL; 241 if (freemem && data && length) { 242 freemem(data, length); 243 } 244 } 245 if (reserved) { 246 kfree_type(ExpansionData, reserved); 247 } 248 super::free(); 249 } 250 251 unsigned int 252 OSData::getLength() const 253 { 254 return length; 255 } 256 unsigned int 257 OSData::getCapacity() const 258 { 259 return capacity; 260 } 261 262 unsigned int 263 OSData::getCapacityIncrement() const 264 { 265 return capacityIncrement; 266 } 267 268 unsigned int 269 OSData::setCapacityIncrement(unsigned increment) 270 { 271 return capacityIncrement = increment; 272 } 273 274 // xx-review: does not check for capacity == EXTERNAL 275 276 unsigned int 277 OSData::ensureCapacity(unsigned int newCapacity) 278 { 279 unsigned char * newData; 280 unsigned int finalCapacity; 281 void * copydata; 282 kern_return_t kr; 283 284 if (newCapacity <= capacity) { 285 return capacity; 286 } 287 288 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1) 289 * capacityIncrement; 290 291 // integer overflow check 292 if (finalCapacity < newCapacity) { 293 return capacity; 294 } 295 296 copydata = data; 297 298 if (finalCapacity >= page_size) { 299 // round up 300 finalCapacity = round_page_32(finalCapacity); 301 // integer overflow check 302 if (finalCapacity < newCapacity) { 303 return capacity; 304 } 305 if (capacity >= page_size) { 306 copydata = NULL; 307 kr = kmem_realloc(alloc_map, 308 (vm_offset_t)data, 309 capacity, 310 (vm_offset_t *)&newData, 311 finalCapacity, 312 IOMemoryTag(alloc_map)); 313 } else { 314 kr = kmem_alloc_flags(alloc_map, (vm_offset_t *)&newData, 315 finalCapacity, IOMemoryTag(alloc_map), KMA_ATOMIC); 316 } 317 if (KERN_SUCCESS != kr) { 318 newData = NULL; 319 } 320 } else { 321 newData = (unsigned char *)kalloc_data_container(finalCapacity, Z_WAITOK); 322 } 323 324 if (newData) { 325 bzero(newData + capacity, finalCapacity - capacity); 326 if (copydata) { 327 bcopy(copydata, newData, capacity); 328 } 329 if (data) { 330 if (capacity < page_size) { 331 kfree_data_container(data, capacity); 332 } else { 333 kmem_free(alloc_map, (vm_offset_t)data, capacity); 334 } 335 } 336 OSCONTAINER_ACCUMSIZE(((size_t)finalCapacity) - ((size_t)capacity)); 337 data = (void *) newData; 338 capacity = finalCapacity; 339 } 340 341 return capacity; 342 } 343 344 bool 345 OSData::appendBytes(const void *bytes, unsigned int inLength) 346 { 347 unsigned int newSize; 348 349 if (!inLength) { 350 return true; 351 } 352 353 if (capacity == EXTERNAL) { 354 return false; 355 } 356 357 if (os_add_overflow(length, inLength, &newSize)) { 358 return false; 359 } 360 361 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) { 362 return false; 363 } 364 365 if (bytes) { 366 bcopy(bytes, &((unsigned char *)data)[length], inLength); 367 } else { 368 bzero(&((unsigned char *)data)[length], inLength); 369 } 370 371 length = newSize; 372 373 return true; 374 } 375 376 bool 377 OSData::appendByte(unsigned char byte, unsigned int inLength) 378 { 379 unsigned int newSize; 380 381 if (!inLength) { 382 return true; 383 } 384 385 if (capacity == EXTERNAL) { 386 return false; 387 } 388 389 if (os_add_overflow(length, inLength, &newSize)) { 390 return false; 391 } 392 393 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) { 394 return false; 395 } 396 397 memset(&((unsigned char *)data)[length], byte, inLength); 398 length = newSize; 399 400 return true; 401 } 402 403 bool 404 OSData::appendBytes(const OSData *other) 405 { 406 return appendBytes(other->data, other->length); 407 } 408 409 const void * 410 OSData::getBytesNoCopy() const 411 { 412 if (!length) { 413 return NULL; 414 } else { 415 return data; 416 } 417 } 418 419 const void * 420 OSData::getBytesNoCopy(unsigned int start, 421 unsigned int inLength) const 422 { 423 const void *outData = NULL; 424 425 if (length 426 && start < length 427 && (start + inLength) >= inLength // overflow check 428 && (start + inLength) <= length) { 429 outData = (const void *) ((char *) data + start); 430 } 431 432 return outData; 433 } 434 435 bool 436 OSData::isEqualTo(const OSData *aData) const 437 { 438 unsigned int len; 439 440 len = aData->length; 441 if (length != len) { 442 return false; 443 } 444 445 return isEqualTo(aData->data, len); 446 } 447 448 bool 449 OSData::isEqualTo(const void *someData, unsigned int inLength) const 450 { 451 return (length >= inLength) && (bcmp(data, someData, inLength) == 0); 452 } 453 454 bool 455 OSData::isEqualTo(const OSMetaClassBase *obj) const 456 { 457 OSData * otherData; 458 OSString * str; 459 460 if ((otherData = OSDynamicCast(OSData, obj))) { 461 return isEqualTo(otherData); 462 } else if ((str = OSDynamicCast(OSString, obj))) { 463 return isEqualTo(str); 464 } else { 465 return false; 466 } 467 } 468 469 bool 470 OSData::isEqualTo(const OSString *obj) const 471 { 472 const char * aCString; 473 char * dataPtr; 474 unsigned int checkLen = length; 475 unsigned int stringLen; 476 477 if (!obj) { 478 return false; 479 } 480 481 stringLen = obj->getLength(); 482 483 dataPtr = (char *)data; 484 485 if (stringLen != checkLen) { 486 // check for the fact that OSData may be a buffer that 487 // that includes a termination byte and will thus have 488 // a length of the actual string length PLUS 1. In this 489 // case we verify that the additional byte is a terminator 490 // and if so count the two lengths as being the same. 491 492 if ((checkLen - stringLen) == 1) { 493 if (dataPtr[checkLen - 1] != 0) { // non-zero means not a terminator and thus not likely the same 494 return false; 495 } 496 checkLen--; 497 } else { 498 return false; 499 } 500 } 501 502 aCString = obj->getCStringNoCopy(); 503 504 for (unsigned int i = 0; i < checkLen; i++) { 505 if (*dataPtr++ != aCString[i]) { 506 return false; 507 } 508 } 509 510 return true; 511 } 512 513 //this was taken from CFPropertyList.c 514 static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 515 516 bool 517 OSData::serialize(OSSerialize *s) const 518 { 519 unsigned int i; 520 const unsigned char *p; 521 unsigned char c; 522 unsigned int serializeLength; 523 524 if (s->previouslySerialized(this)) { 525 return true; 526 } 527 528 if (!s->addXMLStartTag(this, "data")) { 529 return false; 530 } 531 532 serializeLength = length; 533 if (reserved && reserved->disableSerialization) { 534 serializeLength = 0; 535 } 536 537 for (i = 0, p = (unsigned char *)data; i < serializeLength; i++, p++) { 538 /* 3 bytes are encoded as 4 */ 539 switch (i % 3) { 540 case 0: 541 c = __CFPLDataEncodeTable[((p[0] >> 2) & 0x3f)]; 542 if (!s->addChar(c)) { 543 return false; 544 } 545 break; 546 case 1: 547 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 4) & 0x3f)]; 548 if (!s->addChar(c)) { 549 return false; 550 } 551 break; 552 case 2: 553 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 6) & 0x3f)]; 554 if (!s->addChar(c)) { 555 return false; 556 } 557 c = __CFPLDataEncodeTable[(p[0] & 0x3f)]; 558 if (!s->addChar(c)) { 559 return false; 560 } 561 break; 562 } 563 } 564 switch (i % 3) { 565 case 0: 566 break; 567 case 1: 568 c = __CFPLDataEncodeTable[((p[-1] << 4) & 0x30)]; 569 if (!s->addChar(c)) { 570 return false; 571 } 572 if (!s->addChar('=')) { 573 return false; 574 } 575 if (!s->addChar('=')) { 576 return false; 577 } 578 break; 579 case 2: 580 c = __CFPLDataEncodeTable[((p[-1] << 2) & 0x3c)]; 581 if (!s->addChar(c)) { 582 return false; 583 } 584 if (!s->addChar('=')) { 585 return false; 586 } 587 break; 588 } 589 590 return s->addXMLEndTag("data"); 591 } 592 593 void 594 OSData::setDeallocFunction(DeallocFunction func) 595 { 596 if (!reserved) { 597 reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO)); 598 if (!reserved) { 599 return; 600 } 601 } 602 reserved->deallocFunction = func; 603 } 604 605 void 606 OSData::setSerializable(bool serializable) 607 { 608 if (!reserved) { 609 reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO)); 610 if (!reserved) { 611 return; 612 } 613 } 614 reserved->disableSerialization = (!serializable); 615 } 616 617 bool 618 OSData::isSerializable(void) 619 { 620 return !reserved || !reserved->disableSerialization; 621 } 622