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::setIndexed(bool index __unused
)
104 assert(index
&& !indexData
);
105 indexData
= OSData::withCapacity(256);
110 OSSerialize::addBinaryObject(const OSMetaClassBase
* o
, uint32_t key
,
111 const void * bits
, size_t size
,
112 uint32_t * startCollection
)
114 unsigned int newCapacity
;
121 headerSize
= sizeof(key
);
123 uint32_t offset
= length
;
124 if (startCollection
) {
125 *startCollection
= offset
;
126 headerSize
+= sizeof(uint32_t);
128 offset
/= sizeof(uint32_t);
129 indexData
->appendBytes(&offset
, sizeof(offset
));
132 if (os_add3_overflow(size
, headerSize
, 3, &alignSize
)) {
136 if (os_add_overflow(length
, alignSize
, &newCapacity
)) {
139 if (newCapacity
>= capacity
) {
140 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1) * capacityIncrement
;
141 if (newCapacity
< capacity
) {
144 if (newCapacity
> ensureCapacity(newCapacity
)) {
150 endCollection
= false;
151 key
|= kOSSerializeEndCollecton
;
154 bcopy(&key
, &data
[length
], sizeof(key
));
155 bcopy(bits
, &data
[length
+ headerSize
], size
);
162 OSSerialize::endBinaryCollection(uint32_t startCollection
)
170 assert(length
> startCollection
);
171 if (length
<= startCollection
) {
175 clength
= length
- startCollection
;
176 assert(!(clength
& 3));
177 clength
/= sizeof(uint32_t);
179 memcpy(&data
[startCollection
+ sizeof(uint32_t)], &clength
, sizeof(clength
));
183 OSSerialize::binarySerialize(const OSMetaClassBase
*o
)
188 ok
= binarySerializeInternal(o
);
194 header
= indexData
->getLength() / sizeof(uint32_t);
195 assert(header
<= kOSSerializeDataMask
);
197 header
|= kOSSerializeIndexedBinarySignature
;
199 memcpy(&data
[0], &header
, sizeof(header
));
206 OSSerialize::binarySerializeInternal(const OSMetaClassBase
*o
)
218 uint32_t i
, key
, startCollection
;
222 tagIdx
= tags
->getNextIndexOfObject(o
, 0);
226 assert(indexData
->getLength() > (tagIdx
* sizeof(uint32_t)));
227 tagIdx
= ((const uint32_t *)indexData
->getBytesNoCopy())[tagIdx
];
228 assert(tagIdx
<= kOSSerializeDataMask
);
230 key
= (kOSSerializeObject
| tagIdx
);
232 endCollection
= false;
233 key
|= kOSSerializeEndCollecton
;
235 ok
= addBinary(&key
, sizeof(key
));
239 if ((dict
= OSDynamicCast(OSDictionary
, o
))) {
240 key
= (kOSSerializeDictionary
| dict
->count
);
241 ok
= addBinaryObject(o
, key
, NULL
, 0, &startCollection
);
242 for (i
= 0; ok
&& (i
< dict
->count
);) {
243 const OSSymbol
* dictKey
;
244 const OSMetaClassBase
* dictValue
;
245 const OSMetaClassBase
* nvalue
= NULL
;
247 dictKey
= dict
->dictionary
[i
].key
;
248 dictValue
= dict
->dictionary
[i
].value
;
251 dictValue
= nvalue
= (*editor
)(editRef
, this, dict
, dictKey
, dictValue
);
256 ok
= binarySerialize(dictKey
);
260 endCollection
= (i
== dict
->count
);
261 ok
= binarySerialize(dictValue
);
263 ok
= dictValue
->serialize(this);
268 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
270 endBinaryCollection(startCollection
);
271 } else if ((array
= OSDynamicCast(OSArray
, o
))) {
272 key
= (kOSSerializeArray
| array
->count
);
273 ok
= addBinaryObject(o
, key
, NULL
, 0, &startCollection
);
274 for (i
= 0; ok
&& (i
< array
->count
);) {
276 endCollection
= (i
== array
->count
);
277 ok
= binarySerialize(array
->array
[i
- 1]);
279 ok
= array
->array
[i
- 1]->serialize(this);
281 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
283 endBinaryCollection(startCollection
);
284 } else if ((set
= OSDynamicCast(OSSet
, o
))) {
285 key
= (kOSSerializeSet
| set
->members
->count
);
286 ok
= addBinaryObject(o
, key
, NULL
, 0, &startCollection
);
287 for (i
= 0; ok
&& (i
< set
->members
->count
);) {
289 endCollection
= (i
== set
->members
->count
);
290 ok
= binarySerialize(set
->members
->array
[i
- 1]);
292 ok
= set
->members
->array
[i
- 1]->serialize(this);
294 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
296 endBinaryCollection(startCollection
);
297 } else if ((num
= OSDynamicCast(OSNumber
, o
))) {
298 key
= (kOSSerializeNumber
| num
->size
);
299 ok
= addBinaryObject(o
, key
, &num
->value
, sizeof(num
->value
), NULL
);
300 } else if ((boo
= OSDynamicCast(OSBoolean
, o
))) {
301 key
= (kOSSerializeBoolean
| (kOSBooleanTrue
== boo
));
302 ok
= addBinaryObject(o
, key
, NULL
, 0, NULL
);
303 } else if ((sym
= OSDynamicCast(OSSymbol
, o
))) {
304 len
= (sym
->getLength() + 1);
305 key
= (kOSSerializeSymbol
| len
);
306 ok
= addBinaryObject(o
, key
, sym
->getCStringNoCopy(), len
, NULL
);
307 } else if ((str
= OSDynamicCast(OSString
, o
))) {
308 len
= (str
->getLength() + ((indexData
!= NULL
) ? 1 : 0));
309 key
= (kOSSerializeString
| len
);
310 ok
= addBinaryObject(o
, key
, str
->getCStringNoCopy(), len
, NULL
);
311 } else if ((ldata
= OSDynamicCast(OSData
, o
))) {
312 len
= ldata
->getLength();
313 if (ldata
->reserved
&& ldata
->reserved
->disableSerialization
) {
316 key
= (kOSSerializeData
| len
);
317 ok
= addBinaryObject(o
, key
, ldata
->getBytesNoCopy(), len
, NULL
);
325 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
327 #define setAtIndex(v, idx, o) \
328 if (idx >= v##Capacity) \
330 if (v##Capacity >= v##CapacityMax) ok = false; \
333 uint32_t ncap = v##Capacity + 64; \
334 typeof(v##Array) nbuf = (typeof(v##Array)) kalloc_container(ncap * sizeof(o)); \
335 if (!nbuf) ok = false; \
340 bcopy(v##Array, nbuf, v##Capacity * sizeof(o)); \
341 kfree(v##Array, v##Capacity * sizeof(o)); \
344 v##Capacity = ncap; \
348 if (ok) v##Array[idx] = o;
350 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
353 OSUnserializeBinary(const char *buffer
, size_t bufferSize
, OSString
**errorString
)
355 OSObject
** objsArray
;
356 uint32_t objsCapacity
;
357 enum { objsCapacityMax
= 16 * 1024 * 1024 };
360 OSObject
** stackArray
;
361 uint32_t stackCapacity
;
362 enum { stackCapacityMax
= 64 };
370 OSDictionary
* newDict
;
378 const uint32_t * next
;
379 uint32_t key
, len
, wordLen
, length
;
380 bool end
, newCollect
, isRef
;
381 unsigned long long value
;
382 bool ok
, indexed
, hasLength
;
389 if (bufferSize
< sizeof(kOSSerializeBinarySignature
)) {
392 if (kOSSerializeIndexedBinarySignature
== (((const uint8_t *) buffer
)[0])) {
394 } else if (0 != strcmp(kOSSerializeBinarySignature
, buffer
)) {
397 if (3 & ((uintptr_t) buffer
)) {
401 bufferPos
= sizeof(kOSSerializeBinarySignature
);
402 next
= (typeof(next
))(((uintptr_t) buffer
) + bufferPos
);
404 DEBG("---------OSUnserializeBinary(%p)\n", buffer
);
406 objsArray
= stackArray
= NULL
;
407 objsIdx
= objsCapacity
= 0;
408 stackIdx
= stackCapacity
= 0;
419 bufferPos
+= sizeof(*next
);
420 if (!(ok
= (bufferPos
<= bufferSize
))) {
426 len
= (key
& kOSSerializeDataMask
);
427 wordLen
= (len
+ 3) >> 2;
428 end
= (0 != (kOSSerializeEndCollecton
& key
));
429 DEBG("key 0x%08x: 0x%04x, %d\n", key
, len
, end
);
431 newCollect
= isRef
= hasLength
= false;
432 o
= NULL
; newDict
= NULL
; newArray
= NULL
; newSet
= NULL
;
434 switch (kOSSerializeTypeMask
& key
) {
435 case kOSSerializeDictionary
:
436 o
= newDict
= OSDictionary::withCapacity(len
);
437 newCollect
= (len
!= 0);
440 case kOSSerializeArray
:
441 o
= newArray
= OSArray::withCapacity(len
);
442 newCollect
= (len
!= 0);
445 case kOSSerializeSet
:
446 o
= newSet
= OSSet::withCapacity(len
);
447 newCollect
= (len
!= 0);
451 case kOSSerializeObject
:
452 if (len
>= objsIdx
) {
459 case kOSSerializeNumber
:
460 bufferPos
+= sizeof(long long);
461 if (bufferPos
> bufferSize
) {
464 if ((len
!= 32) && (len
!= 64) && (len
!= 16) && (len
!= 8)) {
470 o
= OSNumber::withNumber(value
, len
);
474 case kOSSerializeSymbol
:
475 bufferPos
+= (wordLen
* sizeof(uint32_t));
476 if (bufferPos
> bufferSize
) {
482 if (0 != ((const char *)next
)[len
- 1]) {
485 o
= (OSObject
*) OSSymbol::withCString((const char *) next
);
489 case kOSSerializeString
:
490 bufferPos
+= (wordLen
* sizeof(uint32_t));
491 if (bufferPos
> bufferSize
) {
494 o
= OSString::withStringOfLength((const char *) next
, len
);
498 case kOSSerializeData
:
499 bufferPos
+= (wordLen
* sizeof(uint32_t));
500 if (bufferPos
> bufferSize
) {
503 o
= OSData::withBytes(next
, len
);
507 case kOSSerializeBoolean
:
508 o
= (len
? kOSBooleanTrue
: kOSBooleanFalse
);
515 if (!(ok
= (o
!= NULL
))) {
520 bufferPos
+= sizeof(*next
);
521 if (!(ok
= (bufferPos
<= bufferSize
))) {
528 setAtIndex(objs
, objsIdx
, o
);
538 sym
= (OSSymbol
*) o
;
541 sym
= OSDynamicCast(OSSymbol
, sym
);
542 if (!sym
&& (str
= OSDynamicCast(OSString
, str
))) {
543 sym
= const_cast<OSSymbol
*>(OSSymbol::withString(str
));
549 DEBG("%s = %s\n", sym
->getCStringNoCopy(), o
->getMetaClass()->getClassName());
551 ok
= dict
->setObject(sym
, o
);
553 if (sym
&& (sym
!= str
)) {
559 ok
= array
->setObject(o
);
561 ok
= set
->setObject(o
);
578 setAtIndex(stack
, stackIdx
, parent
);
582 DEBG("++stack[%d] %p\n", stackIdx
, parent
);
592 parent
= stackArray
[stackIdx
];
593 DEBG("--stack[%d] %p\n", stackIdx
, parent
);
605 if (!(dict
= OSDynamicCast(OSDictionary
, parent
))) {
606 if (!(array
= OSDynamicCast(OSArray
, parent
))) {
607 ok
= (NULL
!= (set
= OSDynamicCast(OSSet
, parent
)));
612 DEBG("ret %p\n", result
);
619 for (len
= (result
!= NULL
); len
< objsIdx
; len
++) {
620 objsArray
[len
]->release();
622 kfree(objsArray
, objsCapacity
* sizeof(*objsArray
));
625 kfree(stackArray
, stackCapacity
* sizeof(*stackArray
));