xref: /xnu-11215/libkern/c++/OSSerialize.cpp (revision a3bb9fcc)
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 
41 #define super OSObject
42 
43 OSDefineMetaClassAndStructors(OSSerialize, OSObject)
44 OSMetaClassDefineReservedUnused(OSSerialize, 0);
45 OSMetaClassDefineReservedUnused(OSSerialize, 1);
46 OSMetaClassDefineReservedUnused(OSSerialize, 2);
47 OSMetaClassDefineReservedUnused(OSSerialize, 3);
48 OSMetaClassDefineReservedUnused(OSSerialize, 4);
49 OSMetaClassDefineReservedUnused(OSSerialize, 5);
50 OSMetaClassDefineReservedUnused(OSSerialize, 6);
51 OSMetaClassDefineReservedUnused(OSSerialize, 7);
52 
53 #if OSALLOCDEBUG
54 extern "C" {
55     extern int debug_container_malloc_size;
56 };
57 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
58 #else
59 #define ACCUMSIZE(s)
60 #endif
61 
62 char * OSSerialize::text() const
63 {
64 	return data;
65 }
66 
67 void OSSerialize::clearText()
68 {
69 	if (binary)
70 	{
71 		length = sizeof(kOSSerializeBinarySignature);
72 		bzero(&data[length], capacity - length);
73 		endCollection = true;
74 	}
75     else
76     {
77 		bzero((void *)data, capacity);
78 		length = 1;
79     }
80 	tag = 0;
81 	tags->flushCollection();
82 }
83 
84 bool OSSerialize::previouslySerialized(const OSMetaClassBase *o)
85 {
86 	char temp[16];
87 	OSString *tagString;
88 
89 	if (binary) return (binarySerialize(o));
90 
91 	// look it up
92 	tagString = (OSString *)tags->getObject((const OSSymbol *) o);
93 
94 // xx-review: no error checking here for addString calls!
95 	// does it exist?
96 	if (tagString) {
97 		addString("<reference IDREF=\"");
98 		addString(tagString->getCStringNoCopy());
99 		addString("\"/>");
100 		return true;
101 	}
102 
103 	// build a tag
104 	snprintf(temp, sizeof(temp), "%u", tag++);
105 	tagString = OSString::withCString(temp);
106 
107 	// add to tag dictionary
108         tags->setObject((const OSSymbol *) o, tagString);// XXX check return
109 	tagString->release();
110 
111 	return false;
112 }
113 
114 bool OSSerialize::addXMLStartTag(const OSMetaClassBase *o, const char *tagString)
115 {
116 	if (binary)
117     {
118 		printf("class %s: xml serialize\n", o->getMetaClass()->getClassName());
119 		return (false);
120 	}
121 
122 	if (!addChar('<')) return false;
123 	if (!addString(tagString)) return false;
124 	if (!addString(" ID=\"")) return false;
125 	if (!addString(((OSString *)tags->getObject((const OSSymbol *)o))->getCStringNoCopy()))
126 		return false;
127 	if (!addChar('\"')) return false;
128 	if (!addChar('>')) return false;
129 	return true;
130 }
131 
132 bool OSSerialize::addXMLEndTag(const char *tagString)
133 {
134 
135 	if (!addChar('<')) return false;
136 	if (!addChar('/')) return false;
137 	if (!addString(tagString)) return false;
138 	if (!addChar('>')) return false;
139 	return true;
140 }
141 
142 bool OSSerialize::addChar(const char c)
143 {
144 	if (binary)
145     {
146 		printf("xml serialize\n");
147 		return (false);
148 	}
149 
150 	// add char, possibly extending our capacity
151 	if (length >= capacity && length >=ensureCapacity(capacity+capacityIncrement))
152 		return false;
153 
154 	data[length - 1] = c;
155 	length++;
156 
157 	return true;
158 }
159 
160 bool OSSerialize::addString(const char *s)
161 {
162 	bool rc = false;
163 
164 	while (*s && (rc = addChar(*s++))) ;
165 
166 	return rc;
167 }
168 
169 bool OSSerialize::initWithCapacity(unsigned int inCapacity)
170 {
171     if (!super::init())
172             return false;
173 
174     tags = OSDictionary::withCapacity(32);
175     if (!tags) {
176         return false;
177     }
178 
179     tag = 0;
180     length = 1;
181     capacity = (inCapacity) ? round_page_32(inCapacity) : round_page_32(1);
182     capacityIncrement = capacity;
183 
184     // allocate from the kernel map so that we can safely map this data
185     // into user space (the primary use of the OSSerialize object)
186 
187     kern_return_t rc = kmem_alloc(kernel_map, (vm_offset_t *)&data, capacity);
188     if (rc) {
189         tags->release();
190         tags = 0;
191         return false;
192     }
193     bzero((void *)data, capacity);
194 
195 
196     ACCUMSIZE(capacity);
197 
198     return true;
199 }
200 
201 OSSerialize *OSSerialize::withCapacity(unsigned int inCapacity)
202 {
203 	OSSerialize *me = new OSSerialize;
204 
205 	if (me && !me->initWithCapacity(inCapacity)) {
206 		me->release();
207 		return 0;
208 	}
209 
210 	return me;
211 }
212 
213 unsigned int OSSerialize::getLength() const { return length; }
214 unsigned int OSSerialize::getCapacity() const { return capacity; }
215 unsigned int OSSerialize::getCapacityIncrement() const { return capacityIncrement; }
216 unsigned int OSSerialize::setCapacityIncrement(unsigned int increment)
217 {
218     capacityIncrement = (increment)? increment : 256;
219     return capacityIncrement;
220 }
221 
222 unsigned int OSSerialize::ensureCapacity(unsigned int newCapacity)
223 {
224 	char *newData;
225 
226 	if (newCapacity <= capacity)
227 		return capacity;
228 
229 	// round up
230 	newCapacity = round_page_32(newCapacity);
231 
232 	kern_return_t rc = kmem_realloc(kernel_map,
233 					(vm_offset_t)data,
234 					capacity,
235 					(vm_offset_t *)&newData,
236 					newCapacity);
237 	if (!rc) {
238 	    ACCUMSIZE(newCapacity);
239 
240 	    // kmem realloc does not free the old address range
241 	    kmem_free(kernel_map, (vm_offset_t)data, capacity);
242 	    ACCUMSIZE(-capacity);
243 
244 	    // kmem realloc does not zero out the new memory
245 	    // and this could end up going to user land
246 	    bzero(&newData[capacity], newCapacity - capacity);
247 
248 	    data = newData;
249 	    capacity = newCapacity;
250 	}
251 
252 	return capacity;
253 }
254 
255 void OSSerialize::free()
256 {
257     if (tags)
258         tags->release();
259 
260     if (data) {
261 	kmem_free(kernel_map, (vm_offset_t)data, capacity);
262         ACCUMSIZE( -capacity );
263     }
264     super::free();
265 }
266 
267 
268 OSDefineMetaClassAndStructors(OSSerializer, OSObject)
269 
270 OSSerializer * OSSerializer::forTarget( void * target,
271                                OSSerializerCallback callback, void * ref )
272 {
273     OSSerializer * thing;
274 
275     thing = new OSSerializer;
276     if( thing && !thing->init()) {
277 	thing->release();
278 	thing = 0;
279     }
280 
281     if( thing) {
282 	thing->target	= target;
283         thing->ref	= ref;
284         thing->callback = callback;
285     }
286     return( thing );
287 }
288 
289 bool OSSerializer::serialize( OSSerialize * s ) const
290 {
291     return( (*callback)(target, ref, s) );
292 }
293