/* Copyright (c) 2015 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #include "dynamictypes/DataArray.h" #include "dynamictypes/DataAssociativeArray.h" #include "dynamictypes/DataHashTable.h" #include "dynamictypes/DataSerializationContext.h" #include #include #define stemobject_implementation DataSerializationContext stemobject_vtable_begin(); stemobject_vtable_entry(dispose); stemobject_vtable_entry(beginStructure); stemobject_vtable_entry(beginDictionary); stemobject_vtable_entry(beginArray); stemobject_vtable_entry(endStructure); stemobject_vtable_entry(endDictionary); stemobject_vtable_entry(endArray); stemobject_vtable_entry(writeBoolean); stemobject_vtable_entry(writeInt8); stemobject_vtable_entry(writeUInt8); stemobject_vtable_entry(writeInt16); stemobject_vtable_entry(writeUInt16); stemobject_vtable_entry(writeInt32); stemobject_vtable_entry(writeUInt32); stemobject_vtable_entry(writeInt64); stemobject_vtable_entry(writeUInt64); stemobject_vtable_entry(writeFloat); stemobject_vtable_entry(writeDouble); stemobject_vtable_entry(writeFixed16_16); stemobject_vtable_entry(writeEnumeration); stemobject_vtable_entry(writeEnumeration8); stemobject_vtable_entry(writeEnumeration16); stemobject_vtable_entry(writeEnumeration32); stemobject_vtable_entry(writeBitfield8); stemobject_vtable_entry(writeBitfield16); stemobject_vtable_entry(writeBitfield32); stemobject_vtable_entry(writeBitfield64); stemobject_vtable_entry(writeString); stemobject_vtable_entry(writeBlob); stemobject_vtable_end(); DataSerializationContext * DataSerializationContext_create() { stemobject_create_implementation(init) } bool DataSerializationContext_init(DataSerializationContext * self) { call_super(init, self); self->rootValue = valueCreateBoolean(false); self->currentValue = NULL; self->stackCount = 0; self->stack = NULL; self->finished = false; return true; } void DataSerializationContext_dispose(DataSerializationContext * self) { call_super(dispose, self); } #define failWithStatus(STATUS, RETURN_CODE) \ self->status = (STATUS); \ if (self->jmpBuf != NULL) { \ longjmp(*self->jmpBuf, self->status); \ } \ RETURN_CODE DataValue * DataSerializationContext_result(DataSerializationContext * self) { if (!self->finished) { failWithStatus(SERIALIZATION_ERROR_NO_TOP_LEVEL_CONTAINER, return NULL); } return &self->rootValue; } static void pushContainer(DataSerializationContext * self, const char * key, DataValue container) { if (self->currentValue == NULL) { if (self->finished) { failWithStatus(SERIALIZATION_ERROR_MULTIPLE_TOP_LEVEL_CONTAINERS, return); } self->rootValue = container; self->currentValue = &self->rootValue; } else { self->stack = realloc(self->stack, sizeof(DataValue *) * (self->stackCount + 1)); self->stack[self->stackCount++] = self->currentValue; switch (self->currentValue->type) { case DATA_TYPE_ARRAY: arrayAppend(self->currentValue->value.array, container); self->currentValue = arrayGet(self->currentValue->value.array, self->currentValue->value.array->count - 1); break; case DATA_TYPE_HASH_TABLE: hashSet(self->currentValue->value.hashTable, key, container); self->currentValue = hashGet(self->currentValue->value.hashTable, key); break; case DATA_TYPE_ASSOCIATIVE_ARRAY: associativeArrayAppend(self->currentValue->value.associativeArray, key, container); self->currentValue = associativeArrayGetValueAtIndex(self->currentValue->value.associativeArray, self->currentValue->value.associativeArray->count - 1); break; default: break; } } } void DataSerializationContext_beginStructure(DataSerializationContext * self, const char * key) { pushContainer(self, key, valueCreateHashTable(hashCreate(), true, false)); } void DataSerializationContext_beginDictionary(DataSerializationContext * self, const char * key) { pushContainer(self, key, valueCreateAssociativeArray(associativeArrayCreate(), true, false)); } void DataSerializationContext_beginArray(DataSerializationContext * self, const char * key) { pushContainer(self, key, valueCreateArray(arrayCreate(), true, false)); } static void popContainer(DataSerializationContext * self, DataValueType type) { if (self->currentValue == NULL) { failWithStatus(SERIALIZATION_ERROR_CONTAINER_UNDERFLOW, return); } if (self->currentValue->type != type) { failWithStatus(SERIALIZATION_ERROR_CONTAINER_TYPE_MISMATCH, return); } if (self->stackCount > 0) { self->currentValue = self->stack[--self->stackCount]; } else { self->currentValue = NULL; self->finished = true; } } void DataSerializationContext_endStructure(DataSerializationContext * self) { popContainer(self, DATA_TYPE_HASH_TABLE); } void DataSerializationContext_endDictionary(DataSerializationContext * self) { popContainer(self, DATA_TYPE_ASSOCIATIVE_ARRAY); } void DataSerializationContext_endArray(DataSerializationContext * self) { popContainer(self, DATA_TYPE_ARRAY); } static void writeValue(DataSerializationContext * self, const char * key, DataValue value) { if (self->currentValue == NULL) { failWithStatus(SERIALIZATION_ERROR_NO_CONTAINER_STARTED, return); } switch (self->currentValue->type) { case DATA_TYPE_ARRAY: arrayAppend(self->currentValue->value.array, value); break; case DATA_TYPE_HASH_TABLE: if (key == NULL) { failWithStatus(SERIALIZATION_ERROR_NULL_KEY, return); } hashSet(self->currentValue->value.hashTable, key, value); break; case DATA_TYPE_ASSOCIATIVE_ARRAY: if (key == NULL) { failWithStatus(SERIALIZATION_ERROR_NULL_KEY, return); } associativeArrayAppend(self->currentValue->value.associativeArray, key, value); break; default: break; } } void DataSerializationContext_writeBoolean(DataSerializationContext * self, const char * key, bool value) { writeValue(self, key, valueCreateBoolean(value)); } void DataSerializationContext_writeInt8(DataSerializationContext * self, const char * key, int8_t value) { writeValue(self, key, valueCreateInt8(value)); } void DataSerializationContext_writeUInt8(DataSerializationContext * self, const char * key, uint8_t value) { writeValue(self, key, valueCreateUInt8(value)); } void DataSerializationContext_writeInt16(DataSerializationContext * self, const char * key, int16_t value) { writeValue(self, key, valueCreateInt16(value)); } void DataSerializationContext_writeUInt16(DataSerializationContext * self, const char * key, uint16_t value) { writeValue(self, key, valueCreateUInt16(value)); } void DataSerializationContext_writeInt32(DataSerializationContext * self, const char * key, int32_t value) { writeValue(self, key, valueCreateInt32(value)); } void DataSerializationContext_writeUInt32(DataSerializationContext * self, const char * key, uint32_t value) { writeValue(self, key, valueCreateUInt32(value)); } void DataSerializationContext_writeInt64(DataSerializationContext * self, const char * key, int64_t value) { writeValue(self, key, valueCreateInt64(value)); } void DataSerializationContext_writeUInt64(DataSerializationContext * self, const char * key, uint64_t value) { writeValue(self, key, valueCreateUInt64(value)); } void DataSerializationContext_writeFloat(DataSerializationContext * self, const char * key, float value) { writeValue(self, key, valueCreateFloat(value)); } void DataSerializationContext_writeDouble(DataSerializationContext * self, const char * key, double value) { writeValue(self, key, valueCreateDouble(value)); } void DataSerializationContext_writeFixed16_16(DataSerializationContext * self, const char * key, fixed16_16 value) { writeValue(self, key, valueCreateFixed16_16(value)); } void DataSerializationContext_writeEnumeration(DataSerializationContext * self, const char * key, int value, unsigned int valueCount, Serialization_enumKeyValue * values) { call_virtual(writeEnumeration32, self, key, value, valueCount, values); } void DataSerializationContext_writeEnumeration8(DataSerializationContext * self, const char * key, int8_t value, unsigned int valueCount, Serialization_enumKeyValue * values) { int status = Serialization_checkEnumerationErrors(value, valueCount, values); if (status != SERIALIZATION_ERROR_OK) { failWithStatus(status, return); } writeValue(self, key, valueCreateInt8(value)); } void DataSerializationContext_writeEnumeration16(DataSerializationContext * self, const char * key, int16_t value, unsigned int valueCount, Serialization_enumKeyValue * values) { int status = Serialization_checkEnumerationErrors(value, valueCount, values); if (status != SERIALIZATION_ERROR_OK) { failWithStatus(status, return); } writeValue(self, key, valueCreateInt16(value)); } void DataSerializationContext_writeEnumeration32(DataSerializationContext * self, const char * key, int32_t value, unsigned int valueCount, Serialization_enumKeyValue * values) { int status = Serialization_checkEnumerationErrors(value, valueCount, values); if (status != SERIALIZATION_ERROR_OK) { failWithStatus(status, return); } writeValue(self, key, valueCreateInt32(value)); } #define writeBitfieldImplementation(BIT_COUNT) \ int status = Serialization_checkBitfield##BIT_COUNT##Errors(value, bitNameCount, bitNames); \ if (status != SERIALIZATION_ERROR_OK) { \ failWithStatus(status, return); \ } \ writeValue(self, key, valueCreateUInt##BIT_COUNT(value)) void DataSerializationContext_writeBitfield8(DataSerializationContext * self, const char * key, uint8_t value, unsigned int bitNameCount, Serialization_bitName * bitNames) { writeBitfieldImplementation(8); } void DataSerializationContext_writeBitfield16(DataSerializationContext * self, const char * key, uint16_t value, unsigned int bitNameCount, Serialization_bitName * bitNames) { writeBitfieldImplementation(16); } void DataSerializationContext_writeBitfield32(DataSerializationContext * self, const char * key, uint32_t value, unsigned int bitNameCount, Serialization_bitName * bitNames) { writeBitfieldImplementation(32); } void DataSerializationContext_writeBitfield64(DataSerializationContext * self, const char * key, uint64_t value, unsigned int bitNameCount, Serialization_bitName * bitNames) { writeBitfieldImplementation(64); } void DataSerializationContext_writeString(DataSerializationContext * self, const char * key, const char * value) { writeValue(self, key, valueCreateString(value, DATA_USE_STRLEN, true, true)); } void DataSerializationContext_writeBlob(DataSerializationContext * self, const char * key, const void * value, size_t length) { writeValue(self, key, valueCreateBlob(value, length, true, true)); }