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 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 55 56 char * 57 OSSerialize::text() const 58 { 59 return data; 60 } 61 62 void 63 OSSerialize::clearText() 64 { 65 if (binary) { 66 length = sizeof(kOSSerializeBinarySignature); 67 bzero(&data[length], capacity - length); 68 endCollection = true; 69 } else { 70 bzero((void *)data, capacity); 71 length = 1; 72 } 73 tags->flushCollection(); 74 } 75 76 bool 77 OSSerialize::previouslySerialized(const OSMetaClassBase *o) 78 { 79 char temp[16]; 80 unsigned int tagIdx; 81 82 if (binary) { 83 return binarySerialize(o); 84 } 85 86 // look it up 87 tagIdx = tags->getNextIndexOfObject(o, 0); 88 89 // xx-review: no error checking here for addString calls! 90 // does it exist? 91 if (tagIdx != -1U) { 92 addString("<reference IDREF=\""); 93 snprintf(temp, sizeof(temp), "%u", tagIdx); 94 addString(temp); 95 addString("\"/>"); 96 return true; 97 } 98 99 // add to tag array 100 tags->setObject(o);// XXX check return 101 102 return false; 103 } 104 105 bool 106 OSSerialize::addXMLStartTag(const OSMetaClassBase *o, const char *tagString) 107 { 108 char temp[16]; 109 unsigned int tagIdx; 110 111 if (binary) { 112 printf("class %s: xml serialize\n", o->getMetaClass()->getClassName()); 113 return false; 114 } 115 116 if (!addChar('<')) { 117 return false; 118 } 119 if (!addString(tagString)) { 120 return false; 121 } 122 if (!addString(" ID=\"")) { 123 return false; 124 } 125 tagIdx = tags->getNextIndexOfObject(o, 0); 126 assert(tagIdx != -1U); 127 snprintf(temp, sizeof(temp), "%u", tagIdx); 128 if (!addString(temp)) { 129 return false; 130 } 131 if (!addChar('\"')) { 132 return false; 133 } 134 if (!addChar('>')) { 135 return false; 136 } 137 return true; 138 } 139 140 bool 141 OSSerialize::addXMLEndTag(const char *tagString) 142 { 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 } 155 return true; 156 } 157 158 bool 159 OSSerialize::addChar(const char c) 160 { 161 if (binary) { 162 printf("xml serialize\n"); 163 return false; 164 } 165 166 // add char, possibly extending our capacity 167 if (length >= capacity && length >= ensureCapacity(capacity + capacityIncrement)) { 168 return false; 169 } 170 171 data[length - 1] = c; 172 length++; 173 174 return true; 175 } 176 177 bool 178 OSSerialize::addString(const char *s) 179 { 180 bool rc = false; 181 182 while (*s && (rc = addChar(*s++))) { 183 ; 184 } 185 186 return rc; 187 } 188 189 bool 190 OSSerialize::initWithCapacity(unsigned int inCapacity) 191 { 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(); 208 tags = NULL; 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(); 220 tags = NULL; 221 return false; 222 } 223 bzero((void *)data, capacity); 224 225 226 OSCONTAINER_ACCUMSIZE(capacity); 227 228 return true; 229 } 230 231 OSSerialize * 232 OSSerialize::withCapacity(unsigned int inCapacity) 233 { 234 OSSerialize *me = new OSSerialize; 235 236 if (me && !me->initWithCapacity(inCapacity)) { 237 me->release(); 238 return NULL; 239 } 240 241 return me; 242 } 243 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 256 { 257 return capacityIncrement; 258 } 259 unsigned int 260 OSSerialize::setCapacityIncrement(unsigned int increment) 261 { 262 capacityIncrement = (increment)? increment : 256; 263 return capacityIncrement; 264 } 265 266 unsigned int 267 OSSerialize::ensureCapacity(unsigned int newCapacity) 268 { 269 char *newData; 270 271 if (newCapacity <= capacity) { 272 return capacity; 273 } 274 275 if (round_page_overflow(newCapacity, &newCapacity)) { 276 return capacity; 277 } 278 279 kern_return_t rc = kmem_realloc(kernel_map, 280 (vm_offset_t)data, 281 capacity, 282 (vm_offset_t *)&newData, 283 newCapacity, 284 VM_KERN_MEMORY_IOKIT); 285 if (!rc) { 286 OSCONTAINER_ACCUMSIZE(newCapacity); 287 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; 298 } 299 300 return capacity; 301 } 302 303 void 304 OSSerialize::free() 305 { 306 OSSafeReleaseNULL(tags); 307 OSSafeReleaseNULL(indexData); 308 309 if (data) { 310 kmem_free(kernel_map, (vm_offset_t)data, capacity); 311 OSCONTAINER_ACCUMSIZE( -((size_t)capacity)); 312 } 313 super::free(); 314 } 315 316 317 OSDefineMetaClassAndStructors(OSSerializer, OSObject) 318 319 OSSerializer * OSSerializer::forTarget( void * target, 320 OSSerializerCallback callback, void * ref ) 321 { 322 OSSerializer * thing; 323 324 thing = new OSSerializer; 325 if (thing && !thing->init()) { 326 thing->release(); 327 thing = NULL; 328 } 329 330 if (thing) { 331 thing->target = target; 332 thing->ref = ref; 333 thing->callback = callback; 334 } 335 return thing; 336 } 337 338 bool 339 OSSerializer::callbackToBlock(void * target __unused, void * ref, 340 OSSerialize * serializer) 341 { 342 return ((OSSerializerBlock)ref)(serializer); 343 } 344 345 OSSerializer * 346 OSSerializer::withBlock( 347 OSSerializerBlock callback) 348 { 349 OSSerializer * serializer; 350 OSSerializerBlock block; 351 352 block = Block_copy(callback); 353 if (!block) { 354 return NULL; 355 } 356 357 serializer = (OSSerializer::forTarget(NULL, &OSSerializer::callbackToBlock, block)); 358 359 if (!serializer) { 360 Block_release(block); 361 } 362 363 return serializer; 364 } 365 366 void 367 OSSerializer::free(void) 368 { 369 if (callback == &callbackToBlock) { 370 Block_release(ref); 371 } 372 373 super::free(); 374 } 375 376 bool 377 OSSerializer::serialize( OSSerialize * s ) const 378 { 379 return (*callback)(target, ref, s); 380 } 381