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
47OSSerialize *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
67bool OSSerialize::addBinary(const void * bits, size_t size)
68{
69 unsigned int newCapacity;
70 size_t alignSize;
71
72 if (os_add_overflow(size, 3, &alignSize)) return (false);
73 alignSize &= ~3L;
74 if (os_add_overflow(length, alignSize, &newCapacity)) return (false);
75 if (newCapacity >= capacity)
76 {
77 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) * capacityIncrement;
78 if (newCapacity < capacity) return (false);
79 if (newCapacity > ensureCapacity(newCapacity)) return (false);
80 }
81
82 bcopy(bits, &data[length], size);
83 length += alignSize;
84
85 return (true);
86}
87
88bool OSSerialize::addBinaryObject(const OSMetaClassBase * o, uint32_t key,
89 const void * bits, size_t size)
90{
91 unsigned int newCapacity;
92 size_t alignSize;
93
94 // add to tag array
95 tags->setObject(o);
96
97 if (os_add3_overflow(size, sizeof(key), 3, &alignSize)) return (false);
98 alignSize &= ~3L;
99 if (os_add_overflow(length, alignSize, &newCapacity)) return (false);
100 if (newCapacity >= capacity)
101 {
102 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) * capacityIncrement;
103 if (newCapacity < capacity) return (false);
104 if (newCapacity > ensureCapacity(newCapacity)) return (false);
105 }
106
107 if (endCollection)
108 {
109 endCollection = false;
110 key |= kOSSerializeEndCollecton;
111 }
112
113 bcopy(&key, &data[length], sizeof(key));
114 bcopy(bits, &data[length + sizeof(key)], size);
115 length += alignSize;
116
117 return (true);
118}
119
120bool OSSerialize::binarySerialize(const OSMetaClassBase *o)
121{
122 OSDictionary * dict;
123 OSArray * array;
124 OSSet * set;
125 OSNumber * num;
126 OSSymbol * sym;
127 OSString * str;
128 OSData * ldata;
129 OSBoolean * boo;
130
131 unsigned int tagIdx;
132 uint32_t i, key;
133 size_t len;
134 bool ok;
135
136 tagIdx = tags->getNextIndexOfObject(o, 0);
137 // does it exist?
138 if (-1U != tagIdx)
139 {
140 key = (kOSSerializeObject | tagIdx);
141 if (endCollection)
142 {
143 endCollection = false;
144 key |= kOSSerializeEndCollecton;
145 }
146 ok = addBinary(&key, sizeof(key));
147 return (ok);
148 }
149
150 if ((dict = OSDynamicCast(OSDictionary, o)))
151 {
152 key = (kOSSerializeDictionary | dict->count);
153 ok = addBinaryObject(o, key, NULL, 0);
154 for (i = 0; ok && (i < dict->count);)
155 {
156 const OSSymbol * dictKey;
157 const OSMetaClassBase * dictValue;
158 const OSMetaClassBase * nvalue = 0;
159
160 dictKey = dict->dictionary[i].key;
161 dictValue = dict->dictionary[i].value;
162 i++;
163 if (editor)
164 {
165 dictValue = nvalue = (*editor)(editRef, this, dict, dictKey, dictValue);
166 if (!dictValue) dictValue = dict;
167 }
168 ok = binarySerialize(dictKey);
169 if (!ok) break;
170 endCollection = (i == dict->count);
171 ok = binarySerialize(dictValue);
172 if (!ok) ok = dictValue->serialize(this);
173 if (nvalue) nvalue->release();
174// if (!ok) ok = binarySerialize(kOSBooleanFalse);
175 }
176 }
177 else if ((array = OSDynamicCast(OSArray, o)))
178 {
179 key = (kOSSerializeArray | array->count);
180 ok = addBinaryObject(o, key, NULL, 0);
181 for (i = 0; ok && (i < array->count);)
182 {
183 i++;
184 endCollection = (i == array->count);
185 ok = binarySerialize(array->array[i-1]);
186 if (!ok) ok = array->array[i-1]->serialize(this);
187// if (!ok) ok = binarySerialize(kOSBooleanFalse);
188 }
189 }
190 else if ((set = OSDynamicCast(OSSet, o)))
191 {
192 key = (kOSSerializeSet | set->members->count);
193 ok = addBinaryObject(o, key, NULL, 0);
194 for (i = 0; ok && (i < set->members->count);)
195 {
196 i++;
197 endCollection = (i == set->members->count);
198 ok = binarySerialize(set->members->array[i-1]);
199 if (!ok) ok = set->members->array[i-1]->serialize(this);
200// if (!ok) ok = binarySerialize(kOSBooleanFalse);
201 }
202 }
203 else if ((num = OSDynamicCast(OSNumber, o)))
204 {
205 key = (kOSSerializeNumber | num->size);
206 ok = addBinaryObject(o, key, &num->value, sizeof(num->value));
207 }
208 else if ((boo = OSDynamicCast(OSBoolean, o)))
209 {
210 key = (kOSSerializeBoolean | (kOSBooleanTrue == boo));
211 ok = addBinaryObject(o, key, NULL, 0);
212 }
213 else if ((sym = OSDynamicCast(OSSymbol, o)))
214 {
215 len = (sym->getLength() + 1);
216 key = (kOSSerializeSymbol | len);
217 ok = addBinaryObject(o, key, sym->getCStringNoCopy(), len);
218 }
219 else if ((str = OSDynamicCast(OSString, o)))
220 {
221 len = (str->getLength() + 0);
222 key = (kOSSerializeString | len);
223 ok = addBinaryObject(o, key, str->getCStringNoCopy(), len);
224 }
225 else if ((ldata = OSDynamicCast(OSData, o)))
226 {
227 len = ldata->getLength();
228 if (ldata->reserved && ldata->reserved->disableSerialization) len = 0;
229 key = (kOSSerializeData | len);
230 ok = addBinaryObject(o, key, ldata->getBytesNoCopy(), len);
231 }
232 else return (false);
233
234 return (ok);
235}
236
237/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
238
239#define setAtIndex(v, idx, o) \
240 if (idx >= v##Capacity) \
241 { \
242 if (v##Capacity >= v##CapacityMax) ok = false; \
243 else \
244 { \
245 uint32_t ncap = v##Capacity + 64; \
246 typeof(v##Array) nbuf = (typeof(v##Array)) kalloc_container(ncap * sizeof(o)); \
247 if (!nbuf) ok = false; \
248 else \
249 { \
250 if (v##Array) \
251 { \
252 bcopy(v##Array, nbuf, v##Capacity * sizeof(o)); \
253 kfree(v##Array, v##Capacity * sizeof(o)); \
254 } \
255 v##Array = nbuf; \
256 v##Capacity = ncap; \
257 } \
258 } \
259 } \
260 if (ok) v##Array[idx] = o;
261
262/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
263
264OSObject *
265OSUnserializeBinary(const char *buffer, size_t bufferSize, OSString **errorString)
266{
267 OSObject ** objsArray;
268 uint32_t objsCapacity;
269 enum { objsCapacityMax = 16*1024*1024 };
270 uint32_t objsIdx;
271
272 OSObject ** stackArray;
273 uint32_t stackCapacity;
274 enum { stackCapacityMax = 64 };
275 uint32_t stackIdx;
276
277 OSObject * result;
278 OSObject * parent;
279 OSDictionary * dict;
280 OSArray * array;
281 OSSet * set;
282 OSDictionary * newDict;
283 OSArray * newArray;
284 OSSet * newSet;
285 OSObject * o;
286 OSSymbol * sym;
287 OSString * str;
288
289 size_t bufferPos;
290 const uint32_t * next;
291 uint32_t key, len, wordLen;
292 bool end, newCollect, isRef;
293 unsigned long long value;
294 bool ok;
295
296 if (errorString) *errorString = 0;
297 if (bufferSize < sizeof(kOSSerializeBinarySignature)) return (NULL);
298 if (0 != strcmp(kOSSerializeBinarySignature, buffer)) return (NULL);
299 if (3 & ((uintptr_t) buffer)) return (NULL);
300 bufferPos = sizeof(kOSSerializeBinarySignature);
301 next = (typeof(next)) (((uintptr_t) buffer) + bufferPos);
302
303 DEBG("---------OSUnserializeBinary(%p)\n", buffer);
304
305 objsArray = stackArray = NULL;
306 objsIdx = objsCapacity = 0;
307 stackIdx = stackCapacity = 0;
308
309 result = 0;
310 parent = 0;
311 dict = 0;
312 array = 0;
313 set = 0;
314 sym = 0;
315
316 ok = true;
317 while (ok)
318 {
319 bufferPos += sizeof(*next);
320 if (!(ok = (bufferPos <= bufferSize))) break;
321 key = *next++;
322
323 len = (key & kOSSerializeDataMask);
324 wordLen = (len + 3) >> 2;
325 end = (0 != (kOSSerializeEndCollecton & key));
326 DEBG("key 0x%08x: 0x%04x, %d\n", key, len, end);
327
328 newCollect = isRef = false;
329 o = 0; newDict = 0; newArray = 0; newSet = 0;
330
331 switch (kOSSerializeTypeMask & key)
332 {
333 case kOSSerializeDictionary:
334 o = newDict = OSDictionary::withCapacity(len);
335 newCollect = (len != 0);
336 break;
337 case kOSSerializeArray:
338 o = newArray = OSArray::withCapacity(len);
339 newCollect = (len != 0);
340 break;
341 case kOSSerializeSet:
342 o = newSet = OSSet::withCapacity(len);
343 newCollect = (len != 0);
344 break;
345
346 case kOSSerializeObject:
347 if (len >= objsIdx) break;
348 o = objsArray[len];
349 isRef = true;
350 break;
351
352 case kOSSerializeNumber:
353 bufferPos += sizeof(long long);
354 if (bufferPos > bufferSize) break;
355 if ((len != 32) && (len != 64) && (len != 16) && (len != 8)) break;
356 value = next[1];
357 value <<= 32;
358 value |= next[0];
359 o = OSNumber::withNumber(value, len);
360 next += 2;
361 break;
362
363 case kOSSerializeSymbol:
364 bufferPos += (wordLen * sizeof(uint32_t));
365 if (bufferPos > bufferSize) break;
366 if (len < 2) break;
367 if (0 != ((const char *)next)[len-1]) break;
368 o = (OSObject *) OSSymbol::withCString((const char *) next);
369 next += wordLen;
370 break;
371
372 case kOSSerializeString:
373 bufferPos += (wordLen * sizeof(uint32_t));
374 if (bufferPos > bufferSize) break;
375 o = OSString::withStringOfLength((const char *) next, len);
376 next += wordLen;
377 break;
378
379 case kOSSerializeData:
380 bufferPos += (wordLen * sizeof(uint32_t));
381 if (bufferPos > bufferSize) break;
382 o = OSData::withBytes(next, len);
383 next += wordLen;
384 break;
385
386 case kOSSerializeBoolean:
387 o = (len ? kOSBooleanTrue : kOSBooleanFalse);
388 break;
389
390 default:
391 break;
392 }
393
394 if (!(ok = (o != 0))) break;
395
396 if (!isRef)
397 {
398 setAtIndex(objs, objsIdx, o);
399 if (!ok)
400 {
401 o->release();
402 break;
403 }
404 objsIdx++;
405 }
406
407 if (dict)
408 {
409 if (!sym) sym = (OSSymbol *) o;
410 else
411 {
412 str = sym;
413 sym = OSDynamicCast(OSSymbol, sym);
414 if (!sym && (str = OSDynamicCast(OSString, str)))
415 {
416 sym = const_cast<OSSymbol *>(OSSymbol::withString(str));
417 ok = (sym != 0);
418 if (!ok) break;
419 }
420 DEBG("%s = %s\n", sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
421 if (o != dict) ok = dict->setObject(sym, o);
422 if (sym && (sym != str)) sym->release();
423 sym = 0;
424 }
425 }
426 else if (array) ok = array->setObject(o);
427 else if (set) ok = set->setObject(o);
428 else if (result) ok = false;
429 else
430 {
431 assert(!parent);
432 result = o;
433 }
434
435 if (!ok) break;
436
437 if (end) parent = 0;
438 if (newCollect)
439 {
440 stackIdx++;
441 setAtIndex(stack, stackIdx, parent);
442 if (!ok) break;
443 DEBG("++stack[%d] %p\n", stackIdx, parent);
444 parent = o;
445 dict = newDict;
446 array = newArray;
447 set = newSet;
448 end = false;
449 }
450
451 if (end)
452 {
453 while (stackIdx)
454 {
455 parent = stackArray[stackIdx];
456 DEBG("--stack[%d] %p\n", stackIdx, parent);
457 stackIdx--;
458 if (parent) break;
459 }
460 if (!parent) break;
461 set = 0;
462 dict = 0;
463 array = 0;
464 if (!(dict = OSDynamicCast(OSDictionary, parent)))
465 {
466 if (!(array = OSDynamicCast(OSArray, parent))) ok = (0 != (set = OSDynamicCast(OSSet, parent)));
467 }
468 }
469 }
470 DEBG("ret %p\n", result);
471
472 if (!ok) result = 0;
473
474 if (objsCapacity)
475 {
476 for (len = (result != 0); len < objsIdx; len++) objsArray[len]->release();
477 kfree(objsArray, objsCapacity * sizeof(*objsArray));
478 }
479 if (stackCapacity) kfree(stackArray, stackCapacity * sizeof(*stackArray));
480
481 return (result);
482}
483