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 alignSize
= ((size
+ 3) & ~3L);
73 newCapacity
= length
+ alignSize
;
74 if (newCapacity
>= capacity
)
76 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1) * capacityIncrement
;
77 if (newCapacity
> ensureCapacity(newCapacity
)) return (false);
80 bcopy(bits
, &data
[length
], size
);
86 bool OSSerialize::addBinaryObject(const OSMetaClassBase
* o
, uint32_t key
,
87 const void * bits
, size_t size
)
89 unsigned int newCapacity
;
95 alignSize
= ((size
+ sizeof(key
) + 3) & ~3L);
96 newCapacity
= length
+ alignSize
;
97 if (newCapacity
>= capacity
)
99 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1) * capacityIncrement
;
100 if (newCapacity
> ensureCapacity(newCapacity
)) return (false);
105 endCollection
= false;
106 key
|= kOSSerializeEndCollecton
;
109 bcopy(&key
, &data
[length
], sizeof(key
));
110 bcopy(bits
, &data
[length
+ sizeof(key
)], size
);
116 bool OSSerialize::binarySerialize(const OSMetaClassBase
*o
)
132 tagIdx
= tags
->getNextIndexOfObject(o
, 0);
136 key
= (kOSSerializeObject
| tagIdx
);
139 endCollection
= false;
140 key
|= kOSSerializeEndCollecton
;
142 ok
= addBinary(&key
, sizeof(key
));
146 if ((dict
= OSDynamicCast(OSDictionary
, o
)))
148 key
= (kOSSerializeDictionary
| dict
->count
);
149 ok
= addBinaryObject(o
, key
, NULL
, 0);
150 for (i
= 0; ok
&& (i
< dict
->count
);)
152 const OSSymbol
* dictKey
;
153 const OSMetaClassBase
* dictValue
;
154 const OSMetaClassBase
* nvalue
= 0;
156 dictKey
= dict
->dictionary
[i
].key
;
157 dictValue
= dict
->dictionary
[i
].value
;
161 dictValue
= nvalue
= (*editor
)(editRef
, this, dict
, dictKey
, dictValue
);
162 if (!dictValue
) dictValue
= dict
;
164 ok
= binarySerialize(dictKey
);
166 endCollection
= (i
== dict
->count
);
167 ok
= binarySerialize(dictValue
);
168 if (!ok
) ok
= dictValue
->serialize(this);
169 if (nvalue
) nvalue
->release();
170 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
173 else if ((array
= OSDynamicCast(OSArray
, o
)))
175 key
= (kOSSerializeArray
| array
->count
);
176 ok
= addBinaryObject(o
, key
, NULL
, 0);
177 for (i
= 0; ok
&& (i
< array
->count
);)
180 endCollection
= (i
== array
->count
);
181 ok
= binarySerialize(array
->array
[i
-1]);
182 if (!ok
) ok
= array
->array
[i
-1]->serialize(this);
183 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
186 else if ((set
= OSDynamicCast(OSSet
, o
)))
188 key
= (kOSSerializeSet
| set
->members
->count
);
189 ok
= addBinaryObject(o
, key
, NULL
, 0);
190 for (i
= 0; ok
&& (i
< set
->members
->count
);)
193 endCollection
= (i
== set
->members
->count
);
194 ok
= binarySerialize(set
->members
->array
[i
-1]);
195 if (!ok
) ok
= set
->members
->array
[i
-1]->serialize(this);
196 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
199 else if ((num
= OSDynamicCast(OSNumber
, o
)))
201 key
= (kOSSerializeNumber
| num
->size
);
202 ok
= addBinaryObject(o
, key
, &num
->value
, sizeof(num
->value
));
204 else if ((boo
= OSDynamicCast(OSBoolean
, o
)))
206 key
= (kOSSerializeBoolean
| (kOSBooleanTrue
== boo
));
207 ok
= addBinaryObject(o
, key
, NULL
, 0);
209 else if ((sym
= OSDynamicCast(OSSymbol
, o
)))
211 len
= (sym
->getLength() + 1);
212 key
= (kOSSerializeSymbol
| len
);
213 ok
= addBinaryObject(o
, key
, sym
->getCStringNoCopy(), len
);
215 else if ((str
= OSDynamicCast(OSString
, o
)))
217 len
= (str
->getLength() + 0);
218 key
= (kOSSerializeString
| len
);
219 ok
= addBinaryObject(o
, key
, str
->getCStringNoCopy(), len
);
221 else if ((ldata
= OSDynamicCast(OSData
, o
)))
223 len
= ldata
->getLength();
224 if (ldata
->reserved
&& ldata
->reserved
->disableSerialization
) len
= 0;
225 key
= (kOSSerializeData
| len
);
226 ok
= addBinaryObject(o
, key
, ldata
->getBytesNoCopy(), len
);
233 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
235 #define setAtIndex(v, idx, o) \
236 if (idx >= v##Capacity) \
238 if (v##Capacity >= v##CapacityMax) ok = false; \
241 uint32_t ncap = v##Capacity + 64; \
242 typeof(v##Array) nbuf = (typeof(v##Array)) kalloc_container(ncap * sizeof(o)); \
243 if (!nbuf) ok = false; \
248 bcopy(v##Array, nbuf, v##Capacity * sizeof(o)); \
249 kfree(v##Array, v##Capacity * sizeof(o)); \
252 v##Capacity = ncap; \
256 if (ok) v##Array[idx] = o;
258 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
261 OSUnserializeBinary(const char *buffer
, size_t bufferSize
, OSString
**errorString
)
263 OSObject
** objsArray
;
264 uint32_t objsCapacity
;
265 enum { objsCapacityMax
= 16*1024*1024 };
268 OSObject
** stackArray
;
269 uint32_t stackCapacity
;
270 enum { stackCapacityMax
= 64*1024 };
278 OSDictionary
* newDict
;
286 const uint32_t * next
;
287 uint32_t key
, len
, wordLen
;
288 bool end
, newCollect
, isRef
;
289 unsigned long long value
;
292 if (errorString
) *errorString
= 0;
293 if (bufferSize
< sizeof(kOSSerializeBinarySignature
)) return (NULL
);
294 if (0 != strcmp(kOSSerializeBinarySignature
, buffer
)) return (NULL
);
295 if (3 & ((uintptr_t) buffer
)) return (NULL
);
296 bufferPos
= sizeof(kOSSerializeBinarySignature
);
297 next
= (typeof(next
)) (((uintptr_t) buffer
) + bufferPos
);
299 DEBG("---------OSUnserializeBinary(%p)\n", buffer
);
301 objsArray
= stackArray
= NULL
;
302 objsIdx
= objsCapacity
= 0;
303 stackIdx
= stackCapacity
= 0;
315 bufferPos
+= sizeof(*next
);
316 if (!(ok
= (bufferPos
<= bufferSize
))) break;
319 len
= (key
& kOSSerializeDataMask
);
320 wordLen
= (len
+ 3) >> 2;
321 end
= (0 != (kOSSerializeEndCollecton
& key
));
322 DEBG("key 0x%08x: 0x%04x, %d\n", key
, len
, end
);
324 newCollect
= isRef
= false;
325 o
= 0; newDict
= 0; newArray
= 0; newSet
= 0;
327 switch (kOSSerializeTypeMask
& key
)
329 case kOSSerializeDictionary
:
330 o
= newDict
= OSDictionary::withCapacity(len
);
331 newCollect
= (len
!= 0);
333 case kOSSerializeArray
:
334 o
= newArray
= OSArray::withCapacity(len
);
335 newCollect
= (len
!= 0);
337 case kOSSerializeSet
:
338 o
= newSet
= OSSet::withCapacity(len
);
339 newCollect
= (len
!= 0);
342 case kOSSerializeObject
:
343 if (len
>= objsIdx
) break;
348 case kOSSerializeNumber
:
349 bufferPos
+= sizeof(long long);
350 if (bufferPos
> bufferSize
) break;
351 if ((len
!= 32) && (len
!= 64) && (len
!= 16) && (len
!= 8)) break;
355 o
= OSNumber::withNumber(value
, len
);
359 case kOSSerializeSymbol
:
360 bufferPos
+= (wordLen
* sizeof(uint32_t));
361 if (bufferPos
> bufferSize
) break;
363 if (0 != ((const char *)next
)[len
-1]) break;
364 o
= (OSObject
*) OSSymbol::withCString((const char *) next
);
368 case kOSSerializeString
:
369 bufferPos
+= (wordLen
* sizeof(uint32_t));
370 if (bufferPos
> bufferSize
) break;
371 o
= OSString::withStringOfLength((const char *) next
, len
);
375 case kOSSerializeData
:
376 bufferPos
+= (wordLen
* sizeof(uint32_t));
377 if (bufferPos
> bufferSize
) break;
378 o
= OSData::withBytes(next
, len
);
382 case kOSSerializeBoolean
:
383 o
= (len
? kOSBooleanTrue
: kOSBooleanFalse
);
390 if (!(ok
= (o
!= 0))) break;
394 setAtIndex(objs
, objsIdx
, o
);
405 if (!sym
) sym
= (OSSymbol
*) o
;
409 sym
= OSDynamicCast(OSSymbol
, sym
);
410 if (!sym
&& (str
= OSDynamicCast(OSString
, str
)))
412 sym
= (OSSymbol
*) OSSymbol::withString(str
);
416 DEBG("%s = %s\n", sym
->getCStringNoCopy(), o
->getMetaClass()->getClassName());
417 if (o
!= dict
) ok
= dict
->setObject(sym
, o
);
418 if (sym
&& (sym
!= str
)) sym
->release();
422 else if (array
) ok
= array
->setObject(o
);
423 else if (set
) ok
= set
->setObject(o
);
424 else if (result
) ok
= false;
438 setAtIndex(stack
, stackIdx
, parent
);
441 DEBG("++stack[%d] %p\n", stackIdx
, parent
);
451 if (!stackIdx
) break;
452 parent
= stackArray
[stackIdx
];
453 DEBG("--stack[%d] %p\n", stackIdx
, parent
);
458 if (!(dict
= OSDynamicCast(OSDictionary
, parent
)))
460 if (!(array
= OSDynamicCast(OSArray
, parent
))) ok
= (0 != (set
= OSDynamicCast(OSSet
, parent
)));
464 DEBG("ret %p\n", result
);
470 for (len
= (result
!= 0); len
< objsIdx
; len
++) objsArray
[len
]->release();
471 kfree(objsArray
, objsCapacity
* sizeof(*objsArray
));
473 if (stackCapacity
) kfree(stackArray
, stackCapacity
* sizeof(*stackArray
));