xref: /xnu-11215/libkern/c++/OSSerialize.cpp (revision 14e3d835)
1 /*
2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_LICENSE_HEADER_START@
5  *
6  * The contents of this file constitute Original Code as defined in and
7  * are subject to the Apple Public Source License Version 1.1 (the
8  * "License").  You may not use this file except in compliance with the
9  * License.  Please obtain a copy of the License at
10  * http://www.apple.com/publicsource and read it before using this file.
11  *
12  * This Original Code and all software distributed under the License are
13  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17  * License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * @APPLE_LICENSE_HEADER_END@
21  */
22 /* OSSerialize.cpp created by rsulack on Wen 25-Nov-1998 */
23 
24 #include <sys/cdefs.h>
25 
26 __BEGIN_DECLS
27 #include <vm/vm_kern.h>
28 __END_DECLS
29 
30 #include <libkern/c++/OSContainers.h>
31 #include <libkern/c++/OSLib.h>
32 #include <libkern/c++/OSDictionary.h>
33 
34 #define super OSObject
35 
36 OSDefineMetaClassAndStructors(OSSerialize, OSObject)
37 OSMetaClassDefineReservedUnused(OSSerialize, 0);
38 OSMetaClassDefineReservedUnused(OSSerialize, 1);
39 OSMetaClassDefineReservedUnused(OSSerialize, 2);
40 OSMetaClassDefineReservedUnused(OSSerialize, 3);
41 OSMetaClassDefineReservedUnused(OSSerialize, 4);
42 OSMetaClassDefineReservedUnused(OSSerialize, 5);
43 OSMetaClassDefineReservedUnused(OSSerialize, 6);
44 OSMetaClassDefineReservedUnused(OSSerialize, 7);
45 
46 #if OSALLOCDEBUG
47 extern "C" {
48     extern int debug_container_malloc_size;
49 };
50 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
51 #else
52 #define ACCUMSIZE(s)
53 #endif
54 
55 char * OSSerialize::text() const
56 {
57 	return data;
58 }
59 
60 void OSSerialize::clearText()
61 {
62 	bzero((void *)data, capacity);
63 	length = 1;
64 	tag = 0;
65 	tags->flushCollection();
66 }
67 
68 bool OSSerialize::previouslySerialized(const OSMetaClassBase *o)
69 {
70 	char temp[16];
71 	OSString *tagString;
72 
73 	// look it up
74 	tagString = (OSString *)tags->getObject((const OSSymbol *) o);
75 
76 	// does it exist?
77 	if (tagString) {
78 		addString("<reference IDREF=\"");
79 		addString(tagString->getCStringNoCopy());
80 		addString("\"/>");
81 		return true;
82 	}
83 
84 	// build a tag
85 	sprintf(temp, "%u", tag++);
86 	tagString = OSString::withCString(temp);
87 
88 	// add to tag dictionary
89         tags->setObject((const OSSymbol *) o, tagString);// XXX check return
90 	tagString->release();
91 
92 	return false;
93 }
94 
95 bool OSSerialize::addXMLStartTag(const OSMetaClassBase *o, const char *tagString)
96 {
97 
98 	if (!addChar('<')) return false;
99 	if (!addString(tagString)) return false;
100 	if (!addString(" ID=\"")) return false;
101 	if (!addString(((OSString *)tags->getObject((const OSSymbol *)o))->getCStringNoCopy()))
102 		return false;
103 	if (!addChar('\"')) return false;
104 	if (!addChar('>')) return false;
105 	return true;
106 }
107 
108 bool OSSerialize::addXMLEndTag(const char *tagString)
109 {
110 
111 	if (!addChar('<')) return false;
112 	if (!addChar('/')) return false;
113 	if (!addString(tagString)) return false;
114 	if (!addChar('>')) return false;
115 	return true;
116 }
117 
118 bool OSSerialize::addChar(const char c)
119 {
120 	// add char, possibly extending our capacity
121 	if (length >= capacity && length >=ensureCapacity(capacity+capacityIncrement))
122 		return false;
123 
124 	data[length - 1] = c;
125 	length++;
126 
127 	return true;
128 }
129 
130 bool OSSerialize::addString(const char *s)
131 {
132 	bool rc = false;
133 
134 	while (*s && (rc = addChar(*s++))) ;
135 
136 	return rc;
137 }
138 
139 bool OSSerialize::initWithCapacity(unsigned int inCapacity)
140 {
141     if (!super::init())
142             return false;
143 
144     tags = OSDictionary::withCapacity(32);
145     if (!tags) {
146         return false;
147     }
148 
149     tag = 0;
150     length = 1;
151     capacity = (inCapacity) ? round_page_32(inCapacity) : round_page_32(1);
152     capacityIncrement = capacity;
153 
154     // allocate from the kernel map so that we can safely map this data
155     // into user space (the primary use of the OSSerialize object)
156 
157     kern_return_t rc = kmem_alloc(kernel_map, (vm_offset_t *)&data, capacity);
158     if (rc) {
159         tags->release();
160         tags = 0;
161         return false;
162     }
163     bzero((void *)data, capacity);
164 
165 
166     ACCUMSIZE(capacity);
167 
168     return true;
169 }
170 
171 OSSerialize *OSSerialize::withCapacity(unsigned int inCapacity)
172 {
173 	OSSerialize *me = new OSSerialize;
174 
175 	if (me && !me->initWithCapacity(inCapacity)) {
176 		me->release();
177 		return 0;
178 	}
179 
180 	return me;
181 }
182 
183 unsigned int OSSerialize::getLength() const { return length; }
184 unsigned int OSSerialize::getCapacity() const { return capacity; }
185 unsigned int OSSerialize::getCapacityIncrement() const { return capacityIncrement; }
186 unsigned int OSSerialize::setCapacityIncrement(unsigned int increment)
187 {
188     capacityIncrement = (increment)? increment : 256;
189     return capacityIncrement;
190 }
191 
192 unsigned int OSSerialize::ensureCapacity(unsigned int newCapacity)
193 {
194 	char *newData;
195 
196 	if (newCapacity <= capacity)
197 		return capacity;
198 
199 	// round up
200 	newCapacity = round_page_32(newCapacity);
201 
202 	kern_return_t rc = kmem_realloc(kernel_map,
203 					(vm_offset_t)data,
204 					capacity,
205 					(vm_offset_t *)&newData,
206 					newCapacity);
207 	if (!rc) {
208 	    ACCUMSIZE(newCapacity);
209 
210 	    // kmem realloc does not free the old address range
211 	    kmem_free(kernel_map, (vm_offset_t)data, capacity);
212 	    ACCUMSIZE(-capacity);
213 
214 	    // kmem realloc does not zero out the new memory
215 	    // and this could end up going to user land
216 	    bzero(&newData[capacity], newCapacity - capacity);
217 
218 	    data = newData;
219 	    capacity = newCapacity;
220 	}
221 
222 	return capacity;
223 }
224 
225 void OSSerialize::free()
226 {
227     if (tags)
228         tags->release();
229 
230     if (data) {
231 	kmem_free(kernel_map, (vm_offset_t)data, capacity);
232         ACCUMSIZE( -capacity );
233     }
234     super::free();
235 }
236 
237 
238 OSDefineMetaClassAndStructors(OSSerializer, OSObject)
239 
240 OSSerializer * OSSerializer::forTarget( void * target,
241                                OSSerializerCallback callback, void * ref )
242 {
243     OSSerializer * thing;
244 
245     thing = new OSSerializer;
246     if( thing && !thing->init()) {
247 	thing->release();
248 	thing = 0;
249     }
250 
251     if( thing) {
252 	thing->target	= target;
253         thing->ref	= ref;
254         thing->callback = callback;
255     }
256     return( thing );
257 }
258 
259 bool OSSerializer::serialize( OSSerialize * s ) const
260 {
261     return( (*callback)(target, ref, s) );
262 }
263