]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 5 | * |
2d21ac55 A |
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. | |
0a7de745 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* OSSerialize.cpp created by rsulack on Wen 25-Nov-1998 */ | |
29 | ||
9bccf70c A |
30 | #include <sys/cdefs.h> |
31 | ||
32 | __BEGIN_DECLS | |
33 | #include <vm/vm_kern.h> | |
34 | __END_DECLS | |
35 | ||
1c79356b A |
36 | #include <libkern/c++/OSContainers.h> |
37 | #include <libkern/c++/OSLib.h> | |
38 | #include <libkern/c++/OSDictionary.h> | |
fe8ab488 | 39 | #include <libkern/OSSerializeBinary.h> |
d9a64523 | 40 | #include <libkern/Block.h> |
3e170ce0 | 41 | #include <IOKit/IOLib.h> |
1c79356b A |
42 | |
43 | #define super OSObject | |
44 | ||
45 | OSDefineMetaClassAndStructors(OSSerialize, OSObject) | |
46 | OSMetaClassDefineReservedUnused(OSSerialize, 0); | |
47 | OSMetaClassDefineReservedUnused(OSSerialize, 1); | |
48 | OSMetaClassDefineReservedUnused(OSSerialize, 2); | |
49 | OSMetaClassDefineReservedUnused(OSSerialize, 3); | |
50 | OSMetaClassDefineReservedUnused(OSSerialize, 4); | |
51 | OSMetaClassDefineReservedUnused(OSSerialize, 5); | |
52 | OSMetaClassDefineReservedUnused(OSSerialize, 6); | |
53 | OSMetaClassDefineReservedUnused(OSSerialize, 7); | |
54 | ||
1c79356b | 55 | |
0a7de745 A |
56 | char * |
57 | OSSerialize::text() const | |
1c79356b A |
58 | { |
59 | return data; | |
60 | } | |
61 | ||
0a7de745 A |
62 | void |
63 | OSSerialize::clearText() | |
1c79356b | 64 | { |
0a7de745 | 65 | if (binary) { |
fe8ab488 A |
66 | length = sizeof(kOSSerializeBinarySignature); |
67 | bzero(&data[length], capacity - length); | |
68 | endCollection = true; | |
0a7de745 | 69 | } else { |
fe8ab488 A |
70 | bzero((void *)data, capacity); |
71 | length = 1; | |
0a7de745 | 72 | } |
1c79356b A |
73 | tags->flushCollection(); |
74 | } | |
75 | ||
0a7de745 A |
76 | bool |
77 | OSSerialize::previouslySerialized(const OSMetaClassBase *o) | |
1c79356b A |
78 | { |
79 | char temp[16]; | |
39037602 | 80 | unsigned int tagIdx; |
1c79356b | 81 | |
0a7de745 A |
82 | if (binary) { |
83 | return binarySerialize(o); | |
84 | } | |
fe8ab488 | 85 | |
1c79356b | 86 | // look it up |
39037602 | 87 | tagIdx = tags->getNextIndexOfObject(o, 0); |
1c79356b | 88 | |
b0d623f7 | 89 | // xx-review: no error checking here for addString calls! |
1c79356b | 90 | // does it exist? |
39037602 | 91 | if (tagIdx != -1U) { |
1c79356b | 92 | addString("<reference IDREF=\""); |
39037602 A |
93 | snprintf(temp, sizeof(temp), "%u", tagIdx); |
94 | addString(temp); | |
1c79356b A |
95 | addString("\"/>"); |
96 | return true; | |
97 | } | |
98 | ||
39037602 | 99 | // add to tag array |
0a7de745 | 100 | tags->setObject(o);// XXX check return |
1c79356b A |
101 | |
102 | return false; | |
103 | } | |
104 | ||
0a7de745 A |
105 | bool |
106 | OSSerialize::addXMLStartTag(const OSMetaClassBase *o, const char *tagString) | |
1c79356b | 107 | { |
39037602 A |
108 | char temp[16]; |
109 | unsigned int tagIdx; | |
110 | ||
0a7de745 | 111 | if (binary) { |
fe8ab488 | 112 | printf("class %s: xml serialize\n", o->getMetaClass()->getClassName()); |
0a7de745 | 113 | return false; |
fe8ab488 | 114 | } |
1c79356b | 115 | |
0a7de745 A |
116 | if (!addChar('<')) { |
117 | return false; | |
118 | } | |
119 | if (!addString(tagString)) { | |
120 | return false; | |
121 | } | |
122 | if (!addString(" ID=\"")) { | |
123 | return false; | |
124 | } | |
39037602 A |
125 | tagIdx = tags->getNextIndexOfObject(o, 0); |
126 | assert(tagIdx != -1U); | |
127 | snprintf(temp, sizeof(temp), "%u", tagIdx); | |
0a7de745 A |
128 | if (!addString(temp)) { |
129 | return false; | |
130 | } | |
131 | if (!addChar('\"')) { | |
132 | return false; | |
133 | } | |
134 | if (!addChar('>')) { | |
1c79356b | 135 | return false; |
0a7de745 | 136 | } |
1c79356b A |
137 | return true; |
138 | } | |
139 | ||
0a7de745 A |
140 | bool |
141 | OSSerialize::addXMLEndTag(const char *tagString) | |
1c79356b | 142 | { |
0a7de745 A |
143 | if (!addChar('<')) { |
144 | return false; | |
145 | } | |
146 | if (!addChar('/')) { | |
147 | return false; | |
148 | } | |
149 | if (!addString(tagString)) { | |
150 | return false; | |
151 | } | |
152 | if (!addChar('>')) { | |
153 | return false; | |
154 | } | |
1c79356b A |
155 | return true; |
156 | } | |
157 | ||
0a7de745 A |
158 | bool |
159 | OSSerialize::addChar(const char c) | |
1c79356b | 160 | { |
0a7de745 | 161 | if (binary) { |
fe8ab488 | 162 | printf("xml serialize\n"); |
0a7de745 | 163 | return false; |
fe8ab488 A |
164 | } |
165 | ||
1c79356b | 166 | // add char, possibly extending our capacity |
0a7de745 | 167 | if (length >= capacity && length >= ensureCapacity(capacity + capacityIncrement)) { |
1c79356b | 168 | return false; |
0a7de745 | 169 | } |
1c79356b A |
170 | |
171 | data[length - 1] = c; | |
172 | length++; | |
0a7de745 | 173 | |
1c79356b A |
174 | return true; |
175 | } | |
176 | ||
0a7de745 A |
177 | bool |
178 | OSSerialize::addString(const char *s) | |
1c79356b A |
179 | { |
180 | bool rc = false; | |
181 | ||
0a7de745 A |
182 | while (*s && (rc = addChar(*s++))) { |
183 | ; | |
184 | } | |
1c79356b A |
185 | |
186 | return rc; | |
187 | } | |
188 | ||
0a7de745 A |
189 | bool |
190 | OSSerialize::initWithCapacity(unsigned int inCapacity) | |
1c79356b | 191 | { |
0a7de745 A |
192 | if (!super::init()) { |
193 | return false; | |
194 | } | |
195 | ||
196 | tags = OSArray::withCapacity(256); | |
197 | if (!tags) { | |
198 | return false; | |
199 | } | |
200 | ||
201 | length = 1; | |
202 | ||
203 | if (!inCapacity) { | |
204 | inCapacity = 1; | |
205 | } | |
206 | if (round_page_overflow(inCapacity, &capacity)) { | |
207 | tags->release(); | |
cb323159 | 208 | tags = NULL; |
0a7de745 A |
209 | return false; |
210 | } | |
211 | ||
212 | capacityIncrement = capacity; | |
213 | ||
214 | // allocate from the kernel map so that we can safely map this data | |
215 | // into user space (the primary use of the OSSerialize object) | |
216 | ||
217 | kern_return_t rc = kmem_alloc(kernel_map, (vm_offset_t *)&data, capacity, IOMemoryTag(kernel_map)); | |
218 | if (rc) { | |
219 | tags->release(); | |
cb323159 | 220 | tags = NULL; |
0a7de745 A |
221 | return false; |
222 | } | |
223 | bzero((void *)data, capacity); | |
224 | ||
225 | ||
226 | OSCONTAINER_ACCUMSIZE(capacity); | |
227 | ||
228 | return true; | |
1c79356b A |
229 | } |
230 | ||
0a7de745 A |
231 | OSSerialize * |
232 | OSSerialize::withCapacity(unsigned int inCapacity) | |
1c79356b A |
233 | { |
234 | OSSerialize *me = new OSSerialize; | |
235 | ||
236 | if (me && !me->initWithCapacity(inCapacity)) { | |
55e303ae | 237 | me->release(); |
cb323159 | 238 | return NULL; |
1c79356b A |
239 | } |
240 | ||
241 | return me; | |
242 | } | |
243 | ||
0a7de745 A |
244 | unsigned int |
245 | OSSerialize::getLength() const | |
246 | { | |
247 | return length; | |
248 | } | |
249 | unsigned int | |
250 | OSSerialize::getCapacity() const | |
251 | { | |
252 | return capacity; | |
253 | } | |
254 | unsigned int | |
255 | OSSerialize::getCapacityIncrement() const | |
1c79356b | 256 | { |
0a7de745 A |
257 | return capacityIncrement; |
258 | } | |
259 | unsigned int | |
260 | OSSerialize::setCapacityIncrement(unsigned int increment) | |
261 | { | |
262 | capacityIncrement = (increment)? increment : 256; | |
263 | return capacityIncrement; | |
1c79356b A |
264 | } |
265 | ||
0a7de745 A |
266 | unsigned int |
267 | OSSerialize::ensureCapacity(unsigned int newCapacity) | |
1c79356b A |
268 | { |
269 | char *newData; | |
1c79356b | 270 | |
0a7de745 | 271 | if (newCapacity <= capacity) { |
1c79356b | 272 | return capacity; |
0a7de745 | 273 | } |
1c79356b | 274 | |
39037602 A |
275 | if (round_page_overflow(newCapacity, &newCapacity)) { |
276 | return capacity; | |
277 | } | |
9bccf70c A |
278 | |
279 | kern_return_t rc = kmem_realloc(kernel_map, | |
0a7de745 A |
280 | (vm_offset_t)data, |
281 | capacity, | |
282 | (vm_offset_t *)&newData, | |
283 | newCapacity, | |
284 | VM_KERN_MEMORY_IOKIT); | |
9bccf70c | 285 | if (!rc) { |
0a7de745 | 286 | OSCONTAINER_ACCUMSIZE(newCapacity); |
9bccf70c | 287 | |
0a7de745 A |
288 | // kmem realloc does not free the old address range |
289 | kmem_free(kernel_map, (vm_offset_t)data, capacity); | |
290 | OSCONTAINER_ACCUMSIZE(-((size_t)capacity)); | |
291 | ||
292 | // kmem realloc does not zero out the new memory | |
293 | // and this could end up going to user land | |
294 | bzero(&newData[capacity], newCapacity - capacity); | |
295 | ||
296 | data = newData; | |
297 | capacity = newCapacity; | |
1c79356b A |
298 | } |
299 | ||
300 | return capacity; | |
301 | } | |
302 | ||
0a7de745 A |
303 | void |
304 | OSSerialize::free() | |
1c79356b | 305 | { |
cb323159 A |
306 | OSSafeReleaseNULL(tags); |
307 | OSSafeReleaseNULL(indexData); | |
0a7de745 A |
308 | |
309 | if (data) { | |
310 | kmem_free(kernel_map, (vm_offset_t)data, capacity); | |
311 | OSCONTAINER_ACCUMSIZE( -((size_t)capacity)); | |
312 | } | |
313 | super::free(); | |
1c79356b A |
314 | } |
315 | ||
316 | ||
317 | OSDefineMetaClassAndStructors(OSSerializer, OSObject) | |
318 | ||
319 | OSSerializer * OSSerializer::forTarget( void * target, | |
0a7de745 | 320 | OSSerializerCallback callback, void * ref ) |
1c79356b | 321 | { |
0a7de745 A |
322 | OSSerializer * thing; |
323 | ||
324 | thing = new OSSerializer; | |
325 | if (thing && !thing->init()) { | |
326 | thing->release(); | |
cb323159 | 327 | thing = NULL; |
0a7de745 A |
328 | } |
329 | ||
330 | if (thing) { | |
331 | thing->target = target; | |
332 | thing->ref = ref; | |
333 | thing->callback = callback; | |
334 | } | |
335 | return thing; | |
1c79356b A |
336 | } |
337 | ||
0a7de745 A |
338 | bool |
339 | OSSerializer::callbackToBlock(void * target __unused, void * ref, | |
340 | OSSerialize * serializer) | |
d9a64523 | 341 | { |
0a7de745 | 342 | return ((OSSerializerBlock)ref)(serializer); |
d9a64523 A |
343 | } |
344 | ||
0a7de745 A |
345 | OSSerializer * |
346 | OSSerializer::withBlock( | |
347 | OSSerializerBlock callback) | |
d9a64523 | 348 | { |
0a7de745 A |
349 | OSSerializer * serializer; |
350 | OSSerializerBlock block; | |
d9a64523 | 351 | |
0a7de745 A |
352 | block = Block_copy(callback); |
353 | if (!block) { | |
cb323159 | 354 | return NULL; |
0a7de745 | 355 | } |
d9a64523 | 356 | |
0a7de745 | 357 | serializer = (OSSerializer::forTarget(NULL, &OSSerializer::callbackToBlock, block)); |
d9a64523 | 358 | |
0a7de745 A |
359 | if (!serializer) { |
360 | Block_release(block); | |
361 | } | |
d9a64523 | 362 | |
0a7de745 | 363 | return serializer; |
d9a64523 A |
364 | } |
365 | ||
0a7de745 A |
366 | void |
367 | OSSerializer::free(void) | |
d9a64523 | 368 | { |
0a7de745 A |
369 | if (callback == &callbackToBlock) { |
370 | Block_release(ref); | |
371 | } | |
d9a64523 | 372 | |
0a7de745 | 373 | super::free(); |
d9a64523 A |
374 | } |
375 | ||
0a7de745 A |
376 | bool |
377 | OSSerializer::serialize( OSSerialize * s ) const | |
1c79356b | 378 | { |
0a7de745 | 379 | return (*callback)(target, ref, s); |
1c79356b | 380 | } |