xref: /xnu-11215/libkern/c++/OSData.cpp (revision a5e72196)
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 }
612