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 #define IOKIT_ENABLE_SHARED_PTR 31 32 #include <sys/cdefs.h> 33 #include <vm/vm_kern.h> 34 35 #include <libkern/c++/OSContainers.h> 36 #include <libkern/c++/OSLib.h> 37 #include <libkern/c++/OSDictionary.h> 38 #include <libkern/c++/OSSharedPtr.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.reset(); 208 return false; 209 } 210 211 capacityIncrement = capacity; 212 213 // allocate from the kernel map so that we can safely map this data 214 // into user space (the primary use of the OSSerialize object) 215 216 kern_return_t rc = kmem_alloc(kernel_map, (vm_offset_t *)&data, capacity, IOMemoryTag(kernel_map)); 217 if (rc) { 218 return false; 219 } 220 bzero((void *)data, capacity); 221 222 223 OSCONTAINER_ACCUMSIZE(capacity); 224 225 return true; 226 } 227 228 OSSharedPtr<OSSerialize> 229 OSSerialize::withCapacity(unsigned int inCapacity) 230 { 231 OSSharedPtr<OSSerialize> me = OSMakeShared<OSSerialize>(); 232 233 if (me && !me->initWithCapacity(inCapacity)) { 234 return nullptr; 235 } 236 237 return me; 238 } 239 240 unsigned int 241 OSSerialize::getLength() const 242 { 243 return length; 244 } 245 unsigned int 246 OSSerialize::getCapacity() const 247 { 248 return capacity; 249 } 250 unsigned int 251 OSSerialize::getCapacityIncrement() const 252 { 253 return capacityIncrement; 254 } 255 unsigned int 256 OSSerialize::setCapacityIncrement(unsigned int increment) 257 { 258 capacityIncrement = (increment)? increment : 256; 259 return capacityIncrement; 260 } 261 262 unsigned int 263 OSSerialize::ensureCapacity(unsigned int newCapacity) 264 { 265 char *newData; 266 267 if (newCapacity <= capacity) { 268 return capacity; 269 } 270 271 if (round_page_overflow(newCapacity, &newCapacity)) { 272 return capacity; 273 } 274 275 kern_return_t rc = kmem_realloc(kernel_map, 276 (vm_offset_t)data, 277 capacity, 278 (vm_offset_t *)&newData, 279 newCapacity, 280 VM_KERN_MEMORY_IOKIT); 281 if (!rc) { 282 OSCONTAINER_ACCUMSIZE(newCapacity); 283 284 // kmem realloc does not free the old address range 285 kmem_free(kernel_map, (vm_offset_t)data, capacity); 286 OSCONTAINER_ACCUMSIZE(-((size_t)capacity)); 287 288 // kmem realloc does not zero out the new memory 289 // and this could end up going to user land 290 bzero(&newData[capacity], newCapacity - capacity); 291 292 data = newData; 293 capacity = newCapacity; 294 } 295 296 return capacity; 297 } 298 299 void 300 OSSerialize::free() 301 { 302 if (data) { 303 kmem_free(kernel_map, (vm_offset_t)data, capacity); 304 OSCONTAINER_ACCUMSIZE( -((size_t)capacity)); 305 } 306 super::free(); 307 } 308 309 310 OSDefineMetaClassAndStructors(OSSerializer, OSObject) 311 312 OSSharedPtr<OSSerializer> 313 OSSerializer::forTarget( void * target, 314 OSSerializerCallback callback, void * ref ) 315 { 316 OSSharedPtr<OSSerializer> thing = OSMakeShared<OSSerializer>(); 317 318 if (thing && !thing->init()) { 319 thing.reset(); 320 } 321 322 if (thing) { 323 thing->target = target; 324 thing->ref = ref; 325 thing->callback = callback; 326 } 327 return thing; 328 } 329 330 bool 331 OSSerializer::callbackToBlock(void * target __unused, void * ref, 332 OSSerialize * serializer) 333 { 334 return ((OSSerializerBlock)ref)(serializer); 335 } 336 337 OSSharedPtr<OSSerializer> 338 OSSerializer::withBlock( 339 OSSerializerBlock callback) 340 { 341 OSSharedPtr<OSSerializer> serializer; 342 OSSerializerBlock block; 343 344 block = Block_copy(callback); 345 if (!block) { 346 return NULL; 347 } 348 349 serializer = (OSSerializer::forTarget(NULL, &OSSerializer::callbackToBlock, block)); 350 351 if (!serializer) { 352 Block_release(block); 353 } 354 355 return serializer; 356 } 357 358 void 359 OSSerializer::free(void) 360 { 361 if (callback == &callbackToBlock) { 362 Block_release(ref); 363 } 364 365 super::free(); 366 } 367 368 bool 369 OSSerializer::serialize( OSSerialize * s ) const 370 { 371 return (*callback)(target, ref, s); 372 } 373