/*====================================================================* * * 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