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