]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSSerializeBinary.cpp
xnu-3247.1.106.tar.gz
[apple/xnu.git] / libkern / c++ / OSSerializeBinary.cpp
1 /*
2 * Copyright (c) 2014 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30 #include <libkern/c++/OSContainers.h>
31 #include <libkern/c++/OSLib.h>
32 #include <libkern/c++/OSDictionary.h>
33 #include <libkern/OSSerializeBinary.h>
34
35 #include <IOKit/IOLib.h>
36
37 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
38
39 #if 0
40 #define DEBG(fmt, args...) { kprintf(fmt, args); }
41 #else
42 #define DEBG(fmt, args...) {}
43 #endif
44
45 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
46
47 OSSerialize *OSSerialize::binaryWithCapacity(unsigned int inCapacity,
48 Editor editor, void * reference)
49 {
50 OSSerialize *me;
51
52 if (inCapacity < sizeof(uint32_t)) return (0);
53 me = OSSerialize::withCapacity(inCapacity);
54 if (!me) return (0);
55
56 me->binary = true;
57 me->endCollection = true;
58 me->editor = editor;
59 me->editRef = reference;
60
61 bcopy(kOSSerializeBinarySignature, &me->data[0], sizeof(kOSSerializeBinarySignature));
62 me->length = sizeof(kOSSerializeBinarySignature);
63
64 return (me);
65 }
66
67 bool OSSerialize::addBinary(const void * bits, size_t size)
68 {
69 unsigned int newCapacity;
70 size_t alignSize;
71
72 alignSize = ((size + 3) & ~3L);
73 newCapacity = length + alignSize;
74 if (newCapacity >= capacity)
75 {
76 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) * capacityIncrement;
77 if (newCapacity < ensureCapacity(newCapacity)) return (false);
78 }
79
80 bcopy(bits, &data[length], size);
81 length += alignSize;
82
83 return (true);
84 }
85
86 bool OSSerialize::addBinaryObject(const OSMetaClassBase * o, uint32_t key,
87 const void * bits, size_t size)
88 {
89 unsigned int newCapacity;
90 size_t alignSize;
91 OSNumber * tagNum;
92
93 // build a tag
94 tagNum = OSNumber::withNumber(tag, 32);
95 tag++;
96 // add to tag dictionary
97 tags->setObject((const OSSymbol *) o, tagNum);
98 tagNum->release();
99
100 alignSize = ((size + sizeof(key) + 3) & ~3L);
101 newCapacity = length + alignSize;
102 if (newCapacity >= capacity)
103 {
104 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) * capacityIncrement;
105 if (newCapacity < ensureCapacity(newCapacity)) return (false);
106 }
107
108 if (endCollection)
109 {
110 endCollection = false;
111 key |= kOSSerializeEndCollecton;
112 }
113
114 bcopy(&key, &data[length], sizeof(key));
115 bcopy(bits, &data[length + sizeof(key)], size);
116 length += alignSize;
117
118 return (true);
119 }
120
121 bool OSSerialize::binarySerialize(const OSMetaClassBase *o)
122 {
123 OSDictionary * dict;
124 OSArray * array;
125 OSSet * set;
126 OSNumber * num;
127 OSSymbol * sym;
128 OSString * str;
129 OSData * data;
130 OSBoolean * boo;
131
132 OSNumber * tagNum;
133 uint32_t i, key;
134 size_t len;
135 bool ok;
136
137 tagNum = (OSNumber *)tags->getObject((const OSSymbol *) o);
138 // does it exist?
139 if (tagNum)
140 {
141 key = (kOSSerializeObject | tagNum->unsigned32BitValue());
142 if (endCollection)
143 {
144 endCollection = false;
145 key |= kOSSerializeEndCollecton;
146 }
147 ok = addBinary(&key, sizeof(key));
148 return (ok);
149 }
150
151 if ((dict = OSDynamicCast(OSDictionary, o)))
152 {
153 key = (kOSSerializeDictionary | dict->count);
154 ok = addBinaryObject(o, key, NULL, 0);
155 for (i = 0; ok && (i < dict->count);)
156 {
157 const OSSymbol * dictKey;
158 const OSMetaClassBase * dictValue;
159 const OSMetaClassBase * nvalue = 0;
160
161 i++;
162 dictKey = dict->dictionary[i-1].key;
163 dictValue = dict->dictionary[i-1].value;
164 if (editor)
165 {
166 dictValue = nvalue = (*editor)(editRef, this, dict, dictKey, dictValue);
167 if (!dictValue) dictValue = dict;
168 }
169 ok = binarySerialize(dictKey);
170 if (!ok) break;
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);
176 }
177 }
178 else if ((array = OSDynamicCast(OSArray, o)))
179 {
180 key = (kOSSerializeArray | array->count);
181 ok = addBinaryObject(o, key, NULL, 0);
182 for (i = 0; ok && (i < array->count);)
183 {
184 i++;
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);
189 }
190 }
191 else if ((set = OSDynamicCast(OSSet, o)))
192 {
193 key = (kOSSerializeSet | set->members->count);
194 ok = addBinaryObject(o, key, NULL, 0);
195 for (i = 0; ok && (i < set->members->count);)
196 {
197 i++;
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);
202 }
203 }
204 else if ((num = OSDynamicCast(OSNumber, o)))
205 {
206 key = (kOSSerializeNumber | num->size);
207 ok = addBinaryObject(o, key, &num->value, sizeof(num->value));
208 }
209 else if ((boo = OSDynamicCast(OSBoolean, o)))
210 {
211 key = (kOSSerializeBoolean | (kOSBooleanTrue == boo));
212 ok = addBinaryObject(o, key, NULL, 0);
213 }
214 else if ((sym = OSDynamicCast(OSSymbol, o)))
215 {
216 len = (sym->getLength() + 1);
217 key = (kOSSerializeSymbol | len);
218 ok = addBinaryObject(o, key, sym->getCStringNoCopy(), len);
219 }
220 else if ((str = OSDynamicCast(OSString, o)))
221 {
222 len = (str->getLength() + 0);
223 key = (kOSSerializeString | len);
224 ok = addBinaryObject(o, key, str->getCStringNoCopy(), len);
225 }
226 else if ((data = OSDynamicCast(OSData, o)))
227 {
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);
232 }
233 else return (false);
234
235 return (ok);
236 }
237
238 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
239
240 #define setAtIndex(v, idx, o) \
241 if (idx >= v##Capacity) \
242 { \
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; \
246 if (v##Array) \
247 { \
248 bcopy(v##Array, nbuf, v##Capacity * sizeof(o)); \
249 kfree(v##Array, v##Capacity * sizeof(o)); \
250 } \
251 v##Array = nbuf; \
252 v##Capacity = ncap; \
253 } \
254 if (ok) v##Array[idx] = o;
255
256 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
257
258 OSObject *
259 OSUnserializeBinary(const char *buffer, size_t bufferSize, OSString **errorString)
260 {
261 OSObject ** objsArray;
262 uint32_t objsCapacity;
263 uint32_t objsIdx;
264
265 OSObject ** stackArray;
266 uint32_t stackCapacity;
267 uint32_t stackIdx;
268
269 OSObject * result;
270 OSObject * parent;
271 OSDictionary * dict;
272 OSArray * array;
273 OSSet * set;
274 OSDictionary * newDict;
275 OSArray * newArray;
276 OSSet * newSet;
277 OSObject * o;
278 OSSymbol * sym;
279 OSString * str;
280
281 size_t bufferPos;
282 const uint32_t * next;
283 uint32_t key, len, wordLen;
284 bool end, newCollect, isRef;
285 unsigned long long value;
286 bool ok;
287
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);
294
295 DEBG("---------OSUnserializeBinary(%p)\n", buffer);
296
297 objsArray = stackArray = NULL;
298 objsIdx = objsCapacity = 0;
299 stackIdx = stackCapacity = 0;
300
301 result = 0;
302 parent = 0;
303 dict = 0;
304 array = 0;
305 set = 0;
306 sym = 0;
307
308 ok = true;
309 while (ok)
310 {
311 bufferPos += sizeof(*next);
312 if (!(ok = (bufferPos <= bufferSize))) break;
313 key = *next++;
314
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);
319
320 newCollect = isRef = false;
321 o = 0; newDict = 0; newArray = 0; newSet = 0;
322
323 switch (kOSSerializeTypeMask & key)
324 {
325 case kOSSerializeDictionary:
326 o = newDict = OSDictionary::withCapacity(len);
327 newCollect = (len != 0);
328 break;
329 case kOSSerializeArray:
330 o = newArray = OSArray::withCapacity(len);
331 newCollect = (len != 0);
332 break;
333 case kOSSerializeSet:
334 o = newSet = OSSet::withCapacity(len);
335 newCollect = (len != 0);
336 break;
337
338 case kOSSerializeObject:
339 if (len >= objsIdx) break;
340 o = objsArray[len];
341 o->retain();
342 isRef = true;
343 break;
344
345 case kOSSerializeNumber:
346 bufferPos += sizeof(long long);
347 if (bufferPos > bufferSize) break;
348 value = next[1];
349 value <<= 32;
350 value |= next[0];
351 o = OSNumber::withNumber(value, len);
352 next += 2;
353 break;
354
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);
360 next += wordLen;
361 break;
362
363 case kOSSerializeString:
364 bufferPos += (wordLen * sizeof(uint32_t));
365 if (bufferPos > bufferSize) break;
366 o = OSString::withStringOfLength((const char *) next, len);
367 next += wordLen;
368 break;
369
370 case kOSSerializeData:
371 bufferPos += (wordLen * sizeof(uint32_t));
372 if (bufferPos > bufferSize) break;
373 o = OSData::withBytes(next, len);
374 next += wordLen;
375 break;
376
377 case kOSSerializeBoolean:
378 o = (len ? kOSBooleanTrue : kOSBooleanFalse);
379 break;
380
381 default:
382 break;
383 }
384
385 if (!(ok = (o != 0))) break;
386
387 if (!isRef)
388 {
389 setAtIndex(objs, objsIdx, o);
390 if (!ok) break;
391 objsIdx++;
392 }
393
394 if (dict)
395 {
396 if (sym)
397 {
398 DEBG("%s = %s\n", sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
399 if (o != dict) ok = dict->setObject(sym, o);
400 o->release();
401 sym->release();
402 sym = 0;
403 }
404 else
405 {
406 sym = OSDynamicCast(OSSymbol, o);
407 if (!sym && (str = OSDynamicCast(OSString, o)))
408 {
409 sym = (OSSymbol *) OSSymbol::withString(str);
410 o->release();
411 o = 0;
412 }
413 ok = (sym != 0);
414 }
415 }
416 else if (array)
417 {
418 ok = array->setObject(o);
419 o->release();
420 }
421 else if (set)
422 {
423 ok = set->setObject(o);
424 o->release();
425 }
426 else
427 {
428 assert(!parent);
429 result = o;
430 }
431
432 if (!ok) break;
433
434 if (newCollect)
435 {
436 if (!end)
437 {
438 stackIdx++;
439 setAtIndex(stack, stackIdx, parent);
440 if (!ok) break;
441 }
442 DEBG("++stack[%d] %p\n", stackIdx, parent);
443 parent = o;
444 dict = newDict;
445 array = newArray;
446 set = newSet;
447 end = false;
448 }
449
450 if (end)
451 {
452 if (!stackIdx) break;
453 parent = stackArray[stackIdx];
454 DEBG("--stack[%d] %p\n", stackIdx, parent);
455 stackIdx--;
456 set = 0;
457 dict = 0;
458 array = 0;
459 if (!(dict = OSDynamicCast(OSDictionary, parent)))
460 {
461 if (!(array = OSDynamicCast(OSArray, parent))) ok = (0 != (set = OSDynamicCast(OSSet, parent)));
462 }
463 }
464 }
465 DEBG("ret %p\n", result);
466
467 if (objsCapacity) kfree(objsArray, objsCapacity * sizeof(*objsArray));
468 if (stackCapacity) kfree(stackArray, stackCapacity * sizeof(*stackArray));
469
470 if (!ok && result)
471 {
472 result->release();
473 result = 0;
474 }
475 return (result);
476 }