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 34 __BEGIN_DECLS 35 #include <vm/vm_kern.h> 36 __END_DECLS 37 38 #include <libkern/c++/OSContainers.h> 39 #include <libkern/c++/OSLib.h> 40 #include <libkern/c++/OSDictionary.h> 41 #include <libkern/c++/OSSharedPtr.h> 42 #include <libkern/OSSerializeBinary.h> 43 #include <libkern/Block.h> 44 #include <IOKit/IOLib.h> 45 46 #define super OSObject 47 48 OSDefineMetaClassAndStructors(OSSerialize, OSObject) 49 OSMetaClassDefineReservedUnused(OSSerialize, 0); 50 OSMetaClassDefineReservedUnused(OSSerialize, 1); 51 OSMetaClassDefineReservedUnused(OSSerialize, 2); 52 OSMetaClassDefineReservedUnused(OSSerialize, 3); 53 OSMetaClassDefineReservedUnused(OSSerialize, 4); 54 OSMetaClassDefineReservedUnused(OSSerialize, 5); 55 OSMetaClassDefineReservedUnused(OSSerialize, 6); 56 OSMetaClassDefineReservedUnused(OSSerialize, 7); 57 58 59 char * 60 OSSerialize::text() const 61 { 62 return data; 63 } 64 65 void 66 OSSerialize::clearText() 67 { 68 if (binary) { 69 length = sizeof(kOSSerializeBinarySignature); 70 bzero(&data[length], capacity - length); 71 endCollection = true; 72 } else { 73 bzero((void *)data, capacity); 74 length = 1; 75 } 76 tags->flushCollection(); 77 } 78 79 bool 80 OSSerialize::previouslySerialized(const OSMetaClassBase *o) 81 { 82 char temp[16]; 83 unsigned int tagIdx; 84 85 if (binary) { 86 return binarySerialize(o); 87 } 88 89 // look it up 90 tagIdx = tags->getNextIndexOfObject(o, 0); 91 92 // xx-review: no error checking here for addString calls! 93 // does it exist? 94 if (tagIdx != -1U) { 95 addString("<reference IDREF=\""); 96 snprintf(temp, sizeof(temp), "%u", tagIdx); 97 addString(temp); 98 addString("\"/>"); 99 return true; 100 } 101 102 // add to tag array 103 tags->setObject(o);// XXX check return 104 105 return false; 106 } 107 108 bool 109 OSSerialize::addXMLStartTag(const OSMetaClassBase *o, const char *tagString) 110 { 111 char temp[16]; 112 unsigned int tagIdx; 113 114 if (binary) { 115 printf("class %s: xml serialize\n", o->getMetaClass()->getClassName()); 116 return false; 117 } 118 119 if (!addChar('<')) { 120 return false; 121 } 122 if (!addString(tagString)) { 123 return false; 124 } 125 if (!addString(" ID=\"")) { 126 return false; 127 } 128 tagIdx = tags->getNextIndexOfObject(o, 0); 129 assert(tagIdx != -1U); 130 snprintf(temp, sizeof(temp), "%u", tagIdx); 131 if (!addString(temp)) { 132 return false; 133 } 134 if (!addChar('\"')) { 135 return false; 136 } 137 if (!addChar('>')) { 138 return false; 139 } 140 return true; 141 } 142 143 bool 144 OSSerialize::addXMLEndTag(const char *tagString) 145 { 146 if (!addChar('<')) { 147 return false; 148 } 149 if (!addChar('/')) { 150 return false; 151 } 152 if (!addString(tagString)) { 153 return false; 154 } 155 if (!addChar('>')) { 156 return false; 157 } 158 return true; 159 } 160 161 bool 162 OSSerialize::addChar(const char c) 163 { 164 if (binary) { 165 printf("xml serialize\n"); 166 return false; 167 } 168 169 // add char, possibly extending our capacity 170 if (length >= capacity && length >= ensureCapacity(capacity + capacityIncrement)) { 171 return false; 172 } 173 174 data[length - 1] = c; 175 length++; 176 177 return true; 178 } 179 180 bool 181 OSSerialize::addString(const char *s) 182 { 183 bool rc = false; 184 185 while (*s && (rc = addChar(*s++))) { 186 ; 187 } 188 189 return rc; 190 } 191 192 bool 193 OSSerialize::initWithCapacity(unsigned int inCapacity) 194 { 195 if (!super::init()) { 196 return false; 197 } 198 199 tags = OSArray::withCapacity(256); 200 if (!tags) { 201 return false; 202 } 203 204 length = 1; 205 206 if (!inCapacity) { 207 inCapacity = 1; 208 } 209 if (round_page_overflow(inCapacity, &capacity)) { 210 tags.reset(); 211 return false; 212 } 213 214 capacityIncrement = capacity; 215 216 // allocate from the kernel map so that we can safely map this data 217 // into user space (the primary use of the OSSerialize object) 218 219 kern_return_t rc = kmem_alloc(kernel_map, (vm_offset_t *)&data, capacity, IOMemoryTag(kernel_map)); 220 if (rc) { 221 return false; 222 } 223 bzero((void *)data, capacity); 224 225 226 OSCONTAINER_ACCUMSIZE(capacity); 227 228 return true; 229 } 230 231 OSSharedPtr<OSSerialize> 232 OSSerialize::withCapacity(unsigned int inCapacity) 233 { 234 OSSharedPtr<OSSerialize> me = OSMakeShared<OSSerialize>(); 235 236 if (me && !me->initWithCapacity(inCapacity)) { 237 return nullptr; 238 } 239 240 return me; 241 } 242 243 unsigned int 244 OSSerialize::getLength() const 245 { 246 return length; 247 } 248 unsigned int 249 OSSerialize::getCapacity() const 250 { 251 return capacity; 252 } 253 unsigned int 254 OSSerialize::getCapacityIncrement() const 255 { 256 return capacityIncrement; 257 } 258 unsigned int 259 OSSerialize::setCapacityIncrement(unsigned int increment) 260 { 261 capacityIncrement = (increment)? increment : 256; 262 return capacityIncrement; 263 } 264 265 unsigned int 266 OSSerialize::ensureCapacity(unsigned int newCapacity) 267 { 268 char *newData; 269 270 if (newCapacity <= capacity) { 271 return capacity; 272 } 273 274 if (round_page_overflow(newCapacity, &newCapacity)) { 275 return capacity; 276 } 277 278 kern_return_t rc = kmem_realloc(kernel_map, 279 (vm_offset_t)data, 280 capacity, 281 (vm_offset_t *)&newData, 282 newCapacity, 283 VM_KERN_MEMORY_IOKIT); 284 if (!rc) { 285 OSCONTAINER_ACCUMSIZE(newCapacity); 286 287 // kmem realloc does not free the old address range 288 kmem_free(kernel_map, (vm_offset_t)data, capacity); 289 OSCONTAINER_ACCUMSIZE(-((size_t)capacity)); 290 291 // kmem realloc does not zero out the new memory 292 // and this could end up going to user land 293 bzero(&newData[capacity], newCapacity - capacity); 294 295 data = newData; 296 capacity = newCapacity; 297 } 298 299 return capacity; 300 } 301 302 void 303 OSSerialize::free() 304 { 305 if (data) { 306 kmem_free(kernel_map, (vm_offset_t)data, capacity); 307 OSCONTAINER_ACCUMSIZE( -((size_t)capacity)); 308 } 309 super::free(); 310 } 311 312 313 OSDefineMetaClassAndStructors(OSSerializer, OSObject) 314 315 OSSharedPtr<OSSerializer> 316 OSSerializer::forTarget( void * target, 317 OSSerializerCallback callback, void * ref ) 318 { 319 OSSharedPtr<OSSerializer> thing = OSMakeShared<OSSerializer>(); 320 321 if (thing && !thing->init()) { 322 thing.reset(); 323 } 324 325 if (thing) { 326 thing->target = target; 327 thing->ref = ref; 328 thing->callback = callback; 329 } 330 return thing; 331 } 332 333 bool 334 OSSerializer::callbackToBlock(void * target __unused, void * ref, 335 OSSerialize * serializer) 336 { 337 return ((OSSerializerBlock)ref)(serializer); 338 } 339 340 OSSharedPtr<OSSerializer> 341 OSSerializer::withBlock( 342 OSSerializerBlock callback) 343 { 344 OSSharedPtr<OSSerializer> serializer; 345 OSSerializerBlock block; 346 347 block = Block_copy(callback); 348 if (!block) { 349 return NULL; 350 } 351 352 serializer = (OSSerializer::forTarget(NULL, &OSSerializer::callbackToBlock, block)); 353 354 if (!serializer) { 355 Block_release(block); 356 } 357 358 return serializer; 359 } 360 361 void 362 OSSerializer::free(void) 363 { 364 if (callback == &callbackToBlock) { 365 Block_release(ref); 366 } 367 368 super::free(); 369 } 370 371 bool 372 OSSerializer::serialize( OSSerialize * s ) const 373 { 374 return (*callback)(target, ref, s); 375 } 376