    /*====================================================================*
     *
     *   xmledit.c -
     *
     *   node.h
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    #ifndef XMLEDIT_SOURCE
    #define XMLEDIT_SOURCE

    /*====================================================================*
     *   system header files;
     *--------------------------------------------------------------------*/

    #include <stdint.h>
    #include <string.h>
    #include <limits.h>
    #include <ctype.h>
    #include <errno.h>

    /*====================================================================*
     *  custom header files;
     *--------------------------------------------------------------------*/

    #include "../tools/number.h"
    #include "../tools/memory.h"
    #include "../tools/error.h"
    #include "../nodes/node.h"

    /*====================================================================*
     *   constants;
     *--------------------------------------------------------------------*/

    #define XML_BAD_NUMBER 1
    #define XML_BAD_OFFSET 2
    #define XML_BAD_EXTENT 3

    /*====================================================================*
     *   variables;
     *--------------------------------------------------------------------*/

    static char const * member = "";
    static char const * string = "";
    static unsigned offset = 0;
    static unsigned length = 0;
    static bool series = false;

    /*====================================================================*
     *
     *   void position (size_t extent);
     *
     *   sanity check offset and extent before editing memory;
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    static void position (size_t extent)

    {
    	if (!length)
    	{
    		error (XML_BAD_EXTENT, EPERM, "%s has no length", member);
    	}
    	if (offset > extent)
    	{
    		error (XML_BAD_OFFSET, EPERM, "%s offset of 0x%04X exceeds " DATA_OBJECT " offset of 0x%04X", member, offset, (unsigned int) extent);
    	}
    	if ((offset + length) > extent)
    	{
    		error (XML_BAD_EXTENT, EPERM, "%s length of %u bytes exceeds " DATA_OBJECT " length of " SIZE_T_SPEC " bytes", member, length, extent);
    	}
    	return;
    }

    /*====================================================================*
     *
     *   signed xmlinteger (NODE const * node, unsigned radix);
     *
     *   convert numeric string to an unsigned integer; all string digits
     *   string digits must be valid for the specifid radix; radix can be
     *   1 through 16 but 2, 8, 10 and 16 are the only sensible choices;
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    static unsigned xmlinteger (NODE const * node, unsigned radix)

    {
    	unsigned digit;
    	unsigned value = 0;
    	while ((digit = todigit (*string)) < radix)
    	{
    		value *= radix;
    		value += digit;
    		string++;
    	}
    	if (*string)
    	{
    		error (XML_BAD_NUMBER, EPERM, "%s %s is not numeric", member, node->text);
    	}
    	return (value);
    }

    /*====================================================================*
     *
     *   void xmlstring (void * memory, size_t extent);
     *
     *   xmlstring is expressed as character text;  truncate string and
     *   pad memory with NULs as needed;
     *
     *   per the schema, an series cannot have a string member;
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    static void xmlstring (void * memory, size_t extent)

    {
    	char * buffer = (char *)(memory);
    	if (series)
    	{
    		error (XML_BAD_NUMBER, ENOTSUP, "%s found inside struct", member);
    	}
    	if (length)
    	{
    		while (length > 1)
    		{
    			if (isprint (*string))
    			{
    				buffer [offset] = *string++;
    			}
    			else
    			{
    				buffer [offset] = (char)(0);
    			}
    			offset++;
    			length--;
    		}
    		buffer [offset] = (char)(0);
    		offset++;
    		length--;
    	}
    	return;
    }

    /*====================================================================*
     *
     *   void xmlmemory (void * memory, size_t extent);
     *
     *   xmlmemory is a hexadecimal string of variable extent; an empty
     *   string increments offset and decrements length but nothing is
     *   written to the memory;
     *
     *   per the schema, if xmlmemory is not inside an series then it must
     *   match the object extent;
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    static void xmlmemory (void * memory, size_t extent)

    {
    	uint8_t * buffer = (uint8_t *)(memory);
    	if (!*string)
    	{
    		offset++;
    		length--;
    	}
    	while ((*string) && (length))
    	{
    		uint8_t msb = todigit (*string++);
    		uint8_t lsb = todigit (*string++);
    		if ((msb > 0x0F) || (lsb > 0x0F))
    		{
    			error (XML_BAD_NUMBER, EINVAL, "%s value is not hexadecimal", member);
    		}
    		buffer [offset] = (msb << 4) + lsb;
    		offset++;
    		length--;
    	}
    	if ((length) && (!series))
    	{
    		error (XML_BAD_NUMBER, EINVAL, "%s value is too short", member);
    	}
    	if (*string)
    	{
    		error (XML_BAD_NUMBER, EINVAL, "%s value is too long", member);
    	}
    	return;
    }

    /*====================================================================*
     *
     *   void xmlnumber (void * memory, size_t extent);
     *
     *   xmlnumber is a decimal integer string of variable length; the
     *   value cannot exceed length bytes and offset is incremented by
     *   length bytes;
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    static void xmlnumber (void * memory, size_t extent)

    {
    	uint64_t number = 0;
    	uint64_t maximum = 0;
    	maximum = ~maximum;
    	if (length < sizeof (number))
    	{
    		maximum <<= (length << 3);
    		maximum = ~maximum;
    	}
    	while (isdigit (*string))
    	{
    		number *= 10;
    		number += *string - '0';
    		if (number > maximum)
    		{
    			error (XML_BAD_NUMBER, EINVAL, "%s value exceeds %u bytes", member, length);
    		}
    		string++;
    	}
    	if (*string)
    	{
    		error (XML_BAD_NUMBER, EINVAL, "%s value is not decimal", member);
    	}
    	memcpy ((uint8_t *)(memory) + offset, &number, length);
    	offset += length;
    	length -= length;
    	return;
    }

    /*====================================================================*
     *
     *   void xmlbyte (void * memory, unsigned extent);
     *
     *   xmlbyte is a decimal integer string of variable extent; the
     *   value cannot exceed 255; an empty string increments offset and
     *   decrements length but nothing is written to the memory;
     *
     *   per the schema, if xmlbyte is not inside an series then it must
     *   it must match the object extent which must be 1 by implication;
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    static void xmlbyte (void * memory, size_t extent)

    {
    	if (*string)
    	{
    		uint16_t number = 0;
    		while (isdigit (*string))
    		{
    			number *= 10;
    			number += *string - '0';
    			if (number > 0xFF)
    			{
    				error (XML_BAD_NUMBER, EINVAL, "%s value exceeds 8 bits", member);
    			}
    			string++;
    		}
    		if (*string)
    		{
    			error (XML_BAD_NUMBER, EINVAL, "%s value is not decimal", member);
    		}
    		memcpy ((uint8_t *)(memory) + offset, &number, sizeof (uint8_t));
    	}
    	offset++;
    	length--;
    	if ((length) && (!series))
    	{
    		error (XML_BAD_NUMBER, EINVAL, "%s is too short", member);
    	}
    	return;
    }

    /*====================================================================*
     *
     *   static char const * xmlcontent1 (struct node const * node);
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    static char const * xmlcontent1 (struct node const * node)

    {
    	if (node)
    	{
    		node = node->below;
    	}
    	while (node)
    	{
    		if (node->type == NODE_DATA)
    		{
    			return (node->text);
    		}
    		node = node->after;
    	}
    	return ("");
    }

    /*====================================================================*
     *
     *   char const * xmlvalue1 (struct node const * node);
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    char const * xmlvalue1 (struct node const * node)

    {
    	if (node)
    	{
    		node = node->below;
    	}
    	while (node)
    	{
    		if (node->type == NODE_VALU)
    		{
    			return (node->text);
    		}
    		node = node->after;
    	}
    	return ("");
    }

    /*====================================================================*
     *
     *   static char const * xmlattribute1 (struct node const * node, char const * name);
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    static char const * xmlattribute1 (struct node const * node, char const * name)

    {
    	if (node)
    	{
    		node = node->below;
    	}
    	while (node)
    	{
    		if (node->type == NODE_ATTR)
    		{
    			if (!strcmp (node->text, name))
    			{
    				name = xmlvalue1 (node);
    				return (name);
    			}
    		}
    		node=node->after;
    	}
    	return ("");
    }

    /*====================================================================*
     *
     *   signed xmledit (struct node const * node, void * memory, size_t extent);
     *
     *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
     *   Copyright (c) 2001-2006 by Charles Maier Associates;
     *   Licensed under the Internet Software Consortium License;
     *
     *--------------------------------------------------------------------*/

    signed xmledit (struct node const * node, void * memory, size_t extent)

    {
    	if (node)
    	{
    		node = node->below;
    	}
    	while (node)
    	{
    		if (node->type == NODE_ELEM)
    		{
    			if (!strcmp (node->text, DATA_MEMBER))
    			{
    				member = xmlattribute1 (node, DATA_NAME);
    				offset = (unsigned)(-1);
    				length = (unsigned)(-1);
    				series = false;
    			}
    			else if (!strcmp (node->text, DATA_OFFSET))
    			{
    				string = xmlcontent1 (node);
    				offset = xmlinteger (node, 16);
    			}
    			else if (!strcmp (node->text, DATA_LENGTH))
    			{
    				string = xmlcontent1 (node);
    				length = xmlinteger (node, 10);
    			}
    			else if (!strcmp (node->text, DATA_STRUCT))
    			{
    				series = true;
    			}
    			else if (!strcmp (node->text, DATA_STRING))
    			{
    				string = xmlcontent1 (node);
    				position (extent);
    				xmlstring (memory, extent);
    			}
    			else if (!strcmp (node->text, DATA_MEMORY))
    			{
    				string = xmlcontent1 (node);
    				position (extent);
    				xmlmemory (memory, extent);
    			}
    			else if (!strcmp (node->text, DATA_HUGE))
    			{
    				length = sizeof (uint64_t);
    				position (extent);
    				string = xmlcontent1 (node);
    				xmlnumber (memory, extent);
    			}
    			else if (!strcmp (node->text, DATA_LONG))
    			{
    				length = sizeof (uint32_t);
    				position (extent);
    				string = xmlcontent1 (node);
    				xmlnumber (memory, extent);
    			}
    			else if (!strcmp (node->text, DATA_WORD))
    			{
    				length = sizeof (uint16_t);
    				position (extent);
    				string = xmlcontent1 (node);
    				xmlnumber (memory, extent);
    			}
    			else if (!strcmp (node->text, DATA_BYTE))
    			{
    				position (extent);
    				string = xmlcontent1 (node);
    				xmlbyte (memory, extent);
    			}
    			xmledit (node, memory, extent);
    		}
    		node = node->after;
    	}
    	return (0);
    }

    /*====================================================================*
     *
     *--------------------------------------------------------------------*/

    #endif

[PREV] [HOME] [NEXT]