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 <vm/vm_kern.h>
33
34 #define IOKIT_ENABLE_SHARED_PTR
35
36 #include <libkern/c++/OSData.h>
37 #include <libkern/c++/OSSerialize.h>
38 #include <libkern/c++/OSLib.h>
39 #include <libkern/c++/OSString.h>
40 #include <IOKit/IOLib.h>
41
42 #define super OSObject
43
44 OSDefineMetaClassAndStructorsWithZone(OSData, OSObject, ZC_ZFREE_CLEARMEM)
45 OSMetaClassDefineReservedUsedX86(OSData, 0); // setDeallocFunction
46 OSMetaClassDefineReservedUnused(OSData, 1);
47 OSMetaClassDefineReservedUnused(OSData, 2);
48 OSMetaClassDefineReservedUnused(OSData, 3);
49 OSMetaClassDefineReservedUnused(OSData, 4);
50 OSMetaClassDefineReservedUnused(OSData, 5);
51 OSMetaClassDefineReservedUnused(OSData, 6);
52 OSMetaClassDefineReservedUnused(OSData, 7);
53
54 #define EXTERNAL ((unsigned int) -1)
55
56 static SECURITY_READ_ONLY_LATE(vm_map_t) alloc_map;
57 __startup_func
58 static void
getAllocMap(void)59 getAllocMap(void)
60 {
61 alloc_map = KHEAP_DATA_BUFFERS->kh_fallback_map;
62 }
63 STARTUP(ZALLOC, STARTUP_RANK_LAST, getAllocMap);
64
65 bool
initWithCapacity(unsigned int inCapacity)66 OSData::initWithCapacity(unsigned int inCapacity)
67 {
68 void *_data = NULL;
69
70 if (data) {
71 OSCONTAINER_ACCUMSIZE(-((size_t)capacity));
72 if (!inCapacity || (capacity < inCapacity)) {
73 // clean out old data's storage if it isn't big enough
74 if (capacity < page_size) {
75 kfree_data_container(data, capacity);
76 } else {
77 kmem_free(alloc_map, (vm_offset_t)data, capacity);
78 }
79 data = NULL;
80 capacity = 0;
81 }
82 }
83
84 if (!super::init()) {
85 return false;
86 }
87
88 if (inCapacity && !data) {
89 if (inCapacity < page_size) {
90 data = (void *)kalloc_data_container(inCapacity, Z_WAITOK);
91 } else {
92 kern_return_t kr;
93 if (round_page_overflow(inCapacity, &inCapacity)) {
94 kr = KERN_RESOURCE_SHORTAGE;
95 } else {
96 kr = kmem_alloc_flags(alloc_map, (vm_offset_t *)&_data, inCapacity,
97 IOMemoryTag(alloc_map), KMA_ATOMIC);
98 data = _data;
99 }
100 if (KERN_SUCCESS != kr) {
101 data = NULL;
102 }
103 }
104 if (!data) {
105 return false;
106 }
107 capacity = inCapacity;
108 }
109 OSCONTAINER_ACCUMSIZE(capacity);
110
111 length = 0;
112 if (inCapacity < 16) {
113 capacityIncrement = 16;
114 } else {
115 capacityIncrement = inCapacity;
116 }
117
118 return true;
119 }
120
121 bool
initWithBytes(const void * bytes,unsigned int inLength)122 OSData::initWithBytes(const void *bytes, unsigned int inLength)
123 {
124 if ((inLength && !bytes) || !initWithCapacity(inLength)) {
125 return false;
126 }
127
128 if (bytes != data) {
129 bcopy(bytes, data, inLength);
130 }
131 length = inLength;
132
133 return true;
134 }
135
136 bool
initWithBytesNoCopy(void * bytes,unsigned int inLength)137 OSData::initWithBytesNoCopy(void *bytes, unsigned int inLength)
138 {
139 if (!super::init()) {
140 return false;
141 }
142
143 length = inLength;
144 capacity = EXTERNAL;
145 data = bytes;
146
147 return true;
148 }
149
150 bool
initWithData(const OSData * inData)151 OSData::initWithData(const OSData *inData)
152 {
153 return initWithBytes(inData->data, inData->length);
154 }
155
156 bool
initWithData(const OSData * inData,unsigned int start,unsigned int inLength)157 OSData::initWithData(const OSData *inData,
158 unsigned int start, unsigned int inLength)
159 {
160 const void *localData = inData->getBytesNoCopy(start, inLength);
161
162 if (localData) {
163 return initWithBytes(localData, inLength);
164 } else {
165 return false;
166 }
167 }
168
169 OSSharedPtr<OSData>
withCapacity(unsigned int inCapacity)170 OSData::withCapacity(unsigned int inCapacity)
171 {
172 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
173
174 if (me && !me->initWithCapacity(inCapacity)) {
175 return nullptr;
176 }
177
178 return me;
179 }
180
181 OSSharedPtr<OSData>
withBytes(const void * bytes,unsigned int inLength)182 OSData::withBytes(const void *bytes, unsigned int inLength)
183 {
184 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
185
186 if (me && !me->initWithBytes(bytes, inLength)) {
187 return nullptr;
188 }
189 return me;
190 }
191
192 OSSharedPtr<OSData>
withBytesNoCopy(void * bytes,unsigned int inLength)193 OSData::withBytesNoCopy(void *bytes, unsigned int inLength)
194 {
195 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
196
197 if (me && !me->initWithBytesNoCopy(bytes, inLength)) {
198 return nullptr;
199 }
200
201 return me;
202 }
203
204 OSSharedPtr<OSData>
withData(const OSData * inData)205 OSData::withData(const OSData *inData)
206 {
207 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
208
209 if (me && !me->initWithData(inData)) {
210 return nullptr;
211 }
212
213 return me;
214 }
215
216 OSSharedPtr<OSData>
withData(const OSData * inData,unsigned int start,unsigned int inLength)217 OSData::withData(const OSData *inData,
218 unsigned int start, unsigned int inLength)
219 {
220 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
221
222 if (me && !me->initWithData(inData, start, inLength)) {
223 return nullptr;
224 }
225
226 return me;
227 }
228
229 void
free()230 OSData::free()
231 {
232 if ((capacity != EXTERNAL) && data && capacity) {
233 if (capacity < page_size) {
234 kfree_data_container(data, capacity);
235 } else {
236 kmem_free(alloc_map, (vm_offset_t)data, capacity);
237 }
238 OSCONTAINER_ACCUMSIZE( -((size_t)capacity));
239 } else if (capacity == EXTERNAL) {
240 DeallocFunction freemem = reserved ? reserved->deallocFunction : NULL;
241 if (freemem && data && length) {
242 freemem(data, length);
243 }
244 }
245 if (reserved) {
246 kfree_type(ExpansionData, reserved);
247 }
248 super::free();
249 }
250
251 unsigned int
getLength() const252 OSData::getLength() const
253 {
254 return length;
255 }
256 unsigned int
getCapacity() const257 OSData::getCapacity() const
258 {
259 return capacity;
260 }
261
262 unsigned int
getCapacityIncrement() const263 OSData::getCapacityIncrement() const
264 {
265 return capacityIncrement;
266 }
267
268 unsigned int
setCapacityIncrement(unsigned increment)269 OSData::setCapacityIncrement(unsigned increment)
270 {
271 return capacityIncrement = increment;
272 }
273
274 // xx-review: does not check for capacity == EXTERNAL
275
276 unsigned int
ensureCapacity(unsigned int newCapacity)277 OSData::ensureCapacity(unsigned int newCapacity)
278 {
279 unsigned char * newData;
280 unsigned int finalCapacity;
281 void * copydata;
282 kern_return_t kr;
283
284 if (newCapacity <= capacity) {
285 return capacity;
286 }
287
288 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1)
289 * capacityIncrement;
290
291 // integer overflow check
292 if (finalCapacity < newCapacity) {
293 return capacity;
294 }
295
296 copydata = data;
297
298 if (finalCapacity >= page_size) {
299 // round up
300 finalCapacity = round_page_32(finalCapacity);
301 // integer overflow check
302 if (finalCapacity < newCapacity) {
303 return capacity;
304 }
305 if (capacity >= page_size) {
306 copydata = NULL;
307 kr = kmem_realloc(alloc_map,
308 (vm_offset_t)data,
309 capacity,
310 (vm_offset_t *)&newData,
311 finalCapacity,
312 IOMemoryTag(alloc_map));
313 } else {
314 kr = kmem_alloc_flags(alloc_map, (vm_offset_t *)&newData,
315 finalCapacity, IOMemoryTag(alloc_map), KMA_ATOMIC);
316 }
317 if (KERN_SUCCESS != kr) {
318 newData = NULL;
319 }
320 } else {
321 newData = (unsigned char *)kalloc_data_container(finalCapacity, Z_WAITOK);
322 }
323
324 if (newData) {
325 bzero(newData + capacity, finalCapacity - capacity);
326 if (copydata) {
327 bcopy(copydata, newData, capacity);
328 }
329 if (data) {
330 if (capacity < page_size) {
331 kfree_data_container(data, capacity);
332 } else {
333 kmem_free(alloc_map, (vm_offset_t)data, capacity);
334 }
335 }
336 OSCONTAINER_ACCUMSIZE(((size_t)finalCapacity) - ((size_t)capacity));
337 data = (void *) newData;
338 capacity = finalCapacity;
339 }
340
341 return capacity;
342 }
343
344 bool
appendBytes(const void * bytes,unsigned int inLength)345 OSData::appendBytes(const void *bytes, unsigned int inLength)
346 {
347 unsigned int newSize;
348
349 if (!inLength) {
350 return true;
351 }
352
353 if (capacity == EXTERNAL) {
354 return false;
355 }
356
357 if (os_add_overflow(length, inLength, &newSize)) {
358 return false;
359 }
360
361 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) {
362 return false;
363 }
364
365 if (bytes) {
366 bcopy(bytes, &((unsigned char *)data)[length], inLength);
367 } else {
368 bzero(&((unsigned char *)data)[length], inLength);
369 }
370
371 length = newSize;
372
373 return true;
374 }
375
376 bool
appendByte(unsigned char byte,unsigned int inLength)377 OSData::appendByte(unsigned char byte, unsigned int inLength)
378 {
379 unsigned int newSize;
380
381 if (!inLength) {
382 return true;
383 }
384
385 if (capacity == EXTERNAL) {
386 return false;
387 }
388
389 if (os_add_overflow(length, inLength, &newSize)) {
390 return false;
391 }
392
393 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) {
394 return false;
395 }
396
397 memset(&((unsigned char *)data)[length], byte, inLength);
398 length = newSize;
399
400 return true;
401 }
402
403 bool
appendBytes(const OSData * other)404 OSData::appendBytes(const OSData *other)
405 {
406 return appendBytes(other->data, other->length);
407 }
408
409 const void *
getBytesNoCopy() const410 OSData::getBytesNoCopy() const
411 {
412 if (!length) {
413 return NULL;
414 } else {
415 return data;
416 }
417 }
418
419 const void *
getBytesNoCopy(unsigned int start,unsigned int inLength) const420 OSData::getBytesNoCopy(unsigned int start,
421 unsigned int inLength) const
422 {
423 const void *outData = NULL;
424
425 if (length
426 && start < length
427 && (start + inLength) >= inLength // overflow check
428 && (start + inLength) <= length) {
429 outData = (const void *) ((char *) data + start);
430 }
431
432 return outData;
433 }
434
435 bool
isEqualTo(const OSData * aData) const436 OSData::isEqualTo(const OSData *aData) const
437 {
438 unsigned int len;
439
440 len = aData->length;
441 if (length != len) {
442 return false;
443 }
444
445 return isEqualTo(aData->data, len);
446 }
447
448 bool
isEqualTo(const void * someData,unsigned int inLength) const449 OSData::isEqualTo(const void *someData, unsigned int inLength) const
450 {
451 return (length >= inLength) && (bcmp(data, someData, inLength) == 0);
452 }
453
454 bool
isEqualTo(const OSMetaClassBase * obj) const455 OSData::isEqualTo(const OSMetaClassBase *obj) const
456 {
457 OSData * otherData;
458 OSString * str;
459
460 if ((otherData = OSDynamicCast(OSData, obj))) {
461 return isEqualTo(otherData);
462 } else if ((str = OSDynamicCast(OSString, obj))) {
463 return isEqualTo(str);
464 } else {
465 return false;
466 }
467 }
468
469 bool
isEqualTo(const OSString * obj) const470 OSData::isEqualTo(const OSString *obj) const
471 {
472 const char * aCString;
473 char * dataPtr;
474 unsigned int checkLen = length;
475 unsigned int stringLen;
476
477 if (!obj) {
478 return false;
479 }
480
481 stringLen = obj->getLength();
482
483 dataPtr = (char *)data;
484
485 if (stringLen != checkLen) {
486 // check for the fact that OSData may be a buffer that
487 // that includes a termination byte and will thus have
488 // a length of the actual string length PLUS 1. In this
489 // case we verify that the additional byte is a terminator
490 // and if so count the two lengths as being the same.
491
492 if ((checkLen - stringLen) == 1) {
493 if (dataPtr[checkLen - 1] != 0) { // non-zero means not a terminator and thus not likely the same
494 return false;
495 }
496 checkLen--;
497 } else {
498 return false;
499 }
500 }
501
502 aCString = obj->getCStringNoCopy();
503
504 for (unsigned int i = 0; i < checkLen; i++) {
505 if (*dataPtr++ != aCString[i]) {
506 return false;
507 }
508 }
509
510 return true;
511 }
512
513 //this was taken from CFPropertyList.c
514 static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
515
516 bool
serialize(OSSerialize * s) const517 OSData::serialize(OSSerialize *s) const
518 {
519 unsigned int i;
520 const unsigned char *p;
521 unsigned char c;
522 unsigned int serializeLength;
523
524 if (s->previouslySerialized(this)) {
525 return true;
526 }
527
528 if (!s->addXMLStartTag(this, "data")) {
529 return false;
530 }
531
532 serializeLength = length;
533 if (reserved && reserved->disableSerialization) {
534 serializeLength = 0;
535 }
536
537 for (i = 0, p = (unsigned char *)data; i < serializeLength; i++, p++) {
538 /* 3 bytes are encoded as 4 */
539 switch (i % 3) {
540 case 0:
541 c = __CFPLDataEncodeTable[((p[0] >> 2) & 0x3f)];
542 if (!s->addChar(c)) {
543 return false;
544 }
545 break;
546 case 1:
547 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 4) & 0x3f)];
548 if (!s->addChar(c)) {
549 return false;
550 }
551 break;
552 case 2:
553 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 6) & 0x3f)];
554 if (!s->addChar(c)) {
555 return false;
556 }
557 c = __CFPLDataEncodeTable[(p[0] & 0x3f)];
558 if (!s->addChar(c)) {
559 return false;
560 }
561 break;
562 }
563 }
564 switch (i % 3) {
565 case 0:
566 break;
567 case 1:
568 c = __CFPLDataEncodeTable[((p[-1] << 4) & 0x30)];
569 if (!s->addChar(c)) {
570 return false;
571 }
572 if (!s->addChar('=')) {
573 return false;
574 }
575 if (!s->addChar('=')) {
576 return false;
577 }
578 break;
579 case 2:
580 c = __CFPLDataEncodeTable[((p[-1] << 2) & 0x3c)];
581 if (!s->addChar(c)) {
582 return false;
583 }
584 if (!s->addChar('=')) {
585 return false;
586 }
587 break;
588 }
589
590 return s->addXMLEndTag("data");
591 }
592
593 void
setDeallocFunction(DeallocFunction func)594 OSData::setDeallocFunction(DeallocFunction func)
595 {
596 if (!reserved) {
597 reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
598 if (!reserved) {
599 return;
600 }
601 }
602 reserved->deallocFunction = func;
603 }
604
605 void
setSerializable(bool serializable)606 OSData::setSerializable(bool serializable)
607 {
608 if (!reserved) {
609 reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
610 if (!reserved) {
611 return;
612 }
613 }
614 reserved->disableSerialization = (!serializable);
615 }
616
617 bool
isSerializable(void)618 OSData::isSerializable(void)
619 {
620 return !reserved || !reserved->disableSerialization;
621 }
622