2 * Copyright (c) 2014 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <libkern/c++/OSContainers.h>
31 #include <libkern/c++/OSLib.h>
32 #include <libkern/c++/OSDictionary.h>
33 #include <libkern/OSSerializeBinary.h>
35 #include <IOKit/IOLib.h>
37 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
40 #define DEBG(fmt, args ...) { kprintf(fmt, args); }
42 #define DEBG(fmt, args ...) {}
45 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
48 OSSerialize::binaryWithCapacity(unsigned int inCapacity
,
49 Editor editor
, void * reference
)
53 if (inCapacity
< sizeof(uint32_t)) {
56 me
= OSSerialize::withCapacity(inCapacity
);
62 me
->endCollection
= true;
64 me
->editRef
= reference
;
66 bcopy(kOSSerializeBinarySignature
, &me
->data
[0], sizeof(kOSSerializeBinarySignature
));
67 me
->length
= sizeof(kOSSerializeBinarySignature
);
73 OSSerialize::addBinary(const void * bits
, size_t size
)
75 unsigned int newCapacity
;
78 if (os_add_overflow(size
, 3, &alignSize
)) {
82 if (os_add_overflow(length
, alignSize
, &newCapacity
)) {
85 if (newCapacity
>= capacity
) {
86 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1) * capacityIncrement
;
87 if (newCapacity
< capacity
) {
90 if (newCapacity
> ensureCapacity(newCapacity
)) {
95 bcopy(bits
, &data
[length
], size
);
102 OSSerialize::addBinaryObject(const OSMetaClassBase
* o
, uint32_t key
,
103 const void * bits
, size_t size
)
105 unsigned int newCapacity
;
111 if (os_add3_overflow(size
, sizeof(key
), 3, &alignSize
)) {
115 if (os_add_overflow(length
, alignSize
, &newCapacity
)) {
118 if (newCapacity
>= capacity
) {
119 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1) * capacityIncrement
;
120 if (newCapacity
< capacity
) {
123 if (newCapacity
> ensureCapacity(newCapacity
)) {
129 endCollection
= false;
130 key
|= kOSSerializeEndCollecton
;
133 bcopy(&key
, &data
[length
], sizeof(key
));
134 bcopy(bits
, &data
[length
+ sizeof(key
)], size
);
141 OSSerialize::binarySerialize(const OSMetaClassBase
*o
)
157 tagIdx
= tags
->getNextIndexOfObject(o
, 0);
160 key
= (kOSSerializeObject
| tagIdx
);
162 endCollection
= false;
163 key
|= kOSSerializeEndCollecton
;
165 ok
= addBinary(&key
, sizeof(key
));
169 if ((dict
= OSDynamicCast(OSDictionary
, o
))) {
170 key
= (kOSSerializeDictionary
| dict
->count
);
171 ok
= addBinaryObject(o
, key
, NULL
, 0);
172 for (i
= 0; ok
&& (i
< dict
->count
);) {
173 const OSSymbol
* dictKey
;
174 const OSMetaClassBase
* dictValue
;
175 const OSMetaClassBase
* nvalue
= 0;
177 dictKey
= dict
->dictionary
[i
].key
;
178 dictValue
= dict
->dictionary
[i
].value
;
181 dictValue
= nvalue
= (*editor
)(editRef
, this, dict
, dictKey
, dictValue
);
186 ok
= binarySerialize(dictKey
);
190 endCollection
= (i
== dict
->count
);
191 ok
= binarySerialize(dictValue
);
193 ok
= dictValue
->serialize(this);
198 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
200 } else if ((array
= OSDynamicCast(OSArray
, o
))) {
201 key
= (kOSSerializeArray
| array
->count
);
202 ok
= addBinaryObject(o
, key
, NULL
, 0);
203 for (i
= 0; ok
&& (i
< array
->count
);) {
205 endCollection
= (i
== array
->count
);
206 ok
= binarySerialize(array
->array
[i
- 1]);
208 ok
= array
->array
[i
- 1]->serialize(this);
210 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
212 } else if ((set
= OSDynamicCast(OSSet
, o
))) {
213 key
= (kOSSerializeSet
| set
->members
->count
);
214 ok
= addBinaryObject(o
, key
, NULL
, 0);
215 for (i
= 0; ok
&& (i
< set
->members
->count
);) {
217 endCollection
= (i
== set
->members
->count
);
218 ok
= binarySerialize(set
->members
->array
[i
- 1]);
220 ok
= set
->members
->array
[i
- 1]->serialize(this);
222 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
224 } else if ((num
= OSDynamicCast(OSNumber
, o
))) {
225 key
= (kOSSerializeNumber
| num
->size
);
226 ok
= addBinaryObject(o
, key
, &num
->value
, sizeof(num
->value
));
227 } else if ((boo
= OSDynamicCast(OSBoolean
, o
))) {
228 key
= (kOSSerializeBoolean
| (kOSBooleanTrue
== boo
));
229 ok
= addBinaryObject(o
, key
, NULL
, 0);
230 } else if ((sym
= OSDynamicCast(OSSymbol
, o
))) {
231 len
= (sym
->getLength() + 1);
232 key
= (kOSSerializeSymbol
| len
);
233 ok
= addBinaryObject(o
, key
, sym
->getCStringNoCopy(), len
);
234 } else if ((str
= OSDynamicCast(OSString
, o
))) {
235 len
= (str
->getLength() + 0);
236 key
= (kOSSerializeString
| len
);
237 ok
= addBinaryObject(o
, key
, str
->getCStringNoCopy(), len
);
238 } else if ((ldata
= OSDynamicCast(OSData
, o
))) {
239 len
= ldata
->getLength();
240 if (ldata
->reserved
&& ldata
->reserved
->disableSerialization
) {
243 key
= (kOSSerializeData
| len
);
244 ok
= addBinaryObject(o
, key
, ldata
->getBytesNoCopy(), len
);
252 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
254 #define setAtIndex(v, idx, o) \
255 if (idx >= v##Capacity) \
257 if (v##Capacity >= v##CapacityMax) ok = false; \
260 uint32_t ncap = v##Capacity + 64; \
261 typeof(v##Array) nbuf = (typeof(v##Array)) kalloc_container(ncap * sizeof(o)); \
262 if (!nbuf) ok = false; \
267 bcopy(v##Array, nbuf, v##Capacity * sizeof(o)); \
268 kfree(v##Array, v##Capacity * sizeof(o)); \
271 v##Capacity = ncap; \
275 if (ok) v##Array[idx] = o;
277 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
280 OSUnserializeBinary(const char *buffer
, size_t bufferSize
, OSString
**errorString
)
282 OSObject
** objsArray
;
283 uint32_t objsCapacity
;
284 enum { objsCapacityMax
= 16 * 1024 * 1024 };
287 OSObject
** stackArray
;
288 uint32_t stackCapacity
;
289 enum { stackCapacityMax
= 64 };
297 OSDictionary
* newDict
;
305 const uint32_t * next
;
306 uint32_t key
, len
, wordLen
;
307 bool end
, newCollect
, isRef
;
308 unsigned long long value
;
314 if (bufferSize
< sizeof(kOSSerializeBinarySignature
)) {
317 if (0 != strcmp(kOSSerializeBinarySignature
, buffer
)) {
320 if (3 & ((uintptr_t) buffer
)) {
323 bufferPos
= sizeof(kOSSerializeBinarySignature
);
324 next
= (typeof(next
))(((uintptr_t) buffer
) + bufferPos
);
326 DEBG("---------OSUnserializeBinary(%p)\n", buffer
);
328 objsArray
= stackArray
= NULL
;
329 objsIdx
= objsCapacity
= 0;
330 stackIdx
= stackCapacity
= 0;
341 bufferPos
+= sizeof(*next
);
342 if (!(ok
= (bufferPos
<= bufferSize
))) {
347 len
= (key
& kOSSerializeDataMask
);
348 wordLen
= (len
+ 3) >> 2;
349 end
= (0 != (kOSSerializeEndCollecton
& key
));
350 DEBG("key 0x%08x: 0x%04x, %d\n", key
, len
, end
);
352 newCollect
= isRef
= false;
353 o
= 0; newDict
= 0; newArray
= 0; newSet
= 0;
355 switch (kOSSerializeTypeMask
& key
) {
356 case kOSSerializeDictionary
:
357 o
= newDict
= OSDictionary::withCapacity(len
);
358 newCollect
= (len
!= 0);
360 case kOSSerializeArray
:
361 o
= newArray
= OSArray::withCapacity(len
);
362 newCollect
= (len
!= 0);
364 case kOSSerializeSet
:
365 o
= newSet
= OSSet::withCapacity(len
);
366 newCollect
= (len
!= 0);
369 case kOSSerializeObject
:
370 if (len
>= objsIdx
) {
377 case kOSSerializeNumber
:
378 bufferPos
+= sizeof(long long);
379 if (bufferPos
> bufferSize
) {
382 if ((len
!= 32) && (len
!= 64) && (len
!= 16) && (len
!= 8)) {
388 o
= OSNumber::withNumber(value
, len
);
392 case kOSSerializeSymbol
:
393 bufferPos
+= (wordLen
* sizeof(uint32_t));
394 if (bufferPos
> bufferSize
) {
400 if (0 != ((const char *)next
)[len
- 1]) {
403 o
= (OSObject
*) OSSymbol::withCString((const char *) next
);
407 case kOSSerializeString
:
408 bufferPos
+= (wordLen
* sizeof(uint32_t));
409 if (bufferPos
> bufferSize
) {
412 o
= OSString::withStringOfLength((const char *) next
, len
);
416 case kOSSerializeData
:
417 bufferPos
+= (wordLen
* sizeof(uint32_t));
418 if (bufferPos
> bufferSize
) {
421 o
= OSData::withBytes(next
, len
);
425 case kOSSerializeBoolean
:
426 o
= (len
? kOSBooleanTrue
: kOSBooleanFalse
);
433 if (!(ok
= (o
!= 0))) {
438 setAtIndex(objs
, objsIdx
, o
);
448 sym
= (OSSymbol
*) o
;
451 sym
= OSDynamicCast(OSSymbol
, sym
);
452 if (!sym
&& (str
= OSDynamicCast(OSString
, str
))) {
453 sym
= const_cast<OSSymbol
*>(OSSymbol::withString(str
));
459 DEBG("%s = %s\n", sym
->getCStringNoCopy(), o
->getMetaClass()->getClassName());
461 ok
= dict
->setObject(sym
, o
);
463 if (sym
&& (sym
!= str
)) {
469 ok
= array
->setObject(o
);
471 ok
= set
->setObject(o
);
488 setAtIndex(stack
, stackIdx
, parent
);
492 DEBG("++stack[%d] %p\n", stackIdx
, parent
);
502 parent
= stackArray
[stackIdx
];
503 DEBG("--stack[%d] %p\n", stackIdx
, parent
);
515 if (!(dict
= OSDynamicCast(OSDictionary
, parent
))) {
516 if (!(array
= OSDynamicCast(OSArray
, parent
))) {
517 ok
= (0 != (set
= OSDynamicCast(OSSet
, parent
)));
522 DEBG("ret %p\n", result
);
529 for (len
= (result
!= 0); len
< objsIdx
; len
++) {
530 objsArray
[len
]->release();
532 kfree(objsArray
, objsCapacity
* sizeof(*objsArray
));
535 kfree(stackArray
, stackCapacity
* sizeof(*stackArray
));