1 /* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. 7 * 8 * This file contains Original Code and/or Modifications of Original Code 9 * as defined in and that are subject to the Apple Public Source License 10 * Version 2.0 (the 'License'). You may not use this file except in 11 * compliance with the License. Please obtain a copy of the License at 12 * http://www.opensource.apple.com/apsl/ and read it before using this 13 * file. 14 * 15 * The Original Code and all software distributed under the License are 16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 20 * Please see the License for the specific language governing rights and 21 * limitations under the License. 22 * 23 * @APPLE_LICENSE_HEADER_END@ 24 */ 25 /* IOData.m created by rsulack on Thu 25-Sep-1997 */ 26 27 #include <string.h> 28 29 #include <libkern/c++/OSData.h> 30 #include <libkern/c++/OSSerialize.h> 31 #include <libkern/c++/OSLib.h> 32 #include <libkern/c++/OSString.h> 33 #include <string.h> 34 35 #define super OSObject 36 37 OSDefineMetaClassAndStructors(OSData, OSObject) 38 OSMetaClassDefineReservedUnused(OSData, 0); 39 OSMetaClassDefineReservedUnused(OSData, 1); 40 OSMetaClassDefineReservedUnused(OSData, 2); 41 OSMetaClassDefineReservedUnused(OSData, 3); 42 OSMetaClassDefineReservedUnused(OSData, 4); 43 OSMetaClassDefineReservedUnused(OSData, 5); 44 OSMetaClassDefineReservedUnused(OSData, 6); 45 OSMetaClassDefineReservedUnused(OSData, 7); 46 47 #define EXTERNAL ((unsigned int) -1) 48 49 #if OSALLOCDEBUG 50 extern int debug_container_malloc_size; 51 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0) 52 #else 53 #define ACCUMSIZE(s) 54 #endif 55 56 bool OSData::initWithCapacity(unsigned int inCapacity) 57 { 58 if (!super::init()) 59 return false; 60 61 if (data && (!inCapacity || capacity < inCapacity) ) { 62 // clean out old data's storage if it isn't big enough 63 kfree((vm_address_t) data, capacity); 64 data = 0; 65 ACCUMSIZE(-capacity); 66 } 67 68 if (inCapacity && !data) { 69 data = (void *) kalloc(inCapacity); 70 if (!data) 71 return false; 72 capacity = inCapacity; 73 ACCUMSIZE(inCapacity); 74 } 75 76 length = 0; 77 if (inCapacity < 16) 78 capacityIncrement = 16; 79 else 80 capacityIncrement = inCapacity; 81 82 return true; 83 } 84 85 bool OSData::initWithBytes(const void *bytes, unsigned int inLength) 86 { 87 if ((inLength && !bytes) || !initWithCapacity(inLength)) 88 return false; 89 90 if (bytes != data) 91 bcopy(bytes, data, inLength); 92 length = inLength; 93 94 return true; 95 } 96 97 bool OSData::initWithBytesNoCopy(void *bytes, unsigned int inLength) 98 { 99 if (!super::init()) 100 return false; 101 102 length = inLength; 103 capacity = EXTERNAL; 104 data = bytes; 105 106 return true; 107 } 108 109 bool OSData::initWithData(const OSData *inData) 110 { 111 return initWithBytes(inData->data, inData->length); 112 } 113 114 bool OSData::initWithData(const OSData *inData, 115 unsigned int start, unsigned int inLength) 116 { 117 const void *localData = inData->getBytesNoCopy(start, inLength); 118 119 if (localData) 120 return initWithBytes(localData, inLength); 121 else 122 return false; 123 } 124 125 OSData *OSData::withCapacity(unsigned int inCapacity) 126 { 127 OSData *me = new OSData; 128 129 if (me && !me->initWithCapacity(inCapacity)) { 130 me->release(); 131 return 0; 132 } 133 134 return me; 135 } 136 137 OSData *OSData::withBytes(const void *bytes, unsigned int inLength) 138 { 139 OSData *me = new OSData; 140 141 if (me && !me->initWithBytes(bytes, inLength)) { 142 me->release(); 143 return 0; 144 } 145 return me; 146 } 147 148 OSData *OSData::withBytesNoCopy(void *bytes, unsigned int inLength) 149 { 150 OSData *me = new OSData; 151 152 if (me && !me->initWithBytesNoCopy(bytes, inLength)) { 153 me->release(); 154 return 0; 155 } 156 157 return me; 158 } 159 160 OSData *OSData::withData(const OSData *inData) 161 { 162 OSData *me = new OSData; 163 164 if (me && !me->initWithData(inData)) { 165 me->release(); 166 return 0; 167 } 168 169 return me; 170 } 171 172 OSData *OSData::withData(const OSData *inData, 173 unsigned int start, unsigned int inLength) 174 { 175 OSData *me = new OSData; 176 177 if (me && !me->initWithData(inData, start, inLength)) { 178 me->release(); 179 return 0; 180 } 181 182 return me; 183 } 184 185 void OSData::free() 186 { 187 if (capacity != EXTERNAL && data && capacity) { 188 kfree((vm_offset_t)data, capacity); 189 ACCUMSIZE( -capacity ); 190 } 191 super::free(); 192 } 193 194 unsigned int OSData::getLength() const { return length; } 195 unsigned int OSData::getCapacity() const { return capacity; } 196 197 unsigned int OSData::getCapacityIncrement() const 198 { 199 return capacityIncrement; 200 } 201 202 unsigned int OSData::setCapacityIncrement(unsigned increment) 203 { 204 return capacityIncrement = increment; 205 } 206 207 unsigned int OSData::ensureCapacity(unsigned int newCapacity) 208 { 209 unsigned char * newData; 210 211 if (newCapacity <= capacity) 212 return capacity; 213 214 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) 215 * capacityIncrement; 216 217 newData = (unsigned char *) kalloc(newCapacity); 218 219 if ( newData ) { 220 bzero(newData + capacity, newCapacity - capacity); 221 if (data) { 222 bcopy(data, newData, capacity); 223 kfree((vm_offset_t)data, capacity); 224 } 225 ACCUMSIZE( newCapacity - capacity ); 226 data = (void *) newData; 227 capacity = newCapacity; 228 } 229 230 return capacity; 231 } 232 233 bool OSData::appendBytes(const void *bytes, unsigned int inLength) 234 { 235 unsigned int newSize; 236 237 if (!inLength) 238 return true; 239 240 if (capacity == EXTERNAL) 241 return false; 242 243 newSize = length + inLength; 244 if ( (newSize > capacity) && newSize > ensureCapacity(newSize) ) 245 return false; 246 247 if (bytes) 248 bcopy(bytes, &((unsigned char *)data)[length], inLength); 249 else 250 bzero(&((unsigned char *)data)[length], inLength); 251 252 length = newSize; 253 254 return true; 255 } 256 257 bool OSData::appendByte(unsigned char byte, unsigned int inLength) 258 { 259 unsigned int newSize; 260 261 if (!inLength) 262 return true; 263 264 if (capacity == EXTERNAL) 265 return false; 266 267 newSize = length + inLength; 268 if ( (newSize > capacity) && newSize > ensureCapacity(newSize) ) 269 return false; 270 271 memset(&((unsigned char *)data)[length], byte, inLength); 272 length = newSize; 273 274 return true; 275 } 276 277 bool OSData::appendBytes(const OSData *other) 278 { 279 return appendBytes(other->data, other->length); 280 } 281 282 const void *OSData::getBytesNoCopy() const 283 { 284 if (!length) 285 return 0; 286 else 287 return data; 288 } 289 290 const void *OSData::getBytesNoCopy(unsigned int start, 291 unsigned int inLength) const 292 { 293 const void *outData = 0; 294 295 if (length 296 && start < length 297 && (start + inLength) <= length) 298 outData = (const void *) ((char *) data + start); 299 300 return outData; 301 } 302 303 bool OSData::isEqualTo(const OSData *aData) const 304 { 305 unsigned int len; 306 307 len = aData->length; 308 if ( length != len ) 309 return false; 310 311 return isEqualTo(aData->data, len); 312 } 313 314 bool OSData::isEqualTo(const void *someData, unsigned int inLength) const 315 { 316 return (length >= inLength) && (bcmp(data, someData, inLength) == 0); 317 } 318 319 bool OSData::isEqualTo(const OSMetaClassBase *obj) const 320 { 321 OSData * data; 322 OSString * str; 323 324 if ((data = OSDynamicCast(OSData, obj))) 325 return isEqualTo(data); 326 else if ((str = OSDynamicCast (OSString, obj))) 327 return isEqualTo(str); 328 else 329 return false; 330 } 331 332 bool OSData::isEqualTo(const OSString *obj) const 333 { 334 const char * aCString; 335 char * dataPtr; 336 unsigned int checkLen = length; 337 unsigned int stringLen; 338 339 if (!obj) 340 return false; 341 342 stringLen = obj->getLength (); 343 344 dataPtr = (char *)data; 345 346 if (stringLen != checkLen) { 347 348 // check for the fact that OSData may be a buffer that 349 // that includes a termination byte and will thus have 350 // a length of the actual string length PLUS 1. In this 351 // case we verify that the additional byte is a terminator 352 // and if so count the two lengths as being the same. 353 354 if ( (checkLen - stringLen) == 1) { 355 if (dataPtr[checkLen-1] != 0) // non-zero means not a terminator and thus not likely the same 356 return false; 357 checkLen--; 358 } 359 else 360 return false; 361 } 362 363 aCString = obj->getCStringNoCopy (); 364 365 for ( unsigned int i=0; i < checkLen; i++ ) { 366 if ( *dataPtr++ != aCString[i] ) 367 return false; 368 } 369 370 return true; 371 } 372 373 //this was taken from CFPropertyList.c 374 static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 375 376 bool OSData::serialize(OSSerialize *s) const 377 { 378 unsigned int i; 379 const unsigned char *p; 380 unsigned char c; 381 382 if (s->previouslySerialized(this)) return true; 383 384 if (!s->addXMLStartTag(this, "data")) return false; 385 386 for (i = 0, p = (unsigned char *)data; i < length; i++, p++) { 387 /* 3 bytes are encoded as 4 */ 388 switch (i % 3) { 389 case 0: 390 c = __CFPLDataEncodeTable [ ((p[0] >> 2) & 0x3f)]; 391 if (!s->addChar(c)) return false; 392 break; 393 case 1: 394 c = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 4) & 0x3f)]; 395 if (!s->addChar(c)) return false; 396 break; 397 case 2: 398 c = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 6) & 0x3f)]; 399 if (!s->addChar(c)) return false; 400 c = __CFPLDataEncodeTable [ (p[0] & 0x3f)]; 401 if (!s->addChar(c)) return false; 402 break; 403 } 404 } 405 switch (i % 3) { 406 case 0: 407 break; 408 case 1: 409 c = __CFPLDataEncodeTable [ ((p[-1] << 4) & 0x30)]; 410 if (!s->addChar(c)) return false; 411 if (!s->addChar('=')) return false; 412 if (!s->addChar('=')) return false; 413 break; 414 case 2: 415 c = __CFPLDataEncodeTable [ ((p[-1] << 2) & 0x3c)]; 416 if (!s->addChar(c)) return false; 417 if (!s->addChar('=')) return false; 418 break; 419 } 420 421 return s->addXMLEndTag("data"); 422 } 423