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