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 <libkern/c++/OSData.h> 33#include <libkern/c++/OSSerialize.h> 34#include <libkern/c++/OSLib.h> 35#include <libkern/c++/OSString.h> 36#include <string.h> 37 38#define super OSObject 39 40OSDefineMetaClassAndStructors(OSData, OSObject) 41OSMetaClassDefineReservedUsed(OSData, 0); // setDeallocFunction 42OSMetaClassDefineReservedUnused(OSData, 1); 43OSMetaClassDefineReservedUnused(OSData, 2); 44OSMetaClassDefineReservedUnused(OSData, 3); 45OSMetaClassDefineReservedUnused(OSData, 4); 46OSMetaClassDefineReservedUnused(OSData, 5); 47OSMetaClassDefineReservedUnused(OSData, 6); 48OSMetaClassDefineReservedUnused(OSData, 7); 49 50#define EXTERNAL ((unsigned int) -1) 51 52#if OSALLOCDEBUG 53extern int debug_container_malloc_size; 54#define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0) 55#else 56#define ACCUMSIZE(s) 57#endif 58 59struct OSData::ExpansionData 60{ 61 DeallocFunction deallocFunction; 62 bool disableSerialization; 63}; 64 65bool OSData::initWithCapacity(unsigned int inCapacity) 66{ 67 if (!super::init()) 68 return false; 69 70 if (data && (!inCapacity || capacity < inCapacity) ) { 71 // clean out old data's storage if it isn't big enough 72 kfree(data, capacity); 73 data = 0; 74 ACCUMSIZE(-capacity); 75 } 76 77 if (inCapacity && !data) { 78 data = (void *) kalloc(inCapacity); 79 if (!data) 80 return false; 81 capacity = inCapacity; 82 ACCUMSIZE(inCapacity); 83 } 84 85 length = 0; 86 if (inCapacity < 16) 87 capacityIncrement = 16; 88 else 89 capacityIncrement = inCapacity; 90 91 return true; 92} 93 94bool OSData::initWithBytes(const void *bytes, unsigned int inLength) 95{ 96 if ((inLength && !bytes) || !initWithCapacity(inLength)) 97 return false; 98 99 if (bytes != data) 100 bcopy(bytes, data, inLength); 101 length = inLength; 102 103 return true; 104} 105 106bool OSData::initWithBytesNoCopy(void *bytes, unsigned int inLength) 107{ 108 if (!super::init()) 109 return false; 110 111 length = inLength; 112 capacity = EXTERNAL; 113 data = bytes; 114 115 return true; 116} 117 118bool OSData::initWithData(const OSData *inData) 119{ 120 return initWithBytes(inData->data, inData->length); 121} 122 123bool OSData::initWithData(const OSData *inData, 124 unsigned int start, unsigned int inLength) 125{ 126 const void *localData = inData->getBytesNoCopy(start, inLength); 127 128 if (localData) 129 return initWithBytes(localData, inLength); 130 else 131 return false; 132} 133 134OSData *OSData::withCapacity(unsigned int inCapacity) 135{ 136 OSData *me = new OSData; 137 138 if (me && !me->initWithCapacity(inCapacity)) { 139 me->release(); 140 return 0; 141 } 142 143 return me; 144} 145 146OSData *OSData::withBytes(const void *bytes, unsigned int inLength) 147{ 148 OSData *me = new OSData; 149 150 if (me && !me->initWithBytes(bytes, inLength)) { 151 me->release(); 152 return 0; 153 } 154 return me; 155} 156 157OSData *OSData::withBytesNoCopy(void *bytes, unsigned int inLength) 158{ 159 OSData *me = new OSData; 160 161 if (me && !me->initWithBytesNoCopy(bytes, inLength)) { 162 me->release(); 163 return 0; 164 } 165 166 return me; 167} 168 169OSData *OSData::withData(const OSData *inData) 170{ 171 OSData *me = new OSData; 172 173 if (me && !me->initWithData(inData)) { 174 me->release(); 175 return 0; 176 } 177 178 return me; 179} 180 181OSData *OSData::withData(const OSData *inData, 182 unsigned int start, unsigned int inLength) 183{ 184 OSData *me = new OSData; 185 186 if (me && !me->initWithData(inData, start, inLength)) { 187 me->release(); 188 return 0; 189 } 190 191 return me; 192} 193 194void OSData::free() 195{ 196 if (capacity != EXTERNAL && data && capacity) { 197 kfree(data, capacity); 198 ACCUMSIZE( -capacity ); 199 } else if (capacity == EXTERNAL) { 200 DeallocFunction freemem = reserved ? reserved->deallocFunction : NULL; 201 if (freemem && data && length) { 202 freemem(data, length); 203 } 204 } 205 if (reserved) kfree(reserved, sizeof(ExpansionData)); 206 super::free(); 207} 208 209unsigned int OSData::getLength() const { return length; } 210unsigned int OSData::getCapacity() const { return capacity; } 211 212unsigned int OSData::getCapacityIncrement() const 213{ 214 return capacityIncrement; 215} 216 217unsigned int OSData::setCapacityIncrement(unsigned increment) 218{ 219 return capacityIncrement = increment; 220} 221 222// xx-review: does not check for capacity == EXTERNAL 223 224unsigned int OSData::ensureCapacity(unsigned int newCapacity) 225{ 226 unsigned char * newData; 227 228 if (newCapacity <= capacity) 229 return capacity; 230 231 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) 232 * capacityIncrement; 233 234 newData = (unsigned char *) kalloc(newCapacity); 235 236 if ( newData ) { 237 bzero(newData + capacity, newCapacity - capacity); 238 if (data) { 239 bcopy(data, newData, capacity); 240 kfree(data, capacity); 241 } 242 ACCUMSIZE( newCapacity - capacity ); 243 data = (void *) newData; 244 capacity = newCapacity; 245 } 246 247 return capacity; 248} 249 250bool OSData::appendBytes(const void *bytes, unsigned int inLength) 251{ 252 unsigned int newSize; 253 254 if (!inLength) 255 return true; 256 257 if (capacity == EXTERNAL) 258 return false; 259 260 newSize = length + inLength; 261 if ( (newSize > capacity) && newSize > ensureCapacity(newSize) ) 262 return false; 263 264 if (bytes) 265 bcopy(bytes, &((unsigned char *)data)[length], inLength); 266 else 267 bzero(&((unsigned char *)data)[length], inLength); 268 269 length = newSize; 270 271 return true; 272} 273 274bool OSData::appendByte(unsigned char byte, unsigned int inLength) 275{ 276 unsigned int newSize; 277 278 if (!inLength) 279 return true; 280 281 if (capacity == EXTERNAL) 282 return false; 283 284 newSize = length + inLength; 285 if ( (newSize > capacity) && newSize > ensureCapacity(newSize) ) 286 return false; 287 288 memset(&((unsigned char *)data)[length], byte, inLength); 289 length = newSize; 290 291 return true; 292} 293 294bool OSData::appendBytes(const OSData *other) 295{ 296 return appendBytes(other->data, other->length); 297} 298 299const void *OSData::getBytesNoCopy() const 300{ 301 if (!length) 302 return 0; 303 else 304 return data; 305} 306 307const void *OSData::getBytesNoCopy(unsigned int start, 308 unsigned int inLength) const 309{ 310 const void *outData = 0; 311 312 if (length 313 && start < length 314 && (start + inLength) <= length) 315 outData = (const void *) ((char *) data + start); 316 317 return outData; 318} 319 320bool OSData::isEqualTo(const OSData *aData) const 321{ 322 unsigned int len; 323 324 len = aData->length; 325 if ( length != len ) 326 return false; 327 328 return isEqualTo(aData->data, len); 329} 330 331bool OSData::isEqualTo(const void *someData, unsigned int inLength) const 332{ 333 return (length >= inLength) && (bcmp(data, someData, inLength) == 0); 334} 335 336bool OSData::isEqualTo(const OSMetaClassBase *obj) const 337{ 338 OSData * otherData; 339 OSString * str; 340 341 if ((otherData = OSDynamicCast(OSData, obj))) 342 return isEqualTo(otherData); 343 else if ((str = OSDynamicCast (OSString, obj))) 344 return isEqualTo(str); 345 else 346 return false; 347} 348 349bool OSData::isEqualTo(const OSString *obj) const 350{ 351 const char * aCString; 352 char * dataPtr; 353 unsigned int checkLen = length; 354 unsigned int stringLen; 355 356 if (!obj) 357 return false; 358 359 stringLen = obj->getLength (); 360 361 dataPtr = (char *)data; 362 363 if (stringLen != checkLen) { 364 365 // check for the fact that OSData may be a buffer that 366 // that includes a termination byte and will thus have 367 // a length of the actual string length PLUS 1. In this 368 // case we verify that the additional byte is a terminator 369 // and if so count the two lengths as being the same. 370 371 if ( (checkLen - stringLen) == 1) { 372 if (dataPtr[checkLen-1] != 0) // non-zero means not a terminator and thus not likely the same 373 return false; 374 checkLen--; 375 } 376 else 377 return false; 378 } 379 380 aCString = obj->getCStringNoCopy (); 381 382 for ( unsigned int i=0; i < checkLen; i++ ) { 383 if ( *dataPtr++ != aCString[i] ) 384 return false; 385 } 386 387 return true; 388} 389 390//this was taken from CFPropertyList.c 391static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 392 393bool OSData::serialize(OSSerialize *s) const 394{ 395 unsigned int i; 396 const unsigned char *p; 397 unsigned char c; 398 unsigned int serializeLength; 399 400 if (s->previouslySerialized(this)) return true; 401 402 if (!s->addXMLStartTag(this, "data")) return false; 403 404 serializeLength = length; 405 if (reserved && reserved->disableSerialization) serializeLength = 0; 406 407 for (i = 0, p = (unsigned char *)data; i < serializeLength; i++, p++) { 408 /* 3 bytes are encoded as 4 */ 409 switch (i % 3) { 410 case 0: 411 c = __CFPLDataEncodeTable [ ((p[0] >> 2) & 0x3f)]; 412 if (!s->addChar(c)) return false; 413 break; 414 case 1: 415 c = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 4) & 0x3f)]; 416 if (!s->addChar(c)) return false; 417 break; 418 case 2: 419 c = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 6) & 0x3f)]; 420 if (!s->addChar(c)) return false; 421 c = __CFPLDataEncodeTable [ (p[0] & 0x3f)]; 422 if (!s->addChar(c)) return false; 423 break; 424 } 425 } 426 switch (i % 3) { 427 case 0: 428 break; 429 case 1: 430 c = __CFPLDataEncodeTable [ ((p[-1] << 4) & 0x30)]; 431 if (!s->addChar(c)) return false; 432 if (!s->addChar('=')) return false; 433 if (!s->addChar('=')) return false; 434 break; 435 case 2: 436 c = __CFPLDataEncodeTable [ ((p[-1] << 2) & 0x3c)]; 437 if (!s->addChar(c)) return false; 438 if (!s->addChar('=')) return false; 439 break; 440 } 441 442 return s->addXMLEndTag("data"); 443} 444 445void OSData::setDeallocFunction(DeallocFunction func) 446{ 447 if (!reserved) 448 { 449 reserved = (typeof(reserved)) kalloc(sizeof(ExpansionData)); 450 if (!reserved) return; 451 bzero(reserved, sizeof(ExpansionData)); 452 } 453 reserved->deallocFunction = func; 454} 455 456void OSData::setSerializable(bool serializable) 457{ 458 if (!reserved) 459 { 460 reserved = (typeof(reserved)) kalloc(sizeof(ExpansionData)); 461 if (!reserved) return; 462 bzero(reserved, sizeof(ExpansionData)); 463 } 464 reserved->disableSerialization = (!serializable); 465} 466