xref: /xnu-11215/libkern/c++/OSData.cpp (revision e6231be0)
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 = 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
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
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
151 OSData::initWithData(const OSData *inData)
152 {
153 	return initWithBytes(inData->data, inData->length);
154 }
155 
156 bool
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>
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>
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>
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>
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>
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
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
252 OSData::getLength() const
253 {
254 	return length;
255 }
256 unsigned int
257 OSData::getCapacity() const
258 {
259 	return capacity;
260 }
261 
262 unsigned int
263 OSData::getCapacityIncrement() const
264 {
265 	return capacityIncrement;
266 }
267 
268 unsigned int
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
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
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
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
404 OSData::appendBytes(const OSData *other)
405 {
406 	return appendBytes(other->data, other->length);
407 }
408 
409 const void *
410 OSData::getBytesNoCopy() const
411 {
412 	if (!length) {
413 		return NULL;
414 	} else {
415 		return data;
416 	}
417 }
418 
419 const void *
420 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
436 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
449 OSData::isEqualTo(const void *someData, unsigned int inLength) const
450 {
451 	return (length >= inLength) && (bcmp(data, someData, inLength) == 0);
452 }
453 
454 bool
455 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
470 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
517 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
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
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
618 OSData::isSerializable(void)
619 {
620 	return !reserved || !reserved->disableSerialization;
621 }
622