/*******************************************************************************
 * Copyright (C) 2004-2006 Intel Corp. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  - Neither the name of Intel Corp. nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

/**
 * @author Eugene Yarmosh
 * @author Vadim Revyakin
 */

#ifdef HAVE_CONFIG_H
#include <wsman_config.h>
#endif

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <ctype.h>
#include <assert.h>

#if defined (__SVR4) && defined (__sun)
#include <strings.h>
#endif

#include <u/libu.h>
#include <math.h>

#include "wsman-xml-api.h"
#include "wsman-soap.h"
#include "wsman-xml.h"

#include "wsman-dispatcher.h"
#include "wsman-xml-serializer.h"
#include "wsman-xml-serialize.h"
#include "wsman-soap-envelope.h"

struct __WsSerializerMemEntry {
	char buf[0];
};

typedef struct __WsSerializerMemEntry WsSerializerMemEntry;

struct __WsSerializerContext
{
	pthread_mutex_t lock;
	list_t *WsSerializerAllocList;
};

WsSerializerContextH ws_serializer_init(void)
{
	WsSerializerContextH serializercntx = NULL;
	serializercntx = u_malloc(sizeof(struct __WsSerializerContext));
	if(serializercntx == NULL) return NULL;
	serializercntx->WsSerializerAllocList = list_create(LISTCOUNT_T_MAX);
	if(serializercntx->WsSerializerAllocList == NULL) {
		u_free(serializercntx);
		return NULL;
	}
	u_init_lock(&serializercntx->lock);
	return serializercntx;
}

int ws_serializer_cleanup(WsSerializerContextH serctx)
{
	if(serctx && serctx->WsSerializerAllocList) {
		ws_serializer_free_all(serctx);
                u_destroy_lock(&serctx->lock);
		list_destroy(serctx->WsSerializerAllocList);
		u_free(serctx);
	}
	return 0;
}

void *xml_serializer_alloc(XmlSerializationData * data, int size,
			   int zeroInit)
{
	void *ptr = ws_serializer_alloc(data->serctx, size);
	TRACE_ENTER;
	if (ptr && zeroInit)
		memset(ptr, 0, size);
	TRACE_EXIT;
	return ptr;
}


int xml_serializer_free(XmlSerializationData * data, void *buf)
{
	return ws_serializer_free(data->serctx, buf);
}


WsXmlNodeH
xml_serializer_add_child(XmlSerializationData * data, char *value)
{
	const char *name = data->elementInfo->name;
	const char *ns = data->elementInfo->ns;
	WsXmlNodeH node;

	TRACE_ENTER;
	debug("name = %s; value(%p) = %s", name ? name : "NULL", value, value ? value : "NULL");
	node = ws_xml_add_child(data->xmlNode, ns, name, value);
	TRACE_EXIT;
	return node;
}



WsXmlNodeH xml_serializer_get_child(XmlSerializationData * data)
{
	WsXmlNodeH node;
	const char *name = data->elementInfo->name;
	const char *ns = data->elementInfo->ns;

	TRACE_ENTER;
	debug("name = %s:%s in %s [%d]", ns, name,
	      ws_xml_get_node_local_name(data->xmlNode), data->index);
	node = ws_xml_get_child(data->xmlNode, data->index, ns, name);
#if 0
	if (g_NameNameAliaseTable) {
		int index = 0;
		while (node == NULL &&
				g_NameNameAliaseTable[index].name != NULL) {
			if (!strcmp(g_NameNameAliaseTable[index].name, name))
			       	node = ws_xml_get_child(data->xmlNode,
						     data->index, ns,
						     g_NameNameAliaseTable
						     [index].aliase);
			index++;
		}
	}
#endif
	debug("returned %p; %s",
	      node, node ? ws_xml_get_node_local_name(node) : "");
	TRACE_EXIT;
	return node;
}

static int get_struct_align(void)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		struct {
			char x;
			void *y;
		} b;
	} dummy;
	return (char *) &(((dummy *) NULL)->b) - (char *) NULL;
}


static int
handle_attrs(struct __XmlSerializationData *data,
	     WsXmlNodeH node, size_t sz)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_NODE_ATTR *b;
	} dummy;

	int ret = 0;
	char *savedBufPtr = DATA_BUF(data);
	size_t al;
	size_t pad;
	int i;
	XML_NODE_ATTR **attrsp;
	XML_NODE_ATTR *attr;
	WsXmlAttrH xmlattr;
	char *src, *dstPtr;
	int dstSize;
	TRACE_ENTER;
	debug("node name = %s", ws_xml_get_node_local_name(node));
	if (!XML_IS_ATTRS(data->elementInfo)) {
		debug("No attrs");
		goto DONE;
	}


	DATA_BUF(data) = DATA_BUF(data) + sz;
	al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}
	debug("initial DATABUF = %p", DATA_BUF(data));
	DATA_BUF(data) = DATA_BUF(data) + pad;
	debug("aligned databuf = %p; pad = 0x%x", DATA_BUF(data), pad);

	if (data->mode == XML_SMODE_FREE_MEM) {
		// XXXXX   free memory
		goto DONE;
	}
	if (data->mode == XML_SMODE_SERIALIZE) {
		XML_NODE_ATTR *attrs =
		    *((XML_NODE_ATTR **) DATA_BUF(data));
		debug("attrs = %p", attrs);
		while (attrs) {
			debug("add attr. %s:%s = %s",
			      attrs->ns, attrs->name, attrs->value);
			if (ws_xml_add_node_attr(node,
						 attrs->ns, attrs->name,
						 attrs->value) == NULL) {
				error("could not add attr. %s:%s = %s",
				      attrs->ns, attrs->name,
				      attrs->value);
				ret = 1;
				goto DONE;
			}
			attrs = attrs->next;
		}
		goto DONE;
	}
	// XML_SMODE_DESERIALIZE
	attrsp = (XML_NODE_ATTR **) DATA_BUF(data);
	*attrsp = NULL;
	for (i = 0; i < ws_xml_get_node_attr_count(node); i++) {
		attr =
		    xml_serializer_alloc(data, sizeof(XML_NODE_ATTR), 1);
		if (attr == NULL) {
			error("no memory");
			ret = 1;
			goto DONE;
		}
		xmlattr = ws_xml_get_node_attr(node, i);
		if (xmlattr == NULL) {
			error("could not get attr %d", i);
			ret = 1;
			goto DONE;
		}
		src = ws_xml_get_attr_ns(xmlattr);
		if (!(src == NULL || *src == 0)) {
			dstSize = 1 + (int )strlen(src);
			dstPtr =
			    (char *) xml_serializer_alloc(data, dstSize,
							  1);
			if (dstPtr == NULL) {
				error("no memory");
				ret = 1;
				goto DONE;
			}
			strncpy(dstPtr, src, dstSize);
			attr->ns = dstPtr;
		}
		src = ws_xml_get_attr_name(xmlattr);
		if (!(src == NULL || *src == 0)) {
			dstSize = 1 + (int )strlen(src);
			dstPtr =
			    (char *) xml_serializer_alloc(data, dstSize,
							  1);
			if (dstPtr == NULL) {
				error("no memory");
				ret = 1;
				goto DONE;
			}
			strncpy(dstPtr, src, dstSize);
			attr->name = dstPtr;
		}
		src = ws_xml_get_attr_value(xmlattr);
		if (!(src == NULL || *src == 0)) {
			dstSize = 1 + (int )strlen(src);
			dstPtr =
			    (char *) xml_serializer_alloc(data, dstSize,
							  1);
			if (dstPtr == NULL) {
				error("no memory");
				ret = 1;
				goto DONE;
			}
			strncpy(dstPtr, src, dstSize);
			attr->value = dstPtr;
		}
		attr->next = *attrsp;
		*attrsp = attr;
	}
      DONE:
	DATA_BUF(data) = savedBufPtr;
	TRACE_EXIT;
	return ret;
}

static int do_serialize_int(XmlSerializationData * data, int valSize)
{
	WsXmlNodeH child = NULL;
	XML_TYPE_INT64 tmp;
	int retVal = DATA_ALL_SIZE(data);
	char *end;
	char *str;

	TRACE_ENTER;
	debug("handle %d INT%d %s;", DATA_COUNT(data),
	      8 * valSize, data->elementInfo->name);
	if (DATA_BUF(data) + retVal > data->stopper) {
		error("size of %d structures %s exceeds stopper (%p > %p)",
		      DATA_COUNT(data), DATA_ELNAME(data),
		      DATA_BUF(data) + retVal, data->stopper);
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}
	if (DATA_MUST_BE_SKIPPED(data) || data->mode == XML_SMODE_FREE_MEM) {
		DATA_BUF(data) = DATA_BUF(data) + retVal;
		goto DONE;
	}
	if ((data->mode != XML_SMODE_DESERIALIZE &&
	     data->mode != XML_SMODE_SERIALIZE)) {
		error("invalid mode %d", data->mode);
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}

	for (data->index = 0; data->index < DATA_COUNT(data);
	     data->index++) {
		debug("%s[%d] = %p", data->elementInfo->name, data->index,
		      data->elementBuf);

		if (data->mode == XML_SMODE_SERIALIZE) {
			debug("value size: %d", valSize);
			if (valSize == 1)
				tmp =
				    *((XML_TYPE_INT8 *) data->elementBuf);
			else if (valSize == 2)
				tmp = *((XML_TYPE_INT16 *) data->
				      elementBuf);
			else if (valSize == 4)
				tmp = *((XML_TYPE_INT32 *) data->
				      elementBuf);
			else if (valSize == 8)
				tmp = *((XML_TYPE_INT64 *) data->
				      elementBuf);
			else {
				error("unsupported uint size + %d",
						8 * valSize);
				retVal = WS_ERR_INVALID_PARAMETER;
				goto DONE;
			}

			if (((child = xml_serializer_add_child(data,
						       NULL)) == NULL)
			    || (ws_xml_set_node_long(child, tmp)) != 0) {
				debug("could not add child %s[%d]",
				      DATA_ELNAME(data), data->index);
				retVal = WS_ERR_INSUFFICIENT_RESOURCES;
				goto DONE;
			}
		}
		if (data->mode == XML_SMODE_DESERIALIZE) {
			if ((child = xml_serializer_get_child(data)) == NULL) {
				error ("not enough (%d < %d) instances of element %s",
				     data->index, DATA_COUNT(data),
				     DATA_ELNAME(data));
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			if ((str = ws_xml_get_node_text(child)) == NULL) {
				error("No text of node %s[%d]",
				      DATA_ELNAME(data), data->index);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			while (isspace(str[0]))
				str++;
			errno = 0;
			if (str[0] == 0) {
				if (ws_xml_find_attr_bool(child,
						     XML_NS_SCHEMA_INSTANCE,
						     XML_SCHEMA_NIL)) {
					goto ATTR;
				}
				error("absent value = %s", str);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			tmp = strtoll(str, &end, 10);
			if (errno) {
				error("strtoul(%s) failed; errno = %d",
				      str, errno);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			while (isspace(end[0]))
				end++;
			if (*end != 0) {
				error("wrong token = %s.", str);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			if (valSize == 1) {
				if (tmp > 127 || tmp < -128) {
					error("not int8 = %ld", tmp);
					retVal = WS_ERR_XML_PARSING;
					goto DONE;
				}
				*((XML_TYPE_INT8 *) data->elementBuf) =
				    (XML_TYPE_INT8) tmp;
			} else if (valSize == 2) {
				if (tmp > 32767 || tmp < -32768) {
					error("not int16 = %ld", tmp);
					retVal = WS_ERR_XML_PARSING;
					goto DONE;
				}
				*((XML_TYPE_INT16 *) data->elementBuf) =
				    (XML_TYPE_INT16) tmp;
			} else if (valSize == 4) {
				*((XML_TYPE_INT32 *) data->elementBuf) =
				    (XML_TYPE_INT32) tmp;
			} else if (valSize == 8) {
				*((XML_TYPE_INT64 *) data->elementBuf) =
				    (XML_TYPE_INT64) tmp;
			} else {
				error("unsupported int size + %d",
				      8 * valSize);
				retVal = WS_ERR_INVALID_PARAMETER;
				goto DONE;
			}
		}
ATTR:
		handle_attrs(data, child, valSize);
		DATA_BUF(data) = DATA_BUF(data) + DATA_SIZE(data);
	}
	if ((data->mode == XML_SMODE_DESERIALIZE) &&
	    xml_serializer_get_child(data)) {
		error("too many (%d > %d) instances of element %s",
		      data->index, DATA_COUNT(data), DATA_ELNAME(data));
		retVal = WS_ERR_XML_PARSING;
		goto DONE;
	}
DONE:
	TRACE_EXIT;
	return retVal;
}

static int do_serialize_uint(XmlSerializationData * data, int valSize)
{
	WsXmlNodeH child = NULL;
	XML_TYPE_UINT64 tmp;
	int retVal = DATA_ALL_SIZE(data);
	char *end;
	char *str;

	TRACE_ENTER;
	debug("handle %d UINT%d %s;", DATA_COUNT(data),
	      8 * valSize, data->elementInfo->name);
	if (DATA_BUF(data) + retVal > data->stopper) {
		error("size of %d structures %s exceeds stopper (%p > %p)",
		      DATA_COUNT(data), DATA_ELNAME(data),
		      DATA_BUF(data) + retVal, data->stopper);
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}
	if (DATA_MUST_BE_SKIPPED(data) || data->mode == XML_SMODE_FREE_MEM) {
		DATA_BUF(data) = DATA_BUF(data) + retVal;
		goto DONE;
	}
	if ((data->mode != XML_SMODE_DESERIALIZE &&
	     data->mode != XML_SMODE_SERIALIZE)) {
		error("invalid mode %d", data->mode);
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}

	for (data->index = 0; data->index < DATA_COUNT(data);
	     data->index++) {
		debug("%s[%d] = %p", data->elementInfo->name, data->index,
		      data->elementBuf);

		if (data->mode == XML_SMODE_SERIALIZE) {
			debug("value size: %d", valSize);
			if (valSize == 1)
				tmp =
				    *((XML_TYPE_UINT8 *) data->elementBuf);
			else if (valSize == 2)
				tmp = *((XML_TYPE_UINT16 *) data->
				      elementBuf);
			else if (valSize == 4)
				tmp = *((XML_TYPE_UINT32 *) data->
				      elementBuf);
			else if (valSize == 8)
				tmp = *((XML_TYPE_UINT64 *) data->
				      elementBuf);
			else {
				error("unsupported uint size + %d",
						8 * valSize);
				retVal = WS_ERR_INVALID_PARAMETER;
				goto DONE;
			}

			if (((child = xml_serializer_add_child(data,
						       NULL)) == NULL)
			    || (ws_xml_set_node_ulong(child, tmp)) != 0) {
				debug("could not add child %s[%d]",
				      DATA_ELNAME(data), data->index);
				retVal = WS_ERR_INSUFFICIENT_RESOURCES;
				goto DONE;
			}
		}
		if (data->mode == XML_SMODE_DESERIALIZE) {
			if ((child = xml_serializer_get_child(data)) == NULL) {
				error ("not enough (%d < %d) instances of element %s",
				     data->index, DATA_COUNT(data),
				     DATA_ELNAME(data));
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			if ((str = ws_xml_get_node_text(child)) == NULL) {
				error("No text of node %s[%d]",
				      DATA_ELNAME(data), data->index);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			while (isspace(str[0]))
				str++;
			errno = 0;
			if (str[0] == '-' || str[0] == 0) {
				if (ws_xml_find_attr_bool(child,
						     XML_NS_SCHEMA_INSTANCE,
						     XML_SCHEMA_NIL)) {
					goto ATTR;
				}
				error("absent value = %s", str);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			tmp = strtoull(str, &end, 10);
			if (errno) {
				error("strtoul(%s) failed; errno = %d",
				      str, errno);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			while (isspace(end[0]))
				end++;
			if (*end != 0) {
				error("wrong token = %s.", str);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			if (valSize == 1) {
				if (tmp > 255) {
					error("not uint8 = %ld", tmp);
					retVal = WS_ERR_XML_PARSING;
					goto DONE;
				}
				*((XML_TYPE_UINT8 *) data->elementBuf) =
				    (XML_TYPE_UINT8) tmp;
			} else if (valSize == 2) {
				if (tmp > 65535) {
					error("not uint16 = %ld", tmp);
					retVal = WS_ERR_XML_PARSING;
					goto DONE;
				}
				*((XML_TYPE_UINT16 *) data->elementBuf) =
				    (XML_TYPE_UINT16) tmp;
			} else if (valSize == 4) {
				*((XML_TYPE_UINT32 *) data->elementBuf) =
				    (XML_TYPE_UINT32) tmp;
			} else if (valSize == 8) {
				*((XML_TYPE_UINT64 *) data->elementBuf) =
				    (XML_TYPE_UINT64) tmp;
			} else {
				error("unsupported uint size + %d",
				      8 * valSize);
				retVal = WS_ERR_INVALID_PARAMETER;
				goto DONE;
			}
		}
ATTR:
		handle_attrs(data, child, valSize);
		DATA_BUF(data) = DATA_BUF(data) + DATA_SIZE(data);
	}
	if ((data->mode == XML_SMODE_DESERIALIZE) &&
	    xml_serializer_get_child(data)) {
		error("too many (%d > %d) instances of element %s",
		      data->index, DATA_COUNT(data), DATA_ELNAME(data));
		retVal = WS_ERR_XML_PARSING;
		goto DONE;
	}
DONE:
	TRACE_EXIT;
	return retVal;
}



int do_serialize_uint8(XmlSerializationData * data)
{
	if (XML_IS_ATTRS(data->elementInfo)) {
		size_t al = get_struct_align();
		size_t pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
		if (pad) {
			pad = al - pad;
		}
		DATA_BUF(data) = DATA_BUF(data) + pad;
	}

	return do_serialize_uint(data, sizeof(XML_TYPE_UINT8));
}


int do_serialize_uint16(XmlSerializationData * data)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_UINT16 b;
	} dummy;
	size_t al;
	size_t pad;
	int retVal;
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
	pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);

	if (pad) {
		pad = al - pad;
	}

	DATA_BUF(data) = DATA_BUF(data) + pad;
	retVal = do_serialize_uint(data, sizeof(XML_TYPE_UINT16));
	if (retVal >= 0) {
		retVal += pad;
	}
	return retVal;
}

int do_serialize_uint32(XmlSerializationData * data)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_UINT32 b;
	} dummy;
	size_t al;
	size_t pad;
	int retVal;
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
	pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}

	DATA_BUF(data) = DATA_BUF(data) + pad;
	retVal = do_serialize_uint(data, sizeof(XML_TYPE_UINT32));
	if (retVal >= 0) {
		retVal += pad;
	}
	return retVal;
}

int do_serialize_uint64(XmlSerializationData * data)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_UINT64 b;
	} dummy;
	size_t al;
	size_t pad;
	int retVal;
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
        pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}

	DATA_BUF(data) = DATA_BUF(data) + pad;
	retVal = do_serialize_uint(data, sizeof(XML_TYPE_UINT64));
	if (retVal >= 0) {
		retVal += pad;
	}
	return retVal;
}

int do_serialize_int8(struct __XmlSerializationData* data)
{
	if (XML_IS_ATTRS(data->elementInfo)) {
		size_t al = get_struct_align();
		size_t pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
		if (pad) {
			pad = al - pad;
		}
		DATA_BUF(data) = DATA_BUF(data) + pad;
	}

	return do_serialize_int(data, sizeof(XML_TYPE_INT8));
}
int do_serialize_int16(struct __XmlSerializationData* data)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_UINT16 b;
	} dummy;
	size_t al;
	size_t pad;
	int retVal;
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
	pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);

	if (pad) {
		pad = al - pad;
	}

	DATA_BUF(data) = DATA_BUF(data) + pad;
	retVal = do_serialize_int(data, sizeof(XML_TYPE_INT16));
	if (retVal >= 0) {
		retVal += pad;
	}
	return retVal;
}
int do_serialize_int32(struct __XmlSerializationData* data)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_UINT32 b;
	} dummy;
	size_t al;
	size_t pad;
	int retVal;
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
	pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}

	DATA_BUF(data) = DATA_BUF(data) + pad;
	retVal = do_serialize_int(data, sizeof(XML_TYPE_INT32));
	if (retVal >= 0) {
		retVal += pad;
	}
	return retVal;
}
int do_serialize_int64(struct __XmlSerializationData* data)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_UINT64 b;
	} dummy;
	size_t al;
	size_t pad;
	int retVal;
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
        pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}

	DATA_BUF(data) = DATA_BUF(data) + pad;
	retVal = do_serialize_int(data, sizeof(XML_TYPE_INT64));
	if (retVal >= 0) {
		retVal += pad;
	}
	return retVal;
}

static int do_serialize_real(XmlSerializationData * data, int valSize)
{
	WsXmlNodeH child = NULL;
	XML_TYPE_REAL64 tmp;
	int retVal = DATA_ALL_SIZE(data);
	char *end;
	char *str;

	TRACE_ENTER;
	debug("handle %d REAL%d %s;", DATA_COUNT(data),
	      8 * valSize, data->elementInfo->name);
	if (DATA_BUF(data) + retVal > data->stopper) {
		error("size of %d structures %s exceeds stopper (%p > %p)",
		      DATA_COUNT(data), DATA_ELNAME(data),
		      DATA_BUF(data) + retVal, data->stopper);
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}
	if (DATA_MUST_BE_SKIPPED(data) || data->mode == XML_SMODE_FREE_MEM) {
		DATA_BUF(data) = DATA_BUF(data) + retVal;
		goto DONE;
	}
	if ((data->mode != XML_SMODE_DESERIALIZE &&
	     data->mode != XML_SMODE_SERIALIZE)) {
		error("invalid mode %d", data->mode);
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}

	for (data->index = 0; data->index < DATA_COUNT(data);
	     data->index++) {
		debug("%s[%d] = %p", data->elementInfo->name, data->index,
		      data->elementBuf);

		if (data->mode == XML_SMODE_SERIALIZE) {
			debug("value size: %d", valSize);
			if (valSize == 4)
				tmp = *((XML_TYPE_REAL32 *) data->
				      elementBuf);
			else if (valSize == 8)
				tmp = *((XML_TYPE_REAL64 *) data->
				      elementBuf);
			else {
				error("unsupported real size + %d",
						8 * valSize);
				retVal = WS_ERR_INVALID_PARAMETER;
				goto DONE;
			}

			if (((child = xml_serializer_add_child(data,
						       NULL)) == NULL)
			    || (ws_xml_set_node_real(child, tmp)) != 0) {
				debug("could not add child %s[%d]",
				      DATA_ELNAME(data), data->index);
				retVal = WS_ERR_INSUFFICIENT_RESOURCES;
				goto DONE;
			}
		}
		if (data->mode == XML_SMODE_DESERIALIZE) {
			if ((child = xml_serializer_get_child(data)) == NULL) {
				error ("not enough (%d < %d) instances of element %s",
				     data->index, DATA_COUNT(data),
				     DATA_ELNAME(data));
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			if ((str = ws_xml_get_node_text(child)) == NULL) {
				error("No text of node %s[%d]",
				      DATA_ELNAME(data), data->index);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			while (isspace(str[0]))
				str++;
			errno = 0;
			if (str[0] == 0) {
				if (ws_xml_find_attr_bool(child,
						     XML_NS_SCHEMA_INSTANCE,
						     XML_SCHEMA_NIL)) {
					goto ATTR;
				}
				error("absent value = %s", str);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			tmp = strtod(str, &end);
			if (errno) {
				error("strtod(%s) failed; errno = %d",
				      str, errno);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			while (isspace(end[0]))
				end++;
			if (*end != 0) {
				error("wrong token = %s.", str);
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			if (valSize == 4) {
				*((XML_TYPE_REAL32 *) data->elementBuf) =
				    (XML_TYPE_REAL32) tmp;
			} else if (valSize == 8) {
				*((XML_TYPE_REAL64 *) data->elementBuf) =
				    (XML_TYPE_REAL64) tmp;
			} else {
				error("unsupported REAL size + %d",
				      8 * valSize);
				retVal = WS_ERR_INVALID_PARAMETER;
				goto DONE;
			}
		}
ATTR:
		handle_attrs(data, child, valSize);
		DATA_BUF(data) = DATA_BUF(data) + DATA_SIZE(data);
	}
	if ((data->mode == XML_SMODE_DESERIALIZE) &&
	    xml_serializer_get_child(data)) {
		error("too many (%d > %d) instances of element %s",
		      data->index, DATA_COUNT(data), DATA_ELNAME(data));
		retVal = WS_ERR_XML_PARSING;
		goto DONE;
	}
DONE:
	TRACE_EXIT;
	return retVal;
}

int do_serialize_real32(struct __XmlSerializationData* data)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_REAL32 b;
	} dummy;
	size_t al;
	size_t pad;
	int retVal;
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
	pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}

	DATA_BUF(data) = DATA_BUF(data) + pad;
	retVal = do_serialize_real(data, sizeof(XML_TYPE_REAL32));
	if (retVal >= 0) {
		retVal += pad;
	}
	return retVal;
}
int do_serialize_real64(struct __XmlSerializationData* data)
{
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_REAL64 b;
	} dummy;
	size_t al;
	size_t pad;
	int retVal;
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
        pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}
	DATA_BUF(data) = DATA_BUF(data) + pad;
	retVal = do_serialize_real(data, sizeof(XML_TYPE_REAL64));
	if (retVal >= 0) {
		retVal += pad;
	}
	return retVal;
}

int do_serialize_string(XmlSerializationData * data)
{
	WsXmlNodeH child = NULL;
	int retVal = DATA_ALL_SIZE(data);
	size_t al;
	size_t pad;
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_STR b;
	} dummy;

	TRACE_ENTER;
	debug("handle %d strings %s = %p", DATA_COUNT(data),
	      data->elementInfo->name, data->elementBuf);
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
	pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}
	retVal += pad;
	if (DATA_BUF(data) + retVal > data->stopper) {
		error("stopper: %p > %p",
		      DATA_BUF(data) + retVal, data->stopper);
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}
	if (DATA_MUST_BE_SKIPPED(data)) {
		data->elementBuf = DATA_BUF(data) + retVal;
		goto DONE;
	}
	DATA_BUF(data) = DATA_BUF(data) + pad;
	debug("adjusted elementBuf = %p", data->elementBuf);

	for (data->index = 0; data->index < DATA_COUNT(data);
	     data->index++) {
		if (data->mode == XML_SMODE_FREE_MEM) {
			xml_serializer_free(data, *(XML_TYPE_STR *) DATA_BUF(data));
			*(XML_TYPE_STR *) DATA_BUF(data) = NULL;
		} else if (data->mode == XML_SMODE_SERIALIZE) {
			char *valPtr = *((char **) DATA_BUF(data));
			child = xml_serializer_add_child(data, valPtr);
			if (child == NULL) {
				error("xml_serializer_add_child failed.");
				retVal = WS_ERR_INSUFFICIENT_RESOURCES;
				goto DONE;
			}
			if (ws_xml_get_node_text(child) == NULL) {
				ws_xml_add_node_attr(child,
						     XML_NS_SCHEMA_INSTANCE,
						     XML_SCHEMA_NIL,
						     "true");
			}
		} else if (data->mode == XML_SMODE_DESERIALIZE) {
			char *src;
			if ((child =
			     xml_serializer_get_child(data)) == NULL) {
				error
				    ("not enough (%d < %d) instances of element %s",
				     data->index, DATA_COUNT(data),
				     DATA_ELNAME(data));
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}

			src = ws_xml_get_node_text(child);
			if (src != NULL && *src != 0) {
				char *dstPtr;
				int dstSize = 1 + strlen(src);
				dstPtr =
				    (char *) xml_serializer_alloc(data,
								  dstSize,
								  1);
				if (dstPtr == NULL) {
					error("no memory");
					retVal =
					    WS_ERR_INSUFFICIENT_RESOURCES;
					goto DONE;
				}
				strncpy(dstPtr, src, dstSize);
				*((XML_TYPE_PTR *) DATA_BUF(data)) =
				    dstPtr;
			}
		} else {
			error("invalid mode");
			retVal = WS_ERR_INVALID_PARAMETER;
			goto DONE;
		}
		handle_attrs(data, child, sizeof(XML_TYPE_STR));
		DATA_BUF(data) = DATA_BUF(data) + DATA_SIZE(data);
	}
	if ((data->mode == XML_SMODE_DESERIALIZE) &&
	    xml_serializer_get_child(data)) {
		error("too many (%d > %d) instances of element %s",
		      data->index, DATA_COUNT(data), DATA_ELNAME(data));
		retVal = WS_ERR_XML_PARSING;
		goto DONE;
	}
      DONE:
	TRACE_EXIT;
	return retVal;
}



int do_serialize_bool(XmlSerializationData * data)
{
	int retVal = DATA_ALL_SIZE(data);
	typedef struct {
		XML_TYPE_UINT8 a;
		XML_TYPE_BOOL b;
	} dummy;
	size_t al;
	size_t pad;
	WsXmlNodeH child = NULL;

	TRACE_ENTER;
	debug("handle %d booleans %s; ptr = %p", DATA_COUNT(data),
	      DATA_ELNAME(data), DATA_BUF(data));
	if (XML_IS_ATTRS(data->elementInfo)) {
		al = get_struct_align();
	} else {
		al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	}
	pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}
	retVal += pad;
	if (DATA_BUF(data) + retVal > data->stopper) {
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}
	if (DATA_MUST_BE_SKIPPED(data) || data->mode == XML_SMODE_FREE_MEM) {
		data->elementBuf = DATA_BUF(data) + retVal;
		goto DONE;
	}
	DATA_BUF(data) = DATA_BUF(data) + pad;
	debug("adjusted elementBuf = %p", data->elementBuf);

	for (data->index = 0; data->index < DATA_COUNT(data);
	     data->index++) {
		debug("%s[%d] = %p", DATA_ELNAME(data), data->index,
		      DATA_BUF(data));
		if (data->mode == XML_SMODE_SERIALIZE) {
			XML_TYPE_BOOL tmp;
			tmp = *((XML_TYPE_BOOL *) DATA_BUF(data));
			if ((child = xml_serializer_add_child(data,
			      (tmp == 0) ? "false" : "true")) == NULL) {
				retVal = WS_ERR_INSUFFICIENT_RESOURCES;
				goto DONE;
			}
		} else if (data->mode == XML_SMODE_DESERIALIZE) {
			XML_TYPE_PTR dataPtr =
			    (XML_TYPE_PTR) DATA_BUF(data);
			XML_TYPE_BOOL tmp = -1;
			char *src;
			if ((child =
			     xml_serializer_get_child(data)) == NULL) {
				error("not enough (%d < %d) instances of element %s",
				     data->index, DATA_COUNT(data), DATA_ELNAME(data));
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			src = ws_xml_get_node_text(child);
			if (src == NULL || *src == 0) {
				tmp = 1;
			} else {
				if (isdigit(*src)) {
					tmp = atoi(src);
				} else {
					if (strcmp(src, "yes") == 0 ||
						strcmp(src, "true") == 0) {
						tmp = 1;
					} else if (strcmp(src, "no") == 0 ||
							strcmp(src, "false") == 0) {
						tmp = 0;
					}
				}
			}

			if (tmp == 0 || tmp == 1) {
				*((XML_TYPE_BOOL *) dataPtr) = tmp;
			} else {
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
		} else {
			retVal = WS_ERR_INVALID_PARAMETER;
			goto DONE;
		}
		handle_attrs(data, child, sizeof(XML_TYPE_BOOL));
		DATA_BUF(data) = DATA_BUF(data) + DATA_SIZE(data);
	}
	if ((data->mode == XML_SMODE_DESERIALIZE) &&
	    xml_serializer_get_child(data)) {
		error("too many (%d > %d) instances of element %s",
		      data->index, DATA_COUNT(data), DATA_ELNAME(data));
		retVal = WS_ERR_XML_PARSING;
		goto DONE;
	}
      DONE:
	TRACE_EXIT;
	return retVal;
}



static XmlSerialiseDynamicSizeData *make_dyn_size_data(XmlSerializationData
						       * data,
						       int * retValp)
{
	XmlSerialiseDynamicSizeData *dyn =
	    (XmlSerialiseDynamicSizeData *) data->elementBuf;
	int savedIndex = data->index;
	int size;

	TRACE_ENTER;
	data->index = 0;
	while (xml_serializer_get_child(data) != NULL) {
		data->index++;
	}
	dyn->count = data->index;
	data->index = savedIndex;
	if (dyn->count < DATA_MIN_COUNT(data)) {
		error("not enough (%d < %d) elements %s", dyn->count,
		      DATA_MIN_COUNT(data), DATA_ELNAME(data));
		*retValp = WS_ERR_XML_PARSING;
		dyn = NULL;
		goto DONE;
	}
	if ((DATA_MAX_COUNT(data) > 0)
	    && dyn->count > DATA_MAX_COUNT(data)) {
		error("too many (%d > %d) elements %s", dyn->count,
		      DATA_MAX_COUNT(data), DATA_ELNAME(data));
		*retValp = WS_ERR_XML_PARSING;
		dyn = NULL;
		goto DONE;
	}
	debug("count = %d of %d sizes", dyn->count, DATA_SIZE(data));
	if (dyn->count == 0) {
		goto DONE;
	}

	size = DATA_SIZE(data) * dyn->count;
	dyn->data = xml_serializer_alloc(data, size, 1);
	if (dyn->data == NULL) {
		error("no memory");
		*retValp = WS_ERR_INSUFFICIENT_RESOURCES;
		dyn = NULL;
	}

      DONE:
	TRACE_EXIT;
	return dyn;
}


int do_serialize_dyn_size_array(XmlSerializationData * data)
{
	typedef struct {
		char a;
		XmlSerialiseDynamicSizeData b;
	} dummy;
	size_t al = (char *) &(((dummy *) NULL)->b) - (char *) NULL;
	size_t pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	int retVal;
	char *savedBufPtr;
	XmlSerializerInfo *savedElementInfo;
	XmlSerialiseDynamicSizeData *dyn = NULL;
	int tmp;
	XmlSerializerInfo myinfo;
	int savedIndex;
	char *savedStopper;
	TRACE_ENTER;
	debug("Dyn size array %s; ptr = %p", data->elementInfo->name,
	      data->elementBuf);

	if (pad)
		pad = al - pad;

	retVal = DATA_SIZE(data) + pad;
	if (DATA_BUF(data) + retVal > data->stopper) {
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}
	if (DATA_MUST_BE_SKIPPED(data)) {
		DATA_BUF(data) = DATA_BUF(data) + retVal;
		goto DONE;
	}
	DATA_BUF(data) = DATA_BUF(data) + pad;
	debug("adjusted elementBuf = %p", data->elementBuf);

	savedBufPtr = DATA_BUF(data);
	savedElementInfo = data->elementInfo;

	if (data->mode != XML_SMODE_SERIALIZE &&
	    data->mode != XML_SMODE_DESERIALIZE &&
	    data->mode != XML_SMODE_FREE_MEM) {
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}

	if (data->mode == XML_SMODE_DESERIALIZE) {
		if ((dyn = make_dyn_size_data(data, &retVal)) == NULL) {
			goto DONE;
		}
	} else {
		dyn = (XmlSerialiseDynamicSizeData *) data->elementBuf;
		if (data->mode == XML_SMODE_SERIALIZE) {
			if (dyn->count < DATA_MIN_COUNT(data)) {
				error("not enough (%d < %d) elements %s",
				      dyn->count, DATA_MIN_COUNT(data),
				      DATA_ELNAME(data));
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			if ((DATA_MAX_COUNT(data) > 0)
			    && dyn->count > DATA_MAX_COUNT(data)) {
				error("too many (%d > %d) elements %s",
				      dyn->count, DATA_MAX_COUNT(data),
				      DATA_ELNAME(data));
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
		}
	}

	if (dyn->count == 0) {
		// no dynamic data, nothing to do
		goto DONE;
	}

	savedIndex = data->index;
	savedStopper = data->stopper;
	memcpy(&myinfo, savedElementInfo->extData,
	       sizeof(XmlSerializerInfo));
	myinfo.count = dyn->count;
	myinfo.name = data->elementInfo->name;
	myinfo.ns = data->elementInfo->ns;

	data->stopper = (char *) dyn->data + DATA_SIZE(data) * dyn->count;
	data->elementInfo = &myinfo;
	DATA_BUF(data) = dyn->data;
	data->index = 0;

	debug("dyn = %p, dyn->data = %p + 0x%x",
	      dyn, dyn->data, DATA_SIZE(data) * dyn->count);
	tmp = data->elementInfo->proc(data);

	data->index = savedIndex;
	DATA_BUF(data) = savedBufPtr;
	data->elementInfo = savedElementInfo;
	data->stopper = savedStopper;
	if (tmp < 0 && data->mode != XML_SMODE_FREE_MEM) {
		retVal = tmp;
		goto DONE;
	}
	if ((data->mode == XML_SMODE_FREE_MEM) && dyn->data) {
		xml_serializer_free(data, dyn->data);
		goto DONE;
	}
      DONE:
	DATA_BUF(data) = DATA_BUF(data) + DATA_SIZE(data);
	TRACE_EXIT;
	return retVal;
}




int do_serialize_struct(XmlSerializationData * data)
{
	int retVal = 0;
	int i;
	int elementCount = 0;
	XmlSerializerInfo *elements =
	    (XmlSerializerInfo *) data->elementInfo->extData;
	WsXmlNodeH savedXmlNode = data->xmlNode;
	XmlSerializerInfo *savedElement = data->elementInfo;
	int savedMode = data->mode;
	int savedIndex = data->index;
	void *savedStopper = data->stopper;
	size_t al = get_struct_align();
	size_t pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	size_t count;
	size_t struct_size;
	int savedLocalIndex;
	char *savedLocalElementBuf;
	WsXmlNodeH child;

	TRACE_ENTER;

	debug("handle %d structure \"%s\" ptr = %p", DATA_COUNT(data),
	      data->elementInfo->name ? data->elementInfo->name : "NULL",
	      data->elementBuf);
	if (data->mode != XML_SMODE_SERIALIZE &&
	    data->mode != XML_SMODE_DESERIALIZE &&
	    data->mode != XML_SMODE_FREE_MEM) {
		retVal = WS_ERR_INVALID_PARAMETER;
		debug("Incorrect data->mode = %d", data->mode);
		goto DONE;
	}
	al = get_struct_align();
	pad = (size_t) ((PTRTOINT) DATA_BUF(data) % al);
	if (pad) {
		pad = al - pad;
	}
	retVal = pad + XML_IS_HEAD(savedElement) ?
	    DATA_SIZE(data) : DATA_ALL_SIZE(data);
	if ((char *) DATA_BUF(data) + retVal > data->stopper) {
		error("size of %d structures \"%s\" exceeds stopper (%p > %p)",
		      DATA_COUNT(data), DATA_ELNAME(data) ? DATA_ELNAME(data) : "NULL",
		      (char *) DATA_BUF(data) + retVal, data->stopper);
		retVal = WS_ERR_INVALID_PARAMETER;
		goto DONE;
	}
	if (DATA_MUST_BE_SKIPPED(data)) {
		debug(" %d elements %s skipped", DATA_COUNT(data),
		      DATA_ELNAME(data) ? DATA_ELNAME(data) : "NULL");
		DATA_BUF(data) = DATA_BUF(data) + retVal;
		goto DONE;
	}
	DATA_BUF(data) = DATA_BUF(data) + pad;
	debug("adjusted ptr= %p", data->elementBuf);

	while (elements[elementCount].proc != NULL) {
		elementCount++;
	}

	count = DATA_COUNT(data);
	struct_size = DATA_SIZE(data);
	if (XML_IS_HEAD(savedElement)) {
		count = data->index + 1;
	} else {
		data->index = 0;
	}

	for (; data->index < count; data->index++) {
		int tmp;
		child = NULL;
		savedLocalIndex = data->index;
		savedLocalElementBuf = DATA_BUF(data);
		data->stopper = savedLocalElementBuf + DATA_SIZE(data);
		debug("%s[%d] = %p", DATA_ELNAME(data) ? DATA_ELNAME(data) : "NULL",
		      data->index,
		      DATA_BUF(data));
		if (data->mode == XML_SMODE_SERIALIZE) {
			child = xml_serializer_add_child(data, NULL);
			data->xmlNode = child;
			if (data->xmlNode == NULL) {
				error("can't add child");
				retVal = WS_ERR_INSUFFICIENT_RESOURCES;
				goto DONE;
			}
		} else if (data->mode == XML_SMODE_DESERIALIZE) {
			child = xml_serializer_get_child(data);
			if (child == NULL) {
				error
				    ("not enough (%d < %d) instances of element %s",
				     data->index, DATA_COUNT(data),
				     DATA_ELNAME(data) ? DATA_ELNAME(data) : "NULL");
				retVal = WS_ERR_XML_PARSING;
				goto DONE;
			}
			data->xmlNode = child;
		}

		debug("before for loop. Struct %s = %p",
		      savedElement->name ? savedElement->name : "NULL", DATA_BUF(data));

		for (i = 0; retVal > 0 && i < elementCount; i++) {
			data->elementInfo = &elements[i];
			debug
			    ("handle %d elements %s of struct %s. dstPtr = %p",
			     DATA_COUNT(data), DATA_ELNAME(data) ? DATA_ELNAME(data) : "NULL",
			     savedElement->name ? savedElement->name : "NULL", DATA_BUF(data));
			if (XML_IS_SKIP(data->elementInfo)) {
				data->mode = XML_SMODE_SKIP;
			}

			tmp = data->elementInfo->proc(data);
			debug("retval: %d", tmp);

			if (tmp < 0) {
				error("handling of element \"%s\" failed = %d",
				      DATA_ELNAME(data) ? DATA_ELNAME(data) : "NULL", tmp);
				retVal = tmp;
				goto DONE;
			}
		}
		data->elementInfo = savedElement;
		data->index = savedLocalIndex;
		data->mode = savedMode;
		data->xmlNode = savedXmlNode;
		data->elementInfo = savedElement;
		handle_attrs(data, child, 0);
		data->elementBuf = savedLocalElementBuf + struct_size;
	}
      DONE:
	data->stopper = savedStopper;
	data->elementInfo = savedElement;
	data->index = savedIndex;
	data->mode = savedMode;
	data->xmlNode = savedXmlNode;
	TRACE_EXIT;
	return retVal;
}



static void
initialize_xml_serialization_data(XmlSerializationData * data,
				  WsSerializerContextH serctx,
				  XmlSerializerInfo * elementInfo,
				  XML_TYPE_PTR dataBuf,
				  int mode,
				  XML_NODE_ATTR * attrs,
				  WsXmlNodeH xmlNode)
{
	debug("Initialize XML Serialization...");
	TRACE_ENTER;
	memset(data, 0, sizeof(XmlSerializationData));
	data->serctx = serctx;
	data->elementInfo = elementInfo;
	data->elementBuf = dataBuf;
	data->mode = mode;
	data->attrs = attrs;
	data->xmlNode = xmlNode;

	debug("Finished initializing XML Serialization...");
	TRACE_EXIT;
	return;
}



int ws_serialize(WsSerializerContextH serctx,
		    WsXmlNodeH xmlNode,
		    XML_TYPE_PTR dataPtr,
		    XmlSerializerInfo * info,
		    const char *name,
		    const char *ns, XML_NODE_ATTR * attrs, int output)
{
	int retVal = WS_ERR_INSUFFICIENT_RESOURCES;
	XmlSerializerInfo myinfo;
	XmlSerializationData data;

	TRACE_ENTER;
	if (info->proc == NULL) {
		error("info->proc == NULL");
		goto DONE;
	}
	memcpy(&myinfo, info, sizeof(XmlSerializerInfo));
	if (name == NULL) {
		error("name == NULL");
		goto DONE;
	}
	myinfo.name = name;
	myinfo.ns = ns;
	myinfo.flags |= SER_HEAD;
	initialize_xml_serialization_data(&data,
					  serctx,
					  &myinfo,
					  dataPtr,
					  XML_SMODE_SERIALIZE,
					  attrs, xmlNode);

	data.stopper = (char *) dataPtr + myinfo.size;
	if (output) {
		data.skipFlag = SER_IN;
	} else {
		data.skipFlag = SER_OUT;
	}
	retVal = myinfo.proc(&data);

      DONE:
	TRACE_EXIT;
	return retVal;
}


int ws_serializer_free_mem(WsSerializerContextH serctx, XML_TYPE_PTR buf,
			      XmlSerializerInfo * info)
{
	int retVal;
	XmlSerializationData data;
	XmlSerializerInfo myinfo;

	TRACE_ENTER;
	memcpy(&myinfo, info, sizeof(XmlSerializerInfo));
	myinfo.flags |= SER_HEAD;
	initialize_xml_serialization_data(&data,
					  serctx,
					  &myinfo,
					  buf,
					  XML_SMODE_FREE_MEM, NULL, NULL);

	data.stopper = (char *) buf + myinfo.size;
	if ((retVal = info->proc(&data)) >= 0) {
		xml_serializer_free(&data, buf);
	}
	TRACE_EXIT;
	return retVal;
}


void *ws_deserialize(WsSerializerContextH serctx,
		     WsXmlNodeH xmlParent,
		     XmlSerializerInfo * info,
		     const char *name,
		     const char *ns,
		     XML_NODE_ATTR ** attrs, int index, int output)
{
	int size;
	void *retPtr = NULL;
	XmlSerializationData data;
	XmlSerializerInfo myinfo;

	TRACE_ENTER;
	memcpy(&myinfo, info, sizeof(XmlSerializerInfo));
	if (name == NULL) {
		error("name == NULL");
	}
	myinfo.name = name;
	myinfo.ns = ns;
	myinfo.flags |= SER_HEAD;
	initialize_xml_serialization_data(&data, serctx, &myinfo, NULL,
					  XML_SMODE_DESERIALIZE,
					  NULL, xmlParent);

	data.index = index;

	if (output) {
		data.skipFlag = SER_IN;
	} else {
		data.skipFlag = SER_OUT;
	}

	size = myinfo.size;
	if ((data.elementBuf = xml_serializer_alloc(&data, size, 1)) != NULL) {
		retPtr = data.elementBuf;
		data.stopper = (char *) retPtr + size;
		if (myinfo.proc && myinfo.proc(&data) <= 0) {
			data.elementBuf = retPtr;
			retPtr = NULL;
			ws_serializer_free_mem(serctx, data.elementBuf,
					       &myinfo);
			error("Error during serialization");
		}
	}
	TRACE_EXIT;
	return retPtr;
}

static void enforce_mustunderstand(WsXmlNodeH node)
{
	WsXmlDocH doc = ws_xml_get_node_doc(node);
	char *ns = ws_xml_get_node_name_ns(ws_xml_get_doc_root(doc));
	ws_xml_add_node_attr(node, ns, SOAP_MUST_UNDERSTAND, "true");
}

int
ws_serialize_str(WsSerializerContextH serctx, WsXmlNodeH parent, const char *str,
		 const char *nameNs, const char *name, int mustunderstand)
{
	WsXmlNodeH node;
	TRACE_ENTER;
	//printf("mustunderstand flag for %s: %d\n", name, mustunderstand );
	node = ws_xml_add_child(parent, nameNs, name, str);
	if (node && mustunderstand) {
		enforce_mustunderstand(node);
	}
	TRACE_EXIT;
	return (node == NULL);
}


int ws_serialize_uint32(WsSerializerContextH serctx, WsXmlNodeH parent,
			unsigned long val, const char *nameNs,
			const char *name, int mustunderstand)
{
	WsXmlNodeH node = ws_xml_add_child(parent, nameNs, name, NULL);
	TRACE_ENTER;
	if (node) {
		ws_xml_set_node_ulong(node, val);
		if (mustunderstand) {
			enforce_mustunderstand(node);
		}
	}
	TRACE_EXIT;
	return (node == NULL);
}


char *ws_deserialize_str(WsSerializerContextH serctx, WsXmlNodeH parent, int index,
			 const char *nameNs, const char *name)
{
	char *str = NULL;
	WsXmlNodeH node = ws_xml_get_child(parent, index, nameNs, name);
	TRACE_ENTER;
	if (node) {
		str = ws_xml_get_node_text(node);
		if (serctx && str) {
			int len = (int )strlen(str) + 1;
			char *tmp = str;
			if ((str = ws_serializer_alloc(serctx,
						 len * sizeof(char))))
				strcpy(str, tmp);
		}
	}
	TRACE_EXIT;
	return str;
}

unsigned long ws_deserialize_uint32(WsSerializerContextH serctx,
				    WsXmlNodeH parent, int index,
				    const char *nameNs, const char *name)
{
	unsigned long val = 0;
	WsXmlNodeH node = ws_xml_get_child(parent, index, nameNs, name);
	TRACE_ENTER;
	if (node) {
		val = ws_xml_get_node_ulong(node);
	}
	TRACE_EXIT;
	return val;
}

/*
 * Returns duration in seconds in <value> argument
 *
 *  the format of OperationTimeout is defined by the
 *  XML Schema Datatypes Section 3.2.6.1 http://www.w3.org/TR/xmlschema-2/
 * 
 * Sample: P0Y0M0DT0H0M60.00S
 * 
 * (must start with 'P', 'T' separated date from time, seconds may have fraction)
 * 
 * FIXME: handle fractions of seconds (don't return a time_t but a struct timeval)
 * 
 */
int ws_deserialize_duration(const char *t, time_t * value)
{
	long years = 0;
	long months = 0;
	long days = 0;
	long hours = 0;
	long mins = 0;
	long secs = 0;
	time_t vs;
	int v;
	double f;               /* float for fractional second */
	char *e;                /* end pointer for strtol */
        int got = 64;           /* bitmask of parsing position, 64==year */
	int res = 1;            /* final result, 1 == error */
	int time_handeled = 0;  /* seen 'T' */
	int negative = 0;

	TRACE_ENTER;
	if (t == NULL) {
		debug("node text == NULL");
		goto DONE;
	}

	if (*t == '-') {
		negative = 1;
		t++;
	}
	if (*t != 'P') {
		debug("Wrong beginning of duration");
		goto DONE;
	}
	while (*++t) {
		if (*t == 'T') {
			time_handeled = 1;
			continue;
		}
		v = strtol(t, &e, 10);
		if (t == e) {
			debug("wrong format, missing numeric value");
			goto DONE;
		}
		if (time_handeled && (*e == '.')) {
			f = strtod(t, &e);
			if (*e != 'S') {
				debug("float but not secs");
				goto DONE;
			}
			if (((int)floor(f+0.5)) > v) {
				v++;  /* round value up */
			}
		}
		switch (*e) {
		case 'Y':
			if (got <= 32 || time_handeled) {
				debug("wrong order Y");
				goto DONE;
			}
			years = v;
			got = 32;
			break;
		case 'M':
			if (!time_handeled) {	// months
				if (got <= 16) {
					debug("wrong order M");
					goto DONE;
				}
				months = v;
				got = 16;
				break;
			}
			// minutes
			if (got <= 2 || !time_handeled) {
				debug("wrong order M");
				goto DONE;
			}
			mins = v;
			got = 2;
			break;
		case 'D':
			if (got <= 8 || time_handeled) {
				debug("wrong order D");
				goto DONE;
			}
			days = v;
			got = 8;
			break;
		case 'H':
			if (got <= 4 || !time_handeled) {
				debug("wrong order H");
				goto DONE;
			}
			hours = v;
			got = 4;
			break;
		case 'S':
			if (got <= 1 || !time_handeled) {
				debug("wrong order S");
				goto DONE;
			}
			secs = v;
			got = 1;
			break;
		default:
			debug("wrong format %c", *e);
			goto DONE;
		}
		t = e;
	}

	// invalid if T found and no HMS, or no time value detected
	if ((time_handeled && (got > 4)) || (64 == got)){
		debug("wrong format: floating T or no time value detected");
		goto DONE;
	}

	// We don't know exact date and time of the sender.
	// For simplicity consider 1 month = 30days;

	vs = secs + 60 * mins + 60 * 60 * hours + 60 * 60 * 24 * days +
	    60 * 60 * 24 * 30 * months + 60 * 60 * 24 * 30 * 12 * years;
	if (negative) {
		vs = 0 - vs;
	}
	*value = vs;
	res = 0; // good at this point

      DONE:
	TRACE_EXIT;
	return res;
}


int ws_deserialize_datetime(const char *text, XML_DATETIME * tmx)
{
	int res = 0;
	int r;
	int hours;
	int mins;
	struct tm tm;
	time_t t;

	TRACE_ENTER;
	if (text == NULL) {
		debug("node text == NULL");
		res = 1;
		goto DONE;
	}
	memset(tmx, 0, sizeof(XML_DATETIME));

	r = sscanf(text, "%d-%d-%dT%d:%d:%d%d:%d", &tmx->tm.tm_year,
		   &tmx->tm.tm_mon, &tmx->tm.tm_mday,
		   &tmx->tm.tm_hour, &tmx->tm.tm_min, &tmx->tm.tm_sec,
		   &hours, &mins);
	if (r != 8 ||
		/*
		 https://pubs.opengroup.org/onlinepubs/007908799/xsh/time.h.html
		 tm_year and tm_mon reduced below to be inside the bounds
		*/
		tmx->tm.tm_year < 1900 || tmx->tm.tm_year > 3000 ||
		tmx->tm.tm_mon < 1 || tmx->tm.tm_mon > 12 ||
		tmx->tm.tm_mday < 1 || tmx->tm.tm_mday > 31 ||
		tmx->tm.tm_hour < 0 || tmx->tm.tm_hour > 23 ||
		tmx->tm.tm_min < 0 || tmx->tm.tm_min > 59 ||
		tmx->tm.tm_sec < 0 || tmx->tm.tm_sec > 61 ||
		hours < -24 || hours > 24 ||
		mins < 0 || mins > 59
		) {
		debug("wrong body of datetime(%d): %s", r, text);
		res = 1;
		goto DONE;
	}
	tmx->tm.tm_year -= 1900;
	tmx->tm.tm_mon -= 1;

	t = time(NULL);
#ifdef _WIN32
	localtime_s(&tm, &t);
#else
	localtime_r(&t, &tm);
#endif
	tmx->tm.tm_isdst = tm.tm_isdst;

	if (hours < 0) {
		tmx->tz_min = 60 * hours - mins;
	} else {
		tmx->tz_min = 60 * hours + mins;
	}
      DONE:
	return res;
}



void *ws_serializer_alloc(WsSerializerContextH serctx, int size)
{
	WsSerializerMemEntry *ptr = NULL;
	TRACE_ENTER;
	if ((ptr = (WsSerializerMemEntry *) u_malloc(sizeof(WsSerializerMemEntry) + size)) != NULL) {
		lnode_t *node;
		u_lock(&serctx->lock);
		if ((node = lnode_create(ptr)) == NULL) {
			u_free(ptr);
			ptr = NULL;
		} else {
			list_append(serctx->WsSerializerAllocList, node);
		}
		u_unlock(&serctx->lock);
	}
	TRACE_EXIT;
	return ptr ? ptr->buf : NULL;
}


static int do_serializer_free(WsSerializerContextH serctx, void *ptr)
{
	lnode_t *node = NULL;
	lnode_t *node2 = NULL;
	TRACE_ENTER;
	if (serctx) {
		u_lock(&serctx->lock);
		node = list_first(serctx->WsSerializerAllocList);
		while (node != NULL) {
			WsSerializerMemEntry *entry =
			    (WsSerializerMemEntry *) node->list_data;

			if (entry && (!ptr || ptr == entry->buf)) {
				u_free(entry);
				node2 = node;
				node = list_delete2(serctx->WsSerializerAllocList, node);
				lnode_destroy (node2);
				if (ptr != NULL) {
					break;
				}
			}
			else
				node = list_next(serctx->WsSerializerAllocList, node);
		}
		u_unlock(&serctx->lock);
	}
	TRACE_EXIT;
	return (node != NULL);
}

int ws_serializer_free(WsSerializerContextH serctx, void *ptr)
{
	int retVal = 0;
	TRACE_ENTER;
	if (ptr != NULL)
		retVal = do_serializer_free(serctx, ptr);
	TRACE_EXIT;
	return retVal;
}

void ws_serializer_free_all(WsSerializerContextH serctx)
{
	TRACE_ENTER;
	do_serializer_free(serctx, NULL);
	TRACE_EXIT;
}

int ws_havenilvalue(XML_NODE_ATTR *attrs) 
{
	while(attrs) { 
		if(attrs->ns && attrs->name && attrs->value && 
			strcmp(attrs->ns, XML_NS_SCHEMA_INSTANCE) == 0 && 
			strcmp(attrs->name, XML_SCHEMA_NIL) == 0 && 
			strcasecmp(attrs->value, "true") == 0) 
			return 1; 
		attrs = attrs->next; 
	} 
	return 0; 
} 

