#define IOKIT_ENABLE_SHARED_PTR
#include <sys/cdefs.h>
__BEGIN_DECLS
#include <vm/vm_kern.h>
__END_DECLS
#include <libkern/c++/OSContainers.h>
#include <libkern/c++/OSLib.h>
#include <libkern/c++/OSDictionary.h>
#include <libkern/c++/OSSharedPtr.h>
#include <libkern/OSSerializeBinary.h>
#include <libkern/Block.h>
#include <IOKit/IOLib.h>
#define super OSObject
OSDefineMetaClassAndStructors(OSSerialize, OSObject)
OSMetaClassDefineReservedUnused(OSSerialize, 0);
OSMetaClassDefineReservedUnused(OSSerialize, 1);
OSMetaClassDefineReservedUnused(OSSerialize, 2);
OSMetaClassDefineReservedUnused(OSSerialize, 3);
OSMetaClassDefineReservedUnused(OSSerialize, 4);
OSMetaClassDefineReservedUnused(OSSerialize, 5);
OSMetaClassDefineReservedUnused(OSSerialize, 6);
OSMetaClassDefineReservedUnused(OSSerialize, 7);
char *
OSSerialize::text() const
{
return data;
}
void
OSSerialize::clearText()
{
if (binary) {
length = sizeof(kOSSerializeBinarySignature);
bzero(&data[length], capacity - length);
endCollection = true;
} else {
bzero((void *)data, capacity);
length = 1;
}
tags->flushCollection();
}
bool
OSSerialize::previouslySerialized(const OSMetaClassBase *o)
{
char temp[16];
unsigned int tagIdx;
if (binary) {
return binarySerialize(o);
}
tagIdx = tags->getNextIndexOfObject(o, 0);
if (tagIdx != -1U) {
addString("<reference IDREF=\"");
snprintf(temp, sizeof(temp), "%u", tagIdx);
addString(temp);
addString("\"/>");
return true;
}
tags->setObject(o);
return false;
}
bool
OSSerialize::addXMLStartTag(const OSMetaClassBase *o, const char *tagString)
{
char temp[16];
unsigned int tagIdx;
if (binary) {
printf("class %s: xml serialize\n", o->getMetaClass()->getClassName());
return false;
}
if (!addChar('<')) {
return false;
}
if (!addString(tagString)) {
return false;
}
if (!addString(" ID=\"")) {
return false;
}
tagIdx = tags->getNextIndexOfObject(o, 0);
assert(tagIdx != -1U);
snprintf(temp, sizeof(temp), "%u", tagIdx);
if (!addString(temp)) {
return false;
}
if (!addChar('\"')) {
return false;
}
if (!addChar('>')) {
return false;
}
return true;
}
bool
OSSerialize::addXMLEndTag(const char *tagString)
{
if (!addChar('<')) {
return false;
}
if (!addChar('/')) {
return false;
}
if (!addString(tagString)) {
return false;
}
if (!addChar('>')) {
return false;
}
return true;
}
bool
OSSerialize::addChar(const char c)
{
if (binary) {
printf("xml serialize\n");
return false;
}
if (length >= capacity && length >= ensureCapacity(capacity + capacityIncrement)) {
return false;
}
data[length - 1] = c;
length++;
return true;
}
bool
OSSerialize::addString(const char *s)
{
bool rc = false;
while (*s && (rc = addChar(*s++))) {
;
}
return rc;
}
bool
OSSerialize::initWithCapacity(unsigned int inCapacity)
{
if (!super::init()) {
return false;
}
tags = OSArray::withCapacity(256);
if (!tags) {
return false;
}
length = 1;
if (!inCapacity) {
inCapacity = 1;
}
if (round_page_overflow(inCapacity, &capacity)) {
tags.reset();
return false;
}
capacityIncrement = capacity;
kern_return_t rc = kmem_alloc(kernel_map, (vm_offset_t *)&data, capacity, IOMemoryTag(kernel_map));
if (rc) {
return false;
}
bzero((void *)data, capacity);
OSCONTAINER_ACCUMSIZE(capacity);
return true;
}
OSSharedPtr<OSSerialize>
OSSerialize::withCapacity(unsigned int inCapacity)
{
OSSharedPtr<OSSerialize> me = OSMakeShared<OSSerialize>();
if (me && !me->initWithCapacity(inCapacity)) {
return nullptr;
}
return me;
}
unsigned int
OSSerialize::getLength() const
{
return length;
}
unsigned int
OSSerialize::getCapacity() const
{
return capacity;
}
unsigned int
OSSerialize::getCapacityIncrement() const
{
return capacityIncrement;
}
unsigned int
OSSerialize::setCapacityIncrement(unsigned int increment)
{
capacityIncrement = (increment)? increment : 256;
return capacityIncrement;
}
unsigned int
OSSerialize::ensureCapacity(unsigned int newCapacity)
{
char *newData;
if (newCapacity <= capacity) {
return capacity;
}
if (round_page_overflow(newCapacity, &newCapacity)) {
return capacity;
}
kern_return_t rc = kmem_realloc(kernel_map,
(vm_offset_t)data,
capacity,
(vm_offset_t *)&newData,
newCapacity,
VM_KERN_MEMORY_IOKIT);
if (!rc) {
OSCONTAINER_ACCUMSIZE(newCapacity);
kmem_free(kernel_map, (vm_offset_t)data, capacity);
OSCONTAINER_ACCUMSIZE(-((size_t)capacity));
bzero(&newData[capacity], newCapacity - capacity);
data = newData;
capacity = newCapacity;
}
return capacity;
}
void
OSSerialize::free()
{
if (data) {
kmem_free(kernel_map, (vm_offset_t)data, capacity);
OSCONTAINER_ACCUMSIZE( -((size_t)capacity));
}
super::free();
}
OSDefineMetaClassAndStructors(OSSerializer, OSObject)
OSSharedPtr<OSSerializer>
OSSerializer::forTarget( void * target,
OSSerializerCallback callback, void * ref )
{
OSSharedPtr<OSSerializer> thing = OSMakeShared<OSSerializer>();
if (thing && !thing->init()) {
thing.reset();
}
if (thing) {
thing->target = target;
thing->ref = ref;
thing->callback = callback;
}
return thing;
}
bool
OSSerializer::callbackToBlock(void * target __unused, void * ref,
OSSerialize * serializer)
{
return ((OSSerializerBlock)ref)(serializer);
}
OSSharedPtr<OSSerializer>
OSSerializer::withBlock(
OSSerializerBlock callback)
{
OSSharedPtr<OSSerializer> serializer;
OSSerializerBlock block;
block = Block_copy(callback);
if (!block) {
return NULL;
}
serializer = (OSSerializer::forTarget(NULL, &OSSerializer::callbackToBlock, block));
if (!serializer) {
Block_release(block);
}
return serializer;
}
void
OSSerializer::free(void)
{
if (callback == &callbackToBlock) {
Block_release(ref);
}
super::free();
}
bool
OSSerializer::serialize( OSSerialize * s ) const
{
return (*callback)(target, ref, s);
}