summaryrefslogtreecommitdiffstats
path: root/collection/elapi_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'collection/elapi_util.c')
-rw-r--r--collection/elapi_util.c499
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;
+
+}