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