diff options
Diffstat (limited to 'collection/elapi_util.c')
-rw-r--r-- | collection/elapi_util.c | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/collection/elapi_util.c b/collection/elapi_util.c new file mode 100644 index 0000000..1224c25 --- /dev/null +++ b/collection/elapi_util.c @@ -0,0 +1,499 @@ +/* Copyright */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include "elapi_collection.h" +#include "elapi_debug.h" +#include "elapi_util.h" + +/* Return a static string based on type of the element */ +const char *get_type(int type) +{ + switch(type) { + case ELAPI_TYPE_STRING: return ELAPI_TYPE_NAME_STRING; + case ELAPI_TYPE_INTEGER: return ELAPI_TYPE_NAME_INTEGER; + case ELAPI_TYPE_UNSIGNED: return ELAPI_TYPE_NAME_UNSIGNED; + case ELAPI_TYPE_LONG: return ELAPI_TYPE_NAME_LONG; + case ELAPI_TYPE_ULONG: return ELAPI_TYPE_NAME_ULONG; + case ELAPI_TYPE_BINARY: return ELAPI_TYPE_NAME_BINARY; + default: return ELAPI_TYPE_NAME_UNKNOWN; + } + +} + +/* Calculate the potential size of the item */ +int get_data_len(int type, int length) +{ + int len = 0; + + DEBUG_STRING("util_get_item_len","Entry point"); + + switch(type) { + case ELAPI_TYPE_INTEGER: + case ELAPI_TYPE_UNSIGNED: + case ELAPI_TYPE_LONG: + case ELAPI_TYPE_ULONG: + len = 15; + break; + case ELAPI_TYPE_STRING: + case ELAPI_TYPE_BINARY: + len = length * 2 + 2; + break; + case ELAPI_TYPE_DOUBLE: + len = 64; + break; + default: + len = 0; + break; + } + + DEBUG_STRING("util_get_item_len","Exit point"); + + return len; +} + +/* Copy data escaping characters */ +static int copy_esc(char *dest,char *source,char esc) +{ + int i=0; + int j=0; + + *(dest +j) = esc; + j++; + + while(*(source+i) != '\0') { + if((*(source+i) == '\\') || + (*(source+i) == esc)) { + + *(dest +j) = '\\'; + j++; + + } + *(dest +j) = *(source +i); + i++; + j++; + } + *(dest +j) = esc; + j++; + + return j; +} + + + +/* Grow buffer to accomodate more space */ +int grow_buffer(struct serial_data *buf_data, int len) +{ + void *tmp; + + DEBUG_STRING("grow_buffer","Entry point"); + DEBUG_NUMBER("Current length: ",buf_data->length); + DEBUG_NUMBER("Increment length: ",len); + DEBUG_NUMBER("Expected length: ",buf_data->length+len); + DEBUG_NUMBER("Current size: ",buf_data->size); + + /* Grow buffer if needed */ + while(buf_data->length+len >= buf_data->size) { + errno = 0; + tmp = realloc(buf_data->buffer,buf_data->size+BLOCK_SIZE); + if(tmp == NULL) { + DEBUG_NUMBER("Error. Failed to allocate memory. Errno: ",errno); + return errno; + } + buf_data->buffer = (char *)(tmp); + buf_data->size += BLOCK_SIZE; + DEBUG_NUMBER("New size: ",buf_data->size); + + } + + DEBUG_NUMBER("Final size: ",buf_data->size); + DEBUG_STRING("grow_buffer","Success Exit."); + return EOK; +} + +/* Specail function to add different formatting symbols to the output */ +int put_marker(struct serial_data *buf_data, void *data, int len) +{ + int error = EOK; + + DEBUG_STRING("put_marker","Entry point"); + DEBUG_NUMBER("Marker length: ",len); + + error = grow_buffer(buf_data, len); + if(error) { + DEBUG_NUMBER("grow_buffer failed with: ",error); + return error; + } + memcpy(buf_data->buffer+buf_data->length,data,len); + buf_data->length+=len; + *(buf_data->buffer+buf_data->length) = '\0'; + + DEBUG_STRING("put_marker","Success exit"); + return error; +} + +/* Add item's data */ +int serialize(char *property_in, + int property_len_in, + int type, + void *data_in, + int length_in, + void *custom_data, + int *dummy) +{ + int len; + struct serial_data *buf_data; + char *property; + void *data; + int property_len; + int length; + int error = EOK; + int i; + + DEBUG_STRING("serialize","Entry point"); + + *dummy = 0; + + /* Check is there is buffer. If not allocate */ + buf_data = (struct serial_data *)(custom_data); + if(buf_data == (struct serial_data *)(NULL)) { + DEBUG_STRING("Error.","Storage data is not passed in!"); + return EINVAL; + } + if(buf_data->buffer == NULL) { + DEBUG_STRING("First time use.","Allocating buffer."); + errno = 0; + buf_data->buffer = malloc(BLOCK_SIZE); + if(buf_data->buffer == NULL) { + DEBUG_NUMBER("Error. Failed to allocate memory. Errno: ",errno); + return errno; + } + *(buf_data->buffer)='\0'; + buf_data->length=0; + buf_data->size = BLOCK_SIZE; + } + + DEBUG_NUMBER("Buffer len: ", buf_data->length); + DEBUG_NUMBER("Buffer size: ", buf_data->size); + DEBUG_STRING("Buffer: ", buf_data->buffer); + + /* Check the beginning of the collection */ + if(type == ELAPI_TYPE_COLLECTION) { + DEBUG_STRING("Serializing collection: ", property_in); + DEBUG_STRING("First header. ", ""); + if((error=put_marker(buf_data,"(",1))) return error; + property = TEXT_COLLECTION; + property_len = TEXT_COLLEN; + data = property_in; + length = property_len_in+1; + type=ELAPI_TYPE_STRING; + buf_data->nest_level++; + } + /* Check for subcollections */ + else if(type==ELAPI_TYPE_COLLECTIONREF) { + /* Skip */ + return EOK; + } + /* Check for the end of the collection */ + else if(type==ELAPI_TYPE_END) { + if((buf_data->length>0) && + (*(buf_data->buffer+buf_data->length-1) == ',')) { + buf_data->length--; + *(buf_data->buffer+buf_data->length) = '\0'; + } + if(buf_data->nest_level>0) { + buf_data->nest_level--; + if((error=put_marker(buf_data,")",1))) return error; + } + return EOK; + } + else { + property = property_in; + property_len = property_len_in; + data = data_in; + length = length_in; + } + + DEBUG_STRING("Property: ", property); + DEBUG_NUMBER("Property length: ", property_len); + + /* Start with property and "=" */ + if((error=put_marker(buf_data,property,property_len)) || + (error=put_marker(buf_data,"=",1))) return error; + + /* Get projected length of the item */ + len = get_data_len(type,length); + DEBUG_NUMBER("Expected data length: ",len); + DEBUG_STRING("Buffer so far: ", buf_data->buffer); + + /* Make sure we have enough space */ + if((error=grow_buffer(buf_data,len))) return error; + + /* Add the value */ + switch(type) { + case ELAPI_TYPE_STRING: + /* No escaping for now */ + len = copy_esc(buf_data->buffer+buf_data->length,(char *)(data),'"'); + break; + case ELAPI_TYPE_BINARY: + *(buf_data->buffer+buf_data->length) = '\''; + for(i=0;i<length;i++) sprintf(buf_data->buffer+buf_data->length+i*2 + 1,"%02X",*((unsigned char *)(data+i))); + len = length * 2 + 1; + *(buf_data->buffer+buf_data->length + len) = '\''; + len++; + break; + case ELAPI_TYPE_INTEGER: + len = sprintf(buf_data->buffer+buf_data->length,"%d",*((int *)(data))); + break; + case ELAPI_TYPE_UNSIGNED: + len = sprintf(buf_data->buffer+buf_data->length,"%u",*((unsigned int *)(data))); + break; + case ELAPI_TYPE_LONG: + len = sprintf(buf_data->buffer+buf_data->length,"%ld",*((long *)(data))); + break; + case ELAPI_TYPE_ULONG: + len = sprintf(buf_data->buffer+buf_data->length,"%lu",*((unsigned long *)(data))); + break; + case ELAPI_TYPE_DOUBLE: + len = sprintf(buf_data->buffer+buf_data->length,"%.4f",*((double *)(data))); + break; + default: + *(buf_data->buffer+buf_data->length) = '\0'; + len = 0; + break; + } + + /* Adjust length */ + buf_data->length+=len; + *(buf_data->buffer+buf_data->length) = '\0'; + + /* Always put a comma at the end */ + if((error=put_marker(buf_data,",",1))) return error; + + + DEBUG_STRING("Data: ",buf_data->buffer); + DEBUG_STRING("serialize","Exit point"); + return EOK; + +} + + +/* Add item's data */ +int xml_add(char *property, + int property_len, + int type, + void *data, + int length, + void *custom_data, + int *dummy) +{ + int rc; + struct xml_data *buf_data; + int error = EOK; + char *data_xml; + char *name; + + DEBUG_STRING("xml_add","Entry point"); + + *dummy = 0; + + /* Check is there is buffer. If not allocate */ + buf_data = (struct xml_data *)(custom_data); + if(buf_data == (struct xml_data *)(NULL)) { + DEBUG_STRING("Error.","Storage data is not passed in!"); + return EINVAL; + } + + /* Check if there is buffer allocated */ + if(buf_data->buf == (xmlBufferPtr)(NULL)) { + DEBUG_STRING("xml_add", "First use - allocating memory"); + buf_data->buf = xmlBufferCreate(); + if (buf_data->buf == NULL) { + DEBUG_STRING("xml_add", "Error creating the xml buffer"); + return ENOMEM; + } + DEBUG_NUMBER("Buffer allocated", buf_data->buf); + DEBUG_NUMBER("Buffer output", (buf_data->buf)->content); + + /* Create a new XmlWriter for memory, with no compression. + * Remark: there is no compression for this kind of xmlTextWriter */ + buf_data->writer = xmlNewTextWriterMemory(buf_data->buf, 0); + if (buf_data->writer == NULL) { + error = errno; + DEBUG_STRING("xml_add", "Error creating the xml writer"); + xmlBufferFree(buf_data->buf); + buf_data->buf = (xmlBufferPtr)(NULL); + return ENOMEM; + } + + /* Start the document with the xml default for the version, + * encoding and the default for the standalone declaration. */ + rc = xmlTextWriterStartDocument(buf_data->writer, NULL, NULL, NULL); + if (rc < 0) { + DEBUG_STRING("xml_add", "Error at xmlTextWriterStartDocument"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + buf_data->given_name = NULL; + buf_data->level = 0; + } + + DEBUG_STRING("current buffer:", (buf_data->buf)->content); + DEBUG_NUMBER("Writer", buf_data->writer); + + + /* Check the beginning of the collection */ + if(type == ELAPI_TYPE_COLLECTION) { + DEBUG_STRING("XML collection start: ", property); + rc = xmlTextWriterStartElement(buf_data->writer, BAD_CAST ELEMENT_COLLECTION); + if (rc < 0) { + DEBUG_STRING("xml_add", "Error at xmlTextWriterStartElement"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + + if(buf_data->given_name != NULL) name = buf_data->given_name; + else name = property; + rc = xmlTextWriterWriteAttribute(buf_data->writer, BAD_CAST ATTRIBUTE_NAME, BAD_CAST property); + if (rc < 0) { + DEBUG_STRING("xml_add", "Error at xmlTextWriterWriteAttribute"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + + /* Make sure we track the level */ + buf_data->level++; + } + /* Check for subcollections */ + else if(type==ELAPI_TYPE_COLLECTIONREF) { + buf_data->given_name = property; + } + /* Check for the end of the collection */ + else if(type==ELAPI_TYPE_END) { + buf_data->given_name = NULL; + buf_data->level--; + /* Check if this is the end of the whole collection */ + if(buf_data->level == 0) { + rc = xmlTextWriterEndDocument(buf_data->writer); + if (rc < 0) { + DEBUG_STRING("xml_add", "Error at xmlTextWriterEndDocument"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + } + else { + rc = xmlTextWriterFullEndElement(buf_data->writer); + if (rc < 0) { + DEBUG_STRING("xml_add", "Error at xmlTextWriterEndElement"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + } + } + else { + DEBUG_STRING("Property: ", property); + DEBUG_NUMBER("Property length: ", property_len); + + rc = xmlTextWriterStartElement(buf_data->writer, BAD_CAST ELEMENT_MEMBER); + if (rc < 0) { + DEBUG_STRING("xml_add", "Error at xmlTextWriterStartElement"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + + rc = xmlTextWriterWriteAttribute(buf_data->writer, BAD_CAST ATTRIBUTE_NAME, BAD_CAST property); + if (rc < 0) { + DEBUG_STRING("xml_add", "Error at xmlTextWriterWriteAttribute"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + + rc = xmlTextWriterWriteAttribute(buf_data->writer, BAD_CAST ATTRIBUTE_TYPE, BAD_CAST get_type(type)); + if (rc < 0) { + DEBUG_STRING("xml_add", "Error at xmlTextWriterWriteAttribute"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + + /* Add the value */ + + switch(type) { + case ELAPI_TYPE_STRING: + data_xml = (char *)(data); + if(!xmlCheckUTF8((const unsigned char *)(data_xml))) data_xml = BAD_DATA; + rc = xmlTextWriterWriteString(buf_data->writer, BAD_CAST data_xml); + break; + case ELAPI_TYPE_BINARY: + rc = xmlTextWriterWriteBase64(buf_data->writer, (const char *)(data),0,length); + break; + case ELAPI_TYPE_INTEGER: + rc = xmlTextWriterWriteFormatString(buf_data->writer, "%d", *((int *)(data))); + break; + case ELAPI_TYPE_UNSIGNED: + rc = xmlTextWriterWriteFormatString(buf_data->writer, "%u", *((unsigned int *)(data))); + break; + case ELAPI_TYPE_LONG: + rc = xmlTextWriterWriteFormatString(buf_data->writer, "%ld", *((long *)(data))); + break; + case ELAPI_TYPE_ULONG: + rc = xmlTextWriterWriteFormatString(buf_data->writer, "%lu", *((unsigned long *)(data))); + break; + case ELAPI_TYPE_DOUBLE: + rc = xmlTextWriterWriteFormatString(buf_data->writer, "%.4f", *((double *)(data))); + break; + default: + rc = xmlTextWriterWriteString(buf_data->writer, BAD_CAST ""); + break; + } + + if (rc < 0) { + DEBUG_STRING("xml_add", "Error trying put data into XML"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + + rc = xmlTextWriterFullEndElement(buf_data->writer); + if (rc < 0) { + DEBUG_STRING("xml_add", "Error at xmlTextWriterFullEndElement"); + xmlFreeTextWriter(buf_data->writer); + xmlBufferFree(buf_data->buf); + buf_data->writer = (xmlTextWriterPtr)(NULL); + buf_data->buf = (xmlBufferPtr)(NULL); + return EIO; + } + + } + + DEBUG_STRING("xml_add","Exit point"); + return EOK; + +} |