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
;
94 tagNum
= OSNumber::withNumber(tag
, 32);
96 // add to tag dictionary
97 tags
->setObject((const OSSymbol
*) o
, tagNum
);
100 alignSize
= ((size
+ sizeof(key
) + 3) & ~3L);
101 newCapacity
= length
+ alignSize
;
102 if (newCapacity
>= capacity
)
104 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1) * capacityIncrement
;
105 if (newCapacity
< ensureCapacity(newCapacity
)) return (false);
110 endCollection
= false;
111 key
|= kOSSerializeEndCollecton
;
114 bcopy(&key
, &data
[length
], sizeof(key
));
115 bcopy(bits
, &data
[length
+ sizeof(key
)], size
);
121 bool OSSerialize::binarySerialize(const OSMetaClassBase
*o
)
137 tagNum
= (OSNumber
*)tags
->getObject((const OSSymbol
*) o
);
141 key
= (kOSSerializeObject
| tagNum
->unsigned32BitValue());
144 endCollection
= false;
145 key
|= kOSSerializeEndCollecton
;
147 ok
= addBinary(&key
, sizeof(key
));
151 if ((dict
= OSDynamicCast(OSDictionary
, o
)))
153 key
= (kOSSerializeDictionary
| dict
->count
);
154 ok
= addBinaryObject(o
, key
, NULL
, 0);
155 for (i
= 0; ok
&& (i
< dict
->count
);)
157 const OSSymbol
* dictKey
;
158 const OSMetaClassBase
* dictValue
;
159 const OSMetaClassBase
* nvalue
= 0;
162 dictKey
= dict
->dictionary
[i
-1].key
;
163 dictValue
= dict
->dictionary
[i
-1].value
;
166 dictValue
= nvalue
= (*editor
)(editRef
, this, dict
, dictKey
, dictValue
);
167 if (!dictValue
) dictValue
= dict
;
169 ok
= binarySerialize(dictKey
);
171 endCollection
= (i
== dict
->count
);
172 ok
= binarySerialize(dictValue
);
173 if (!ok
) ok
= dictValue
->serialize(this);
174 if (nvalue
) nvalue
->release();
175 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
178 else if ((array
= OSDynamicCast(OSArray
, o
)))
180 key
= (kOSSerializeArray
| array
->count
);
181 ok
= addBinaryObject(o
, key
, NULL
, 0);
182 for (i
= 0; ok
&& (i
< array
->count
);)
185 endCollection
= (i
== array
->count
);
186 ok
= binarySerialize(array
->array
[i
-1]);
187 if (!ok
) ok
= array
->array
[i
-1]->serialize(this);
188 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
191 else if ((set
= OSDynamicCast(OSSet
, o
)))
193 key
= (kOSSerializeSet
| set
->members
->count
);
194 ok
= addBinaryObject(o
, key
, NULL
, 0);
195 for (i
= 0; ok
&& (i
< set
->members
->count
);)
198 endCollection
= (i
== set
->members
->count
);
199 ok
= binarySerialize(set
->members
->array
[i
-1]);
200 if (!ok
) ok
= set
->members
->array
[i
-1]->serialize(this);
201 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
204 else if ((num
= OSDynamicCast(OSNumber
, o
)))
206 key
= (kOSSerializeNumber
| num
->size
);
207 ok
= addBinaryObject(o
, key
, &num
->value
, sizeof(num
->value
));
209 else if ((boo
= OSDynamicCast(OSBoolean
, o
)))
211 key
= (kOSSerializeBoolean
| (kOSBooleanTrue
== boo
));
212 ok
= addBinaryObject(o
, key
, NULL
, 0);
214 else if ((sym
= OSDynamicCast(OSSymbol
, o
)))
216 len
= (sym
->getLength() + 1);
217 key
= (kOSSerializeSymbol
| len
);
218 ok
= addBinaryObject(o
, key
, sym
->getCStringNoCopy(), len
);
220 else if ((str
= OSDynamicCast(OSString
, o
)))
222 len
= (str
->getLength() + 0);
223 key
= (kOSSerializeString
| len
);
224 ok
= addBinaryObject(o
, key
, str
->getCStringNoCopy(), len
);
226 else if ((data
= OSDynamicCast(OSData
, o
)))
228 len
= data
->getLength();
229 if (data
->reserved
&& data
->reserved
->disableSerialization
) len
= 0;
230 key
= (kOSSerializeData
| len
);
231 ok
= addBinaryObject(o
, key
, data
->getBytesNoCopy(), len
);
238 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
240 #define setAtIndex(v, idx, o) \
241 if (idx >= v##Capacity) \
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; \
248 bcopy(v##Array, nbuf, v##Capacity * sizeof(o)); \
249 kfree(v##Array, v##Capacity * sizeof(o)); \
252 v##Capacity = ncap; \
254 if (ok) v##Array[idx] = o;
256 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
259 OSUnserializeBinary(const char *buffer
, size_t bufferSize
, OSString
**errorString
)
261 OSObject
** objsArray
;
262 uint32_t objsCapacity
;
265 OSObject
** stackArray
;
266 uint32_t stackCapacity
;
274 OSDictionary
* newDict
;
282 const uint32_t * next
;
283 uint32_t key
, len
, wordLen
;
284 bool end
, newCollect
, isRef
;
285 unsigned long long value
;
288 if (errorString
) *errorString
= 0;
289 if (0 != strcmp(kOSSerializeBinarySignature
, buffer
)) return (NULL
);
290 if (3 & ((uintptr_t) buffer
)) return (NULL
);
291 if (bufferSize
< sizeof(kOSSerializeBinarySignature
)) return (NULL
);
292 bufferPos
= sizeof(kOSSerializeBinarySignature
);
293 next
= (typeof(next
)) (((uintptr_t) buffer
) + bufferPos
);
295 DEBG("---------OSUnserializeBinary(%p)\n", buffer
);
297 objsArray
= stackArray
= NULL
;
298 objsIdx
= objsCapacity
= 0;
299 stackIdx
= stackCapacity
= 0;
311 bufferPos
+= sizeof(*next
);
312 if (!(ok
= (bufferPos
<= bufferSize
))) break;
315 len
= (key
& kOSSerializeDataMask
);
316 wordLen
= (len
+ 3) >> 2;
317 end
= (0 != (kOSSerializeEndCollecton
& key
));
318 DEBG("key 0x%08x: 0x%04x, %d\n", key
, len
, end
);
320 newCollect
= isRef
= false;
321 o
= 0; newDict
= 0; newArray
= 0; newSet
= 0;
323 switch (kOSSerializeTypeMask
& key
)
325 case kOSSerializeDictionary
:
326 o
= newDict
= OSDictionary::withCapacity(len
);
327 newCollect
= (len
!= 0);
329 case kOSSerializeArray
:
330 o
= newArray
= OSArray::withCapacity(len
);
331 newCollect
= (len
!= 0);
333 case kOSSerializeSet
:
334 o
= newSet
= OSSet::withCapacity(len
);
335 newCollect
= (len
!= 0);
338 case kOSSerializeObject
:
339 if (len
>= objsIdx
) break;
345 case kOSSerializeNumber
:
346 bufferPos
+= sizeof(long long);
347 if (bufferPos
> bufferSize
) break;
351 o
= OSNumber::withNumber(value
, len
);
355 case kOSSerializeSymbol
:
356 bufferPos
+= (wordLen
* sizeof(uint32_t));
357 if (bufferPos
> bufferSize
) break;
358 if (0 != ((const char *)next
)[len
-1]) break;
359 o
= (OSObject
*) OSSymbol::withCString((const char *) next
);
363 case kOSSerializeString
:
364 bufferPos
+= (wordLen
* sizeof(uint32_t));
365 if (bufferPos
> bufferSize
) break;
366 o
= OSString::withStringOfLength((const char *) next
, len
);
370 case kOSSerializeData
:
371 bufferPos
+= (wordLen
* sizeof(uint32_t));
372 if (bufferPos
> bufferSize
) break;
373 o
= OSData::withBytes(next
, len
);
377 case kOSSerializeBoolean
:
378 o
= (len
? kOSBooleanTrue
: kOSBooleanFalse
);
385 if (!(ok
= (o
!= 0))) break;
389 setAtIndex(objs
, objsIdx
, o
);
398 DEBG("%s = %s\n", sym
->getCStringNoCopy(), o
->getMetaClass()->getClassName());
399 if (o
!= dict
) ok
= dict
->setObject(sym
, o
);
406 sym
= OSDynamicCast(OSSymbol
, o
);
407 if (!sym
&& (str
= OSDynamicCast(OSString
, o
)))
409 sym
= (OSSymbol
*) OSSymbol::withString(str
);
418 ok
= array
->setObject(o
);
423 ok
= set
->setObject(o
);
439 setAtIndex(stack
, stackIdx
, parent
);
442 DEBG("++stack[%d] %p\n", stackIdx
, parent
);
452 if (!stackIdx
) break;
453 parent
= stackArray
[stackIdx
];
454 DEBG("--stack[%d] %p\n", stackIdx
, parent
);
459 if (!(dict
= OSDynamicCast(OSDictionary
, parent
)))
461 if (!(array
= OSDynamicCast(OSArray
, parent
))) ok
= (0 != (set
= OSDynamicCast(OSSet
, parent
)));
465 DEBG("ret %p\n", result
);
467 if (objsCapacity
) kfree(objsArray
, objsCapacity
* sizeof(*objsArray
));
468 if (stackCapacity
) kfree(stackArray
, stackCapacity
* sizeof(*stackArray
));