]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSData.cpp
xnu-6153.141.1.tar.gz
[apple/xnu.git] / libkern / c++ / OSData.cpp
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 }