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 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
47 OSSerialize
*OSSerialize::binaryWithCapacity(unsigned int inCapacity
,
48 Editor editor
, void * reference
)
52 if (inCapacity
< sizeof(uint32_t)) return (0);
53 me
= OSSerialize::withCapacity(inCapacity
);
57 me
->endCollection
= true;
59 me
->editRef
= reference
;
61 bcopy(kOSSerializeBinarySignature
, &me
->data
[0], sizeof(kOSSerializeBinarySignature
));
62 me
->length
= sizeof(kOSSerializeBinarySignature
);
67 bool OSSerialize::addBinary(const void * bits
, size_t size
)
69 unsigned int newCapacity
;
72 if (os_add_overflow(size
, 3, &alignSize
)) return (false);
74 if (os_add_overflow(length
, alignSize
, &newCapacity
)) return (false);
75 if (newCapacity
>= capacity
)
77 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1) * capacityIncrement
;
78 if (newCapacity
> ensureCapacity(newCapacity
)) return (false);
81 bcopy(bits
, &data
[length
], size
);
87 bool OSSerialize::addBinaryObject(const OSMetaClassBase
* o
, uint32_t key
,
88 const void * bits
, size_t size
)
90 unsigned int newCapacity
;
96 if (os_add3_overflow(size
, sizeof(key
), 3, &alignSize
)) return (false);
98 if (os_add_overflow(length
, alignSize
, &newCapacity
)) return (false);
99 if (newCapacity
>= capacity
)
101 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1) * capacityIncrement
;
102 if (newCapacity
> ensureCapacity(newCapacity
)) return (false);
107 endCollection
= false;
108 key
|= kOSSerializeEndCollecton
;
111 bcopy(&key
, &data
[length
], sizeof(key
));
112 bcopy(bits
, &data
[length
+ sizeof(key
)], size
);
118 bool OSSerialize::binarySerialize(const OSMetaClassBase
*o
)
134 tagIdx
= tags
->getNextIndexOfObject(o
, 0);
138 key
= (kOSSerializeObject
| tagIdx
);
141 endCollection
= false;
142 key
|= kOSSerializeEndCollecton
;
144 ok
= addBinary(&key
, sizeof(key
));
148 if ((dict
= OSDynamicCast(OSDictionary
, o
)))
150 key
= (kOSSerializeDictionary
| dict
->count
);
151 ok
= addBinaryObject(o
, key
, NULL
, 0);
152 for (i
= 0; ok
&& (i
< dict
->count
);)
154 const OSSymbol
* dictKey
;
155 const OSMetaClassBase
* dictValue
;
156 const OSMetaClassBase
* nvalue
= 0;
158 dictKey
= dict
->dictionary
[i
].key
;
159 dictValue
= dict
->dictionary
[i
].value
;
163 dictValue
= nvalue
= (*editor
)(editRef
, this, dict
, dictKey
, dictValue
);
164 if (!dictValue
) dictValue
= dict
;
166 ok
= binarySerialize(dictKey
);
168 endCollection
= (i
== dict
->count
);
169 ok
= binarySerialize(dictValue
);
170 if (!ok
) ok
= dictValue
->serialize(this);
171 if (nvalue
) nvalue
->release();
172 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
175 else if ((array
= OSDynamicCast(OSArray
, o
)))
177 key
= (kOSSerializeArray
| array
->count
);
178 ok
= addBinaryObject(o
, key
, NULL
, 0);
179 for (i
= 0; ok
&& (i
< array
->count
);)
182 endCollection
= (i
== array
->count
);
183 ok
= binarySerialize(array
->array
[i
-1]);
184 if (!ok
) ok
= array
->array
[i
-1]->serialize(this);
185 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
188 else if ((set
= OSDynamicCast(OSSet
, o
)))
190 key
= (kOSSerializeSet
| set
->members
->count
);
191 ok
= addBinaryObject(o
, key
, NULL
, 0);
192 for (i
= 0; ok
&& (i
< set
->members
->count
);)
195 endCollection
= (i
== set
->members
->count
);
196 ok
= binarySerialize(set
->members
->array
[i
-1]);
197 if (!ok
) ok
= set
->members
->array
[i
-1]->serialize(this);
198 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
201 else if ((num
= OSDynamicCast(OSNumber
, o
)))
203 key
= (kOSSerializeNumber
| num
->size
);
204 ok
= addBinaryObject(o
, key
, &num
->value
, sizeof(num
->value
));
206 else if ((boo
= OSDynamicCast(OSBoolean
, o
)))
208 key
= (kOSSerializeBoolean
| (kOSBooleanTrue
== boo
));
209 ok
= addBinaryObject(o
, key
, NULL
, 0);
211 else if ((sym
= OSDynamicCast(OSSymbol
, o
)))
213 len
= (sym
->getLength() + 1);
214 key
= (kOSSerializeSymbol
| len
);
215 ok
= addBinaryObject(o
, key
, sym
->getCStringNoCopy(), len
);
217 else if ((str
= OSDynamicCast(OSString
, o
)))
219 len
= (str
->getLength() + 0);
220 key
= (kOSSerializeString
| len
);
221 ok
= addBinaryObject(o
, key
, str
->getCStringNoCopy(), len
);
223 else if ((ldata
= OSDynamicCast(OSData
, o
)))
225 len
= ldata
->getLength();
226 if (ldata
->reserved
&& ldata
->reserved
->disableSerialization
) len
= 0;
227 key
= (kOSSerializeData
| len
);
228 ok
= addBinaryObject(o
, key
, ldata
->getBytesNoCopy(), len
);
235 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
237 #define setAtIndex(v, idx, o) \
238 if (idx >= v##Capacity) \
240 if (v##Capacity >= v##CapacityMax) ok = false; \
243 uint32_t ncap = v##Capacity + 64; \
244 typeof(v##Array) nbuf = (typeof(v##Array)) kalloc_container(ncap * sizeof(o)); \
245 if (!nbuf) ok = false; \
250 bcopy(v##Array, nbuf, v##Capacity * sizeof(o)); \
251 kfree(v##Array, v##Capacity * sizeof(o)); \
254 v##Capacity = ncap; \
258 if (ok) v##Array[idx] = o;
260 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
263 OSUnserializeBinary(const char *buffer
, size_t bufferSize
, OSString
**errorString
)
265 OSObject
** objsArray
;
266 uint32_t objsCapacity
;
267 enum { objsCapacityMax
= 16*1024*1024 };
270 OSObject
** stackArray
;
271 uint32_t stackCapacity
;
272 enum { stackCapacityMax
= 64 };
280 OSDictionary
* newDict
;
288 const uint32_t * next
;
289 uint32_t key
, len
, wordLen
;
290 bool end
, newCollect
, isRef
;
291 unsigned long long value
;
294 if (errorString
) *errorString
= 0;
295 if (bufferSize
< sizeof(kOSSerializeBinarySignature
)) return (NULL
);
296 if (0 != strcmp(kOSSerializeBinarySignature
, buffer
)) return (NULL
);
297 if (3 & ((uintptr_t) buffer
)) return (NULL
);
298 bufferPos
= sizeof(kOSSerializeBinarySignature
);
299 next
= (typeof(next
)) (((uintptr_t) buffer
) + bufferPos
);
301 DEBG("---------OSUnserializeBinary(%p)\n", buffer
);
303 objsArray
= stackArray
= NULL
;
304 objsIdx
= objsCapacity
= 0;
305 stackIdx
= stackCapacity
= 0;
317 bufferPos
+= sizeof(*next
);
318 if (!(ok
= (bufferPos
<= bufferSize
))) break;
321 len
= (key
& kOSSerializeDataMask
);
322 wordLen
= (len
+ 3) >> 2;
323 end
= (0 != (kOSSerializeEndCollecton
& key
));
324 DEBG("key 0x%08x: 0x%04x, %d\n", key
, len
, end
);
326 newCollect
= isRef
= false;
327 o
= 0; newDict
= 0; newArray
= 0; newSet
= 0;
329 switch (kOSSerializeTypeMask
& key
)
331 case kOSSerializeDictionary
:
332 o
= newDict
= OSDictionary::withCapacity(len
);
333 newCollect
= (len
!= 0);
335 case kOSSerializeArray
:
336 o
= newArray
= OSArray::withCapacity(len
);
337 newCollect
= (len
!= 0);
339 case kOSSerializeSet
:
340 o
= newSet
= OSSet::withCapacity(len
);
341 newCollect
= (len
!= 0);
344 case kOSSerializeObject
:
345 if (len
>= objsIdx
) break;
350 case kOSSerializeNumber
:
351 bufferPos
+= sizeof(long long);
352 if (bufferPos
> bufferSize
) break;
353 if ((len
!= 32) && (len
!= 64) && (len
!= 16) && (len
!= 8)) break;
357 o
= OSNumber::withNumber(value
, len
);
361 case kOSSerializeSymbol
:
362 bufferPos
+= (wordLen
* sizeof(uint32_t));
363 if (bufferPos
> bufferSize
) break;
365 if (0 != ((const char *)next
)[len
-1]) break;
366 o
= (OSObject
*) OSSymbol::withCString((const char *) next
);
370 case kOSSerializeString
:
371 bufferPos
+= (wordLen
* sizeof(uint32_t));
372 if (bufferPos
> bufferSize
) break;
373 o
= OSString::withStringOfLength((const char *) next
, len
);
377 case kOSSerializeData
:
378 bufferPos
+= (wordLen
* sizeof(uint32_t));
379 if (bufferPos
> bufferSize
) break;
380 o
= OSData::withBytes(next
, len
);
384 case kOSSerializeBoolean
:
385 o
= (len
? kOSBooleanTrue
: kOSBooleanFalse
);
392 if (!(ok
= (o
!= 0))) break;
396 setAtIndex(objs
, objsIdx
, o
);
407 if (!sym
) sym
= (OSSymbol
*) o
;
411 sym
= OSDynamicCast(OSSymbol
, sym
);
412 if (!sym
&& (str
= OSDynamicCast(OSString
, str
)))
414 sym
= const_cast<OSSymbol
*>(OSSymbol::withString(str
));
418 DEBG("%s = %s\n", sym
->getCStringNoCopy(), o
->getMetaClass()->getClassName());
419 if (o
!= dict
) ok
= dict
->setObject(sym
, o
);
420 if (sym
&& (sym
!= str
)) sym
->release();
424 else if (array
) ok
= array
->setObject(o
);
425 else if (set
) ok
= set
->setObject(o
);
426 else if (result
) ok
= false;
439 setAtIndex(stack
, stackIdx
, parent
);
441 DEBG("++stack[%d] %p\n", stackIdx
, parent
);
453 parent
= stackArray
[stackIdx
];
454 DEBG("--stack[%d] %p\n", stackIdx
, parent
);
462 if (!(dict
= OSDynamicCast(OSDictionary
, parent
)))
464 if (!(array
= OSDynamicCast(OSArray
, parent
))) ok
= (0 != (set
= OSDynamicCast(OSSet
, parent
)));
468 DEBG("ret %p\n", result
);
474 for (len
= (result
!= 0); len
< objsIdx
; len
++) objsArray
[len
]->release();
475 kfree(objsArray
, objsCapacity
* sizeof(*objsArray
));
477 if (stackCapacity
) kfree(stackArray
, stackCapacity
* sizeof(*stackArray
));