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