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