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