1/*
2 * Copyright (c) 2014 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
29
30#include <libkern/c++/OSSharedPtr.h>
31#include <libkern/OSSerializeBinary.h>
32#include <libkern/c++/OSContainers.h>
33#include <libkern/c++/OSLib.h>
34#include <libkern/c++/OSDictionary.h>
35#include <libkern/OSSerializeBinary.h>
36#include <libkern/c++/OSSharedPtr.h>
37
38#include <IOKit/IOLib.h>
39
40/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41
42#if 0
43#define DEBG(fmt, args ...) { kprintf(fmt, args); }
44#else
45#define DEBG(fmt, args ...) {}
46#endif
47
48/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
49
50OSSerialize *
51OSSerialize::binaryWithCapacity(unsigned int inCapacity,
52 Editor editor, void * reference)
53{
54 OSSerialize *me;
55
56 if (inCapacity < sizeof(uint32_t)) {
57 return NULL;
58 }
59 me = OSSerialize::withCapacity(capacity: inCapacity);
60 if (!me) {
61 return NULL;
62 }
63
64 me->binary = true;
65 me->endCollection = true;
66 me->editor = editor;
67 me->editRef = reference;
68
69 bcopy(kOSSerializeBinarySignature, dst: &me->data[0], n: sizeof(kOSSerializeBinarySignature));
70 me->length = sizeof(kOSSerializeBinarySignature);
71
72 return me;
73}
74
75bool
76OSSerialize::addBinary(const void * bits, size_t size)
77{
78 unsigned int newCapacity;
79 size_t alignSize;
80
81 if (os_add_overflow(size, 3, &alignSize)) {
82 return false;
83 }
84 alignSize &= ~3L;
85 if (os_add_overflow(length, alignSize, &newCapacity)) {
86 return false;
87 }
88 if (newCapacity >= capacity) {
89 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) * capacityIncrement;
90 if (newCapacity < capacity) {
91 return false;
92 }
93 if (newCapacity > ensureCapacity(newCapacity)) {
94 return false;
95 }
96 }
97
98 bcopy(src: bits, dst: &data[length], n: size);
99 length += alignSize;
100
101 return true;
102}
103
104void
105OSSerialize::setIndexed(bool index __unused)
106{
107 assert(index && !indexData);
108 indexData = OSData::withCapacity(capacity: 256);
109 assert(indexData);
110}
111
112bool
113OSSerialize::addBinaryObject(const OSMetaClassBase * o, uint32_t key,
114 const void * bits, uint32_t size,
115 uint32_t * startCollection)
116{
117 unsigned int newCapacity;
118 size_t alignSize;
119 size_t headerSize;
120
121 // add to tag array
122 tags->setObject(o);
123
124 headerSize = sizeof(key);
125 if (indexData) {
126 uint32_t offset = length;
127 if (startCollection) {
128 *startCollection = offset;
129 headerSize += sizeof(uint32_t);
130 }
131 offset /= sizeof(uint32_t);
132 indexData->appendValue(value: offset);
133 }
134
135 if (os_add3_overflow(size, headerSize, 3, &alignSize)) {
136 return false;
137 }
138 alignSize &= ~3L;
139 if (os_add_overflow(length, alignSize, &newCapacity)) {
140 return false;
141 }
142 if (newCapacity >= capacity) {
143 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) * capacityIncrement;
144 if (newCapacity < capacity) {
145 return false;
146 }
147 if (newCapacity > ensureCapacity(newCapacity)) {
148 return false;
149 }
150 }
151
152 if (endCollection) {
153 endCollection = false;
154 key |= kOSSerializeEndCollecton;
155 }
156
157 bcopy(src: &key, dst: &data[length], n: sizeof(key));
158 bcopy(src: bits, dst: &data[length + headerSize], n: size);
159 length += alignSize;
160
161 return true;
162}
163
164void
165OSSerialize::endBinaryCollection(uint32_t startCollection)
166{
167 uint32_t clength;
168
169 if (!indexData) {
170 return;
171 }
172
173 assert(length > startCollection);
174 if (length <= startCollection) {
175 return;
176 }
177
178 clength = length - startCollection;
179 assert(!(clength & 3));
180 clength /= sizeof(uint32_t);
181
182 memcpy(dst: &data[startCollection + sizeof(uint32_t)], src: &clength, n: sizeof(clength));
183}
184
185bool
186OSSerialize::binarySerialize(const OSMetaClassBase *o)
187{
188 bool ok;
189 uint32_t header;
190
191 ok = binarySerializeInternal(o);
192 if (!ok) {
193 return ok;
194 }
195
196 if (indexData) {
197 header = indexData->getLength() / sizeof(uint32_t);
198 assert(header <= kOSSerializeDataMask);
199 header <<= 8;
200 header |= kOSSerializeIndexedBinarySignature;
201
202 memcpy(dst: &data[0], src: &header, n: sizeof(header));
203 }
204
205 return ok;
206}
207
208bool
209OSSerialize::binarySerializeInternal(const OSMetaClassBase *o)
210{
211 OSDictionary * dict;
212 OSArray * array;
213 OSSet * set;
214 OSNumber * num;
215 OSSymbol * sym;
216 OSString * str;
217 OSData * ldata;
218 OSBoolean * boo;
219
220 unsigned int tagIdx;
221 uint32_t i, key, startCollection = 0;
222 uint32_t len;
223 bool ok;
224
225 tagIdx = tags->getNextIndexOfObject(anObject: o, index: 0);
226 // does it exist?
227 if (-1U != tagIdx) {
228 if (indexData) {
229 assert(indexData->getLength() > (tagIdx * sizeof(uint32_t)));
230 tagIdx = ((const uint32_t *)indexData->getBytesNoCopy())[tagIdx];
231 assert(tagIdx <= kOSSerializeDataMask);
232 }
233 key = (kOSSerializeObject | tagIdx);
234 if (endCollection) {
235 endCollection = false;
236 key |= kOSSerializeEndCollecton;
237 }
238 ok = addBinary(bits: &key, size: sizeof(key));
239 return ok;
240 }
241
242 if ((dict = OSDynamicCast(OSDictionary, o))) {
243 key = (kOSSerializeDictionary | dict->count);
244 ok = addBinaryObject(o, key, NULL, size: 0, startCollection: &startCollection);
245 for (i = 0; ok && (i < dict->count);) {
246 const OSSymbol * dictKey;
247 const OSMetaClassBase * dictValue;
248 const OSMetaClassBase * nvalue = NULL;
249
250 dictKey = dict->dictionary[i].key;
251 dictValue = dict->dictionary[i].value;
252 i++;
253 if (editor) {
254 dictValue = nvalue = (*editor)(editRef, this, dict, dictKey, dictValue);
255 if (!dictValue) {
256 dictValue = dict;
257 }
258 }
259 ok = binarySerialize(o: dictKey);
260 if (!ok) {
261 break;
262 }
263 endCollection = (i == dict->count);
264 ok = binarySerialize(o: dictValue);
265 if (!ok) {
266 ok = dictValue->serialize(serializer: this);
267 }
268 if (nvalue) {
269 nvalue->release();
270 }
271// if (!ok) ok = binarySerialize(kOSBooleanFalse);
272 }
273 endBinaryCollection(startCollection);
274 } else if ((array = OSDynamicCast(OSArray, o))) {
275 key = (kOSSerializeArray | array->count);
276 ok = addBinaryObject(o, key, NULL, size: 0, startCollection: &startCollection);
277 for (i = 0; ok && (i < array->count);) {
278 i++;
279 endCollection = (i == array->count);
280 ok = binarySerialize(o: array->array[i - 1]);
281 if (!ok) {
282 ok = array->array[i - 1]->serialize(serializer: this);
283 }
284// if (!ok) ok = binarySerialize(kOSBooleanFalse);
285 }
286 endBinaryCollection(startCollection);
287 } else if ((set = OSDynamicCast(OSSet, o))) {
288 key = (kOSSerializeSet | set->members->count);
289 ok = addBinaryObject(o, key, NULL, size: 0, startCollection: &startCollection);
290 for (i = 0; ok && (i < set->members->count);) {
291 i++;
292 endCollection = (i == set->members->count);
293 ok = binarySerialize(o: set->members->array[i - 1]);
294 if (!ok) {
295 ok = set->members->array[i - 1]->serialize(serializer: this);
296 }
297// if (!ok) ok = binarySerialize(kOSBooleanFalse);
298 }
299 endBinaryCollection(startCollection);
300 } else if ((num = OSDynamicCast(OSNumber, o))) {
301 key = (kOSSerializeNumber | num->size);
302 ok = addBinaryObject(o, key, bits: &num->value, size: sizeof(num->value), NULL);
303 } else if ((boo = OSDynamicCast(OSBoolean, o))) {
304 key = (kOSSerializeBoolean | (kOSBooleanTrue == boo));
305 ok = addBinaryObject(o, key, NULL, size: 0, NULL);
306 } else if ((sym = OSDynamicCast(OSSymbol, o))) {
307 len = (sym->getLength() + 1);
308 key = (kOSSerializeSymbol | len);
309 ok = addBinaryObject(o, key, bits: sym->getCStringNoCopy(), size: len, NULL);
310 } else if ((str = OSDynamicCast(OSString, o))) {
311 len = str->getLength();
312 key = (kOSSerializeString | len);
313 ok = addBinaryObject(o, key, bits: str->getCStringNoCopy(), size: len, NULL);
314 } else if ((ldata = OSDynamicCast(OSData, o))) {
315 len = ldata->getLength();
316 if (ldata->reserved && ldata->reserved->disableSerialization) {
317 len = 0;
318 }
319 key = (kOSSerializeData | len);
320 ok = addBinaryObject(o, key, bits: ldata->getBytesNoCopy(), size: len, NULL);
321 } else {
322 return false;
323 }
324
325 return ok;
326}
327
328/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
329
330#define setAtIndex(v, idx, o) \
331 ok = idx < v##Capacity; \
332 if (!ok && v##Capacity < v##CapacityMax) { \
333 uint32_t ncap = v##Capacity + 64; \
334 typeof(v##Array) nbuf = kreallocp_type_container(OSObject *, \
335 v##Array, v##Capacity, &ncap, Z_WAITOK_ZERO); \
336 if (nbuf) { \
337 ok = true; \
338 v##Array = nbuf; \
339 v##Capacity = ncap; \
340 } \
341 } \
342 if (ok) v##Array[idx] = o
343
344/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
345
346OSObject *
347OSUnserializeBinary(const char *buffer, size_t bufferSize, OSString **errorString)
348{
349 OSObject ** objsArray;
350 uint32_t objsCapacity;
351 enum { objsCapacityMax = 16 * 1024 * 1024 };
352 uint32_t objsIdx;
353
354 OSObject ** stackArray;
355 uint32_t stackCapacity;
356 enum { stackCapacityMax = 64 };
357 uint32_t stackIdx;
358
359 OSObject * result;
360 OSObject * parent;
361 OSDictionary * dict;
362 OSArray * array;
363 OSSet * set;
364 OSDictionary * newDict;
365 OSArray * newArray;
366 OSSet * newSet;
367 OSObject * o;
368 OSSymbol * sym;
369 OSString * str;
370
371 size_t bufferPos;
372 const uint32_t * next;
373 uint32_t key, len, wordLen, length;
374 bool end, newCollect, isRef;
375 union {
376 unsigned long long value;
377 double fpValue;
378 } value;
379 bool ok, indexed, hasLength;
380
381 indexed = false;
382 if (errorString) {
383 *errorString = NULL;
384 }
385
386 if (bufferSize < sizeof(kOSSerializeBinarySignature)) {
387 return NULL;
388 }
389 if (kOSSerializeIndexedBinarySignature == (((const uint8_t *) buffer)[0])) {
390 indexed = true;
391 } else if (0 != strcmp(kOSSerializeBinarySignature, s2: buffer)) {
392 return NULL;
393 }
394 if (3 & ((uintptr_t) buffer)) {
395 return NULL;
396 }
397
398 bufferPos = sizeof(kOSSerializeBinarySignature);
399 next = (typeof(next))(((uintptr_t) buffer) + bufferPos);
400
401 DEBG("---------OSUnserializeBinary(%p)\n", buffer);
402
403 objsArray = stackArray = NULL;
404 objsIdx = objsCapacity = 0;
405 stackIdx = stackCapacity = 0;
406
407 result = NULL;
408 parent = NULL;
409 dict = NULL;
410 array = NULL;
411 set = NULL;
412 sym = NULL;
413
414 ok = true;
415 while (ok) {
416 bufferPos += sizeof(*next);
417 if (!(ok = (bufferPos <= bufferSize))) {
418 break;
419 }
420 key = *next++;
421 length = 0;
422
423 len = (key & kOSSerializeDataMask);
424 wordLen = (len + 3) >> 2;
425 end = (0 != (kOSSerializeEndCollecton & key));
426 DEBG("key 0x%08x: 0x%04x, %d\n", key, len, end);
427
428 newCollect = isRef = hasLength = false;
429 o = NULL; newDict = NULL; newArray = NULL; newSet = NULL;
430
431 switch (kOSSerializeTypeMask & key) {
432 case kOSSerializeDictionary:
433 o = newDict = OSDictionary::withCapacity(capacity: len);
434 newCollect = (len != 0);
435 hasLength = indexed;
436 break;
437 case kOSSerializeArray:
438 o = newArray = OSArray::withCapacity(capacity: len);
439 newCollect = (len != 0);
440 hasLength = indexed;
441 break;
442 case kOSSerializeSet:
443 o = newSet = OSSet::withCapacity(capacity: len);
444 newCollect = (len != 0);
445 hasLength = indexed;
446 break;
447
448 case kOSSerializeObject:
449 if (len >= objsIdx) {
450 break;
451 }
452 o = objsArray[len];
453 isRef = true;
454 break;
455
456 case kOSSerializeNumber:
457 bufferPos += sizeof(long long);
458 if (bufferPos > bufferSize) {
459 break;
460 }
461 value.value = next[1];
462 value.value <<= 32;
463 value.value |= next[0];
464 switch (len) {
465 case 63:
466 o = OSNumber::withDouble(value: value.fpValue);
467 break;
468 case 31:
469 o = OSNumber::withFloat(value: (float) value.fpValue);
470 break;
471 case 64:
472 case 32:
473 case 16:
474 case 8:
475 o = OSNumber::withNumber(value: value.value, numberOfBits: len);
476 break;
477 }
478 next += 2;
479 break;
480
481 case kOSSerializeSymbol:
482 bufferPos += (wordLen * sizeof(uint32_t));
483 if (bufferPos > bufferSize) {
484 break;
485 }
486 if (len < 1) {
487 break;
488 }
489 if (0 != ((const char *)next)[len - 1]) {
490 break;
491 }
492 o = (OSObject *) OSSymbol::withCString(cString: (const char *) next);
493 next += wordLen;
494 break;
495
496 case kOSSerializeString:
497 bufferPos += (wordLen * sizeof(uint32_t));
498 if (bufferPos > bufferSize) {
499 break;
500 }
501 o = OSString::withCString(cString: (const char *) next, length: len);
502 next += wordLen;
503 break;
504
505 case kOSSerializeData:
506 bufferPos += (wordLen * sizeof(uint32_t));
507 if (bufferPos > bufferSize) {
508 break;
509 }
510 o = OSData::withBytes(bytes: next, numBytes: len);
511 next += wordLen;
512 break;
513
514 case kOSSerializeBoolean:
515 o = (len ? kOSBooleanTrue : kOSBooleanFalse);
516 break;
517
518 default:
519 break;
520 }
521
522 if (!(ok = (o != NULL))) {
523 break;
524 }
525
526 if (hasLength) {
527 bufferPos += sizeof(*next);
528 if (!(ok = (bufferPos <= bufferSize))) {
529 o->release();
530 break;
531 }
532 length = *next++;
533 }
534
535 if (!isRef) {
536 setAtIndex(objs, objsIdx, o);
537 if (!ok) {
538 o->release();
539 break;
540 }
541 objsIdx++;
542 }
543
544 if (dict) {
545 if (!sym) {
546 sym = (OSSymbol *) o;
547 } else {
548 str = sym;
549 sym = OSDynamicCast(OSSymbol, sym);
550 if (!sym && (str = OSDynamicCast(OSString, str))) {
551 sym = const_cast<OSSymbol *>(OSSymbol::withString(aString: str));
552 ok = (sym != NULL);
553 if (!ok) {
554 break;
555 }
556 }
557 DEBG("%s = %s\n", sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
558 if (o != dict) {
559 ok = dict->setObject(aKey: sym, anObject: o);
560 }
561 if (sym && (sym != str)) {
562 sym->release();
563 }
564 sym = NULL;
565 }
566 } else if (array) {
567 ok = array->setObject(o);
568 } else if (set) {
569 ok = set->setObject(o);
570 } else if (result) {
571 ok = false;
572 } else {
573 assert(!parent);
574 result = o;
575 }
576
577 if (!ok) {
578 break;
579 }
580
581 if (end) {
582 parent = NULL;
583 }
584 if (newCollect) {
585 stackIdx++;
586 setAtIndex(stack, stackIdx, parent);
587 if (!ok) {
588 break;
589 }
590 DEBG("++stack[%d] %p\n", stackIdx, parent);
591 parent = o;
592 dict = newDict;
593 array = newArray;
594 set = newSet;
595 end = false;
596 }
597
598 if (end) {
599 while (stackIdx) {
600 parent = stackArray[stackIdx];
601 DEBG("--stack[%d] %p\n", stackIdx, parent);
602 stackIdx--;
603 if (parent) {
604 break;
605 }
606 }
607 if (!parent) {
608 break;
609 }
610 set = NULL;
611 dict = NULL;
612 array = NULL;
613 if (!(dict = OSDynamicCast(OSDictionary, parent))) {
614 if (!(array = OSDynamicCast(OSArray, parent))) {
615 ok = (NULL != (set = OSDynamicCast(OSSet, parent)));
616 }
617 }
618 }
619 }
620 DEBG("ret %p\n", result);
621
622 if (!ok) {
623 result = NULL;
624 }
625
626 if (objsCapacity) {
627 for (len = (result != NULL); len < objsIdx; len++) {
628 objsArray[len]->release();
629 }
630 kfree_type(OSObject *, objsCapacity, objsArray);
631 }
632 if (stackCapacity) {
633 kfree_type(OSObject *, stackCapacity, stackArray);
634 }
635
636 return result;
637}
638
639OSObject*
640OSUnserializeXML(
641 const char * buffer,
642 OSSharedPtr<OSString>& errorString)
643{
644 OSString* errorStringRaw = NULL;
645 OSObject* result = OSUnserializeXML(buffer, errorString: &errorStringRaw);
646 errorString.reset(p: errorStringRaw, OSNoRetain);
647 return result;
648}
649
650OSObject*
651OSUnserializeXML(
652 const char * buffer,
653 size_t bufferSize,
654 OSSharedPtr<OSString> &errorString)
655{
656 OSString* errorStringRaw = NULL;
657 OSObject* result = OSUnserializeXML(buffer, bufferSize, errorString: &errorStringRaw);
658 errorString.reset(p: errorStringRaw, OSNoRetain);
659 return result;
660}
661
662OSObject*
663OSUnserializeBinary(const char *buffer, size_t bufferSize, OSSharedPtr<OSString>& errorString)
664{
665 OSString* errorStringRaw = NULL;
666 OSObject* result = OSUnserializeBinary(buffer, bufferSize, errorString: &errorStringRaw);
667 errorString.reset(p: errorStringRaw, OSNoRetain);
668 return result;
669}
670
671OSObject*
672OSUnserialize(const char *buffer, OSSharedPtr<OSString>& errorString)
673{
674 OSString* errorStringRaw = NULL;
675 OSObject* result = OSUnserialize(buffer, errorString: &errorStringRaw);
676 errorString.reset(p: errorStringRaw, OSNoRetain);
677 return result;
678}
679