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