xml/libxml2libs/src/libxml2/libxml2_xmlstring.c
changeset 0 e35f40988205
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xml/libxml2libs/src/libxml2/libxml2_xmlstring.c	Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,1000 @@
+/*
+ * libxml2_xmlstring.c : an XML string utilities module
+ *
+ * This module provides various utility functions for manipulating
+ * the xmlChar* type. All functions named xmlStr* have been moved here
+ * from the parser.c file (their original home).
+ *
+ * See Copyright for the status of this software.
+ *
+ * UTF8 string routines from:
+ * William Brack <wbrack@mmm.com.hk>
+ *
+ * daniel@veillard.com
+ * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
+ */
+
+#define IN_LIBXML
+#include "xmlenglibxml.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdapis/libxml2/libxml2_globals.h>
+#include <stdapis/libxml2/libxml2_parserinternals.h>
+#include "libxml2_errencoding.h"
+#include <stdapis/libxml2/libxml2_xmlstring.h>
+
+/************************************************************************
+ *                                                                      *
+ *                Commodity functions to handle xmlChars                *
+ *                                                                      *
+ ************************************************************************/
+
+/**
+ * xmlStrndup:
+ * @param cur the input xmlChar*
+ * @param len the len of cur
+ *
+ * a strndup for array of xmlChar's
+ *
+ * Returns a new xmlChar* or NULL
+ *
+ * OOM: possible --> returns NULL for (cup!=NULL && len>=0) and sets OOM flag
+ */
+XMLPUBFUNEXPORT xmlChar *
+xmlStrndup(const xmlChar *cur, int len) {
+    xmlChar *ret;
+
+    if (!cur || (len < 0))
+        return(NULL);
+    ret = (xmlChar*) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
+    if (!ret) {
+        // NOTE: error reporting is removed; it will be done from xmlMalloc	
+        return ret; // ret is NULL here
+    }
+    memcpy(ret, cur, len * sizeof(xmlChar));
+    ret[len] = 0;
+    return(ret);
+}
+
+/**
+ * xmlStrdup:
+ * @param cur the input xmlChar *
+ *
+ * a strdup for array of xmlChar's. Since they are supposed to be
+ * encoded in UTF-8 or an encoding with 8bit based chars, we assume
+ * a termination mark of '0'.
+ *
+ * Returns a new xmlChar * or NULL
+ *
+ * OOM: possible --> returns NULL for cur!=NULL and sets OOM flag
+ */
+ 
+XMLPUBFUNEXPORT xmlChar*
+xmlStrdup(const xmlChar *cur) {
+    const xmlChar *p = cur;
+
+    if (!cur)
+        { // This should not normally happen -- check argument before calling!
+        // NOTE: Avoiding usage of NULL here improves generated assembly!
+        return(xmlChar*)cur /* NULL */;
+        }
+    while (*p != 0)
+        p++; /* non input consuming */
+    return(xmlStrndup(cur, p - cur));
+}
+
+/**
+ * xmlCharStrndup:
+ * @param cur the input char *
+ * @param len the len of cur
+ *
+ * a strndup for char's to xmlChar's
+ *
+ * Returns a new xmlChar * or NULL
+ */
+
+XMLPUBFUNEXPORT xmlChar *
+xmlCharStrndup(const char *cur, int len) {
+    int i;
+    xmlChar *ret;
+
+    if ((cur == NULL) || (len < 0)) return(NULL);
+    ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
+    if (ret == NULL) {
+        xmlErrMemory(NULL, NULL);
+        return(NULL);
+    }
+    for (i = 0;i < len;i++)
+        ret[i] = (xmlChar) cur[i];
+    ret[len] = 0;
+    return(ret);
+}
+
+/**
+ * xmlCharStrdup:
+ * @param cur the input char *
+ *
+ * a strdup for char's to xmlChar's
+ *
+ * Returns a new xmlChar * or NULL
+ */
+
+XMLPUBFUNEXPORT xmlChar *
+xmlCharStrdup(const char *cur) {
+    const char *p = cur;
+
+    if (cur == NULL) return(NULL);
+    while (*p != '\0') p++; /* non input consuming */
+    return(xmlCharStrndup(cur, p - cur));
+}
+
+/**
+ * xmlStrcmp:
+ * @param str1 the first xmlChar *
+ * @param str2 the second xmlChar *
+ *
+ * a strcmp for xmlChar's
+ *
+ * Returns the integer result of the comparison
+ */
+
+XMLPUBFUNEXPORT int
+xmlStrcmp(const xmlChar *str1, const xmlChar *str2) {
+    register int tmp;
+
+    if (str1 == str2) return(0);
+    if (str1 == NULL) return(-1);
+    if (str2 == NULL) return(1);
+    do {
+        tmp = *str1++ - *str2;
+        if (tmp != 0) return(tmp);
+    } while (*str2++ != 0);
+    return 0;
+}
+
+/**
+ * xmlStrEqual:
+ * @param str1 the first xmlChar *
+ * @param str2 the second xmlChar *
+ *
+ * Check if both string are equal of have same content
+ * Should be a bit more readable and faster than xmlStrEqual()
+ *
+ * Returns 1 if they are equal, 0 if they are different
+ *
+ * OOM: never
+ */
+// OPTIMIZE:
+//           - consider inlining OR
+//           - define as macro that tests first bytes prior calling it
+//           - for many caller functions safty checks are redundant (consider creating version w/o them)
+XMLPUBFUNEXPORT int
+xmlStrEqual(const xmlChar *str1, const xmlChar *str2) {
+    if (str1 == str2) return(1);
+    if (str1 == NULL) return(0);
+    if (str2 == NULL) return(0);
+    do {
+        if (*str1++ != *str2)
+            return(0);
+    } while (*str2++);
+    return(1);
+}
+
+/**
+ * xmlStrQEqual:
+ * @param pref the prefix of the QName
+ * @param name the localname of the QName
+ * @param str the second xmlChar *
+ *
+ * Check if a QName is Equal to a given string
+ *
+ * Returns 1 if they are equal, 0 if they are different
+ */
+
+XMLPUBFUNEXPORT int
+xmlStrQEqual(const xmlChar *pref, const xmlChar *name, const xmlChar *str) {
+    if (pref == NULL) return(xmlStrEqual(name, str));
+    if (name == NULL) return(0);
+    if (str == NULL) return(0);
+
+    do {
+        if (*pref++ != *str) return(0);
+    } while ((*str++) && (*pref));
+    if (*str++ != ':') return(0);
+    do {
+        if (*name++ != *str) return(0);
+    } while (*str++);
+    return(1);
+}
+
+/**
+ * xmlStrncmp:
+ * @param str1 the first xmlChar *
+ * @param str2 the second xmlChar *
+ * @param len the max comparison length
+ *
+ * a strncmp for xmlChar's
+ *
+ * Returns the integer result of the comparison
+ *
+ * OOM: never
+ */
+
+XMLPUBFUNEXPORT int
+xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len) {
+    register int tmp;
+
+    if (len <= 0) return(0);
+    if (str1 == str2) return(0);
+    if (str1 == NULL) return(-1);
+    if (str2 == NULL) return(1);
+#ifdef __GNUC__
+    tmp = strncmp(str1, str2, len);
+    return tmp;
+#else
+    do {
+        tmp = *str1++ - *str2;
+        if (tmp != 0 || --len == 0) return(tmp);
+    } while (*str2++ != 0);
+    return 0;
+#endif
+}
+
+static const xmlChar casemap[256] = {
+    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+    0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+    0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+    0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
+    0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+    0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
+    0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
+    0x78,0x79,0x7A,0x7B,0x5C,0x5D,0x5E,0x5F,
+    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
+    0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
+    0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+    0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
+    0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+    0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
+    0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+    0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
+    0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+    0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
+    0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+    0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
+    0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+    0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
+    0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+    0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
+    0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+};
+
+
+/**
+ * xmlStrcasecmp:
+ * @param str1 the first xmlChar *
+ * @param str2 the second xmlChar *
+ *
+ * a strcasecmp for xmlChar's
+ *
+ * Returns the integer result of the comparison
+ */
+
+XMLPUBFUNEXPORT int
+xmlStrcasecmp(const xmlChar *str1, const xmlChar *str2) {
+    register int tmp;
+
+    if (str1 == str2) return(0);
+    if (str1 == NULL) return(-1);
+    if (str2 == NULL) return(1);
+    do {
+        tmp = casemap[*str1++] - casemap[*str2];
+        if (tmp != 0) return(tmp);
+    } while (*str2++ != 0);
+    return 0;
+}
+
+/**
+ * xmlStrncasecmp:
+ * @param str1 the first xmlChar *
+ * @param str2 the second xmlChar *
+ * @param len the max comparison length
+ *
+ * a strncasecmp for xmlChar's
+ *
+ * Returns the integer result of the comparison
+ */
+
+XMLPUBFUNEXPORT int
+xmlStrncasecmp(const xmlChar *str1, const xmlChar *str2, int len) {
+    register int tmp;
+
+    if (len <= 0) return(0);
+    if (str1 == str2) return(0);
+    if (str1 == NULL) return(-1);
+    if (str2 == NULL) return(1);
+    do {
+        tmp = casemap[*str1++] - casemap[*str2];
+        if (tmp != 0 || --len == 0) return(tmp);
+    } while (*str2++ != 0);
+    return 0;
+}
+
+/**
+ * xmlStrchr:
+ * @param str the xmlChar * array
+ * @param val the xmlChar to search
+ *
+ * a strchr for xmlChar's
+ *
+ * Returns the xmlChar* for the first occurrence or NULL.
+ */
+
+XMLPUBFUNEXPORT const xmlChar *
+xmlStrchr(const xmlChar *str, xmlChar val) {
+    if (str == NULL) return(NULL);
+    while (*str != 0) { /* non input consuming */
+        if (*str == val) return((xmlChar *) str);
+        str++;
+    }
+    return(NULL);
+}
+
+/**
+ * xmlStrstr:
+ * @param str the xmlChar * array (haystack)
+ * @param val the xmlChar to search (needle)
+ *
+ * a strstr for xmlChar's
+ *
+ * Returns the xmlChar * for the first occurrence or NULL.
+ *
+ * OOM: never
+ */
+
+XMLPUBFUNEXPORT const xmlChar *
+xmlStrstr(const xmlChar *str, const xmlChar *val) {
+    int n;
+
+    if (str == NULL) return(NULL);
+    if (val == NULL) return(NULL);
+    n = xmlStrlen(val);
+
+    if (n == 0) return(str);
+    while (*str != 0) { /* non input consuming */
+        if (*str == *val) {
+            if (!xmlStrncmp(str, val, n)) return((const xmlChar *) str);
+        }
+        str++;
+    }
+    return(NULL);
+}
+
+/**
+ * xmlStrcasestr:
+ * @param str the xmlChar * array (haystack)
+ * @param val the xmlChar to search (needle)
+ *
+ * a case-ignoring strstr for xmlChar's
+ *
+ * Returns the xmlChar * for the first occurrence or NULL.
+ */
+
+XMLPUBFUNEXPORT const xmlChar *
+xmlStrcasestr(const xmlChar *str, xmlChar *val) {
+    int n;
+
+    if (str == NULL) return(NULL);
+    if (val == NULL) return(NULL);
+    n = xmlStrlen(val);
+
+    if (n == 0) return(str);
+    while (*str != 0) { /* non input consuming */
+        if (casemap[*str] == casemap[*val])
+            if (!xmlStrncasecmp(str, val, n)) return(str);
+        str++;
+    }
+    return(NULL);
+}
+
+/**
+ * xmlStrsub:
+ * @param str the xmlChar * array (haystack)
+ * @param start the index of the first char (zero based)
+ * @param len the length of the substring
+ *
+ * Extract a substring of a given string
+ *
+ * Returns the xmlChar * for the first occurrence or NULL.
+ */
+
+XMLPUBFUNEXPORT xmlChar *
+xmlStrsub(const xmlChar *str, int start, int len) {
+    int i;
+
+    if (str == NULL) return(NULL);
+    if (start < 0) return(NULL);
+    if (len < 0) return(NULL);
+
+    for (i = 0;i < start;i++) {
+        if (*str == 0) return(NULL);
+        str++;
+    }
+    if (*str == 0) return(NULL);
+    return(xmlStrndup(str, len));
+}
+
+/**
+ * xmlStrlen:
+ * @param str the xmlChar * array
+ *
+ * length of a xmlChar's string
+ *
+ * Returns the number of xmlChar contained in the ARRAY.
+ */
+
+XMLPUBFUNEXPORT int
+xmlStrlen(const xmlChar *str) {
+    int len = 0;
+
+    if (str == NULL) return(0);
+    while (*str != 0) { /* non input consuming */
+        str++;
+        len++;
+    }
+    return(len);
+}
+
+/**
+ * xmlStrncat:
+ * @param cur the original xmlChar* array
+ * @param add the xmlChar* array added
+ * @param len the length of add
+ *
+ * a strncat for array of xmlChar's, it will extend cur with the len
+ * first bytes of add.
+ *
+ * Returns a new xmlChar*, the original cur is reallocated if needed
+ * and should not be freed
+ *
+ * OOM: possible --> OOM flag is set  
+ */
+XMLPUBFUNEXPORT xmlChar*
+xmlStrncat(xmlChar* cur, const xmlChar* add, int len)
+{
+    int size;
+    xmlChar* ret;
+
+    if ((add == NULL) || (len == 0))
+        return(cur);
+    if (cur == NULL)
+        return(xmlStrndup(add, len));
+
+    size = xmlStrlen(cur);
+    // DONE: Fix xmlRealloc: Nothing to fix!
+    ret = (xmlChar*) xmlRealloc(cur, (size + len + 1) * sizeof(xmlChar));
+    if (!ret) {
+        xmlErrMemory(NULL, NULL);
+        return(cur);
+    }
+    memcpy(&ret[size], add, len * sizeof(xmlChar));
+    ret[size + len] = 0;
+    return(ret);
+}
+
+/**
+ * xmlStrncatNew:
+ * @param str1 first xmlChar string
+ * @param str2 second xmlChar string
+ * @param len the len of str2
+ *
+ * same as xmlStrncat, but creates a new string.  The original
+ * two strings are not freed.
+ *
+ * Returns a new xmlChar* or NULL
+ *
+ * OOM: possible --> returns NULL, sets OOM flag
+ */
+XMLPUBFUNEXPORT xmlChar *
+xmlStrncatNew(const xmlChar *str1, const xmlChar *str2, int len) {
+    int size;
+    xmlChar *ret;
+
+    if ((str2 == NULL) || (len == 0))
+        return(xmlStrdup(str1));
+    if (str1 == NULL)
+        return(xmlStrndup(str2, len));
+
+    size = xmlStrlen(str1);
+    ret = (xmlChar *) xmlMalloc((size + len + 1) * sizeof(xmlChar));
+    if (ret == NULL) {
+        xmlErrMemory(NULL, NULL); // sets OOM flag
+        //return(xmlStrndup(str1, size)); 
+        return NULL;
+    }
+    memcpy(ret, str1, size * sizeof(xmlChar));
+    memcpy(&ret[size], str2, len * sizeof(xmlChar));
+    ret[size + len] = 0;
+    return(ret);
+}
+
+/**
+ * xmlStrcat:
+ * @param cur the original xmlChar* array
+ * @param add the xmlChar* array added
+ *
+ * a strcat for array of xmlChar's. Since they are supposed to be
+ * encoded in UTF-8 or an encoding with 8bit based chars, we assume
+ * a termination mark of '0'.
+ *
+ * Returns a new xmlChar* containing the concatenated string.
+ *
+ * OOM: possible --> OOM flag is set 
+ */
+XMLPUBFUNEXPORT xmlChar*
+xmlStrcat(xmlChar* cur, const xmlChar *add) {
+    const xmlChar* p = add;
+
+    if (!add)
+        return(cur);
+    if (!cur)
+        return(xmlStrdup(add));
+
+    while (*p != 0)
+        p++; /* non input consuming */
+    return(xmlStrncat(cur, add, p - add));
+}
+
+/**
+ * xmlStrPrintf:
+ * @param buf the result buffer.
+ * @param len the result buffer length.
+ * @param msg the message with printf formatting.
+ * @param # extra parameters for the message.
+ *
+ * Formats msg and places result into buf.
+ *
+ * Returns the number of characters written to buf or -1 if an error occurs.
+ */
+XMLPUBFUNEXPORT int
+xmlStrPrintf(xmlChar *buf, int len, const xmlChar *msg, ...) {
+    va_list args;
+    int ret;
+
+    if((buf == NULL) || (msg == NULL)) {
+        return(-1);
+    }
+
+    va_start(args, msg);
+    ret = vsnprintf((char *) buf, len, (const char *) msg, args);
+    va_end(args);
+    buf[len - 1] = 0; /* be safe ! */
+
+    return(ret);
+}
+
+/**
+ * xmlStrVPrintf:
+ * @param buf the result buffer.
+ * @param len the result buffer length.
+ * @param msg the message with printf formatting.
+ * @param ap extra parameters for the message.
+ *
+ * Formats msg and places result into buf.
+ *
+ * Returns the number of characters written to buf or -1 if an error occurs.
+ */
+XMLPUBFUNEXPORT int
+xmlStrVPrintf(xmlChar *buf, int len, const xmlChar *msg, va_list ap) {
+    int ret;
+
+    if((buf == NULL) || (msg == NULL)) {
+        return(-1);
+    }
+
+    ret = vsnprintf((char *) buf, len, (const char *) msg, ap);
+    buf[len - 1] = 0; /* be safe ! */
+
+    return(ret);
+}
+
+/************************************************************************
+ *                                                                      *
+ *              Generic UTF8 handling routines                          *
+ *                                                                      *
+ * From rfc2044: encoding of the Unicode values on UTF-8:               *
+ *                                                                      *
+ * UCS-4 range (hex.)           UTF-8 octet sequence (binary)           *
+ * 0000 0000-0000 007F   0xxxxxxx                                       *
+ * 0000 0080-0000 07FF   110xxxxx 10xxxxxx                              *
+ * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx                     *
+ *                                                                      *
+ * I hope we won't use values > 0xFFFF anytime soon !                   *
+ *                                                                      *
+ ************************************************************************/
+
+
+/**
+ * xmlUTF8Size:
+ * @param utf pointer to the UTF8 character
+ *
+ * calculates the internal size of a UTF8 character
+ *
+ * returns the numbers of bytes in the character, -1 on format error
+ */
+XMLPUBFUNEXPORT int
+xmlUTF8Size(const xmlChar *utf) {
+    xmlChar mask;
+    int len;
+
+    if (utf == NULL)
+        return -1;
+    if (*utf < 0x80)
+        return 1;
+    /* check valid UTF8 character */
+    if (!(*utf & 0x40))
+        return -1;
+    /* determine number of bytes in char */
+    len = 2;
+    for (mask=0x20; mask != 0; mask>>=1) {
+        if (!(*utf & mask))
+            return len;
+        len++;
+    }
+    return -1;
+}
+
+/**
+ * xmlUTF8Charcmp:
+ * @param utf1 pointer to first UTF8 char
+ * @param utf2 pointer to second UTF8 char
+ *
+ * compares the two UCS4 values
+ *
+ * returns result of the compare as with xmlStrncmp
+ */
+XMLPUBFUNEXPORT int
+xmlUTF8Charcmp(const xmlChar *utf1, const xmlChar *utf2) {
+
+    if (utf1 == NULL ) {
+        if (utf2 == NULL)
+            return 0;
+        return -1;
+    }
+    return xmlStrncmp(utf1, utf2, xmlUTF8Size(utf1));
+}
+
+/**
+ * xmlUTF8Strlen:
+ * @param utf a sequence of UTF-8 encoded bytes
+ *
+ * compute the length of an UTF8 string, it doesn't do a full UTF8
+ * checking of the content of the string.
+ *
+ * Returns the number of characters in the string or -1 in case of error
+ *
+ * OOM: never
+ */
+XMLPUBFUNEXPORT int
+xmlUTF8Strlen(const xmlChar *utf) {
+    int ret = 0;
+
+    if (utf == NULL)
+        return(-1);
+
+    while (*utf != 0) {
+        if (utf[0] & 0x80) {
+            if ((utf[1] & 0xc0) != 0x80)
+                return(-1);
+            if ((utf[0] & 0xe0) == 0xe0) {
+                if ((utf[2] & 0xc0) != 0x80)
+                    return(-1);
+                if ((utf[0] & 0xf0) == 0xf0) {
+                    if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
+                        return(-1);
+                    utf += 4;
+                } else {
+                    utf += 3;
+                }
+            } else {
+                utf += 2;
+            }
+        } else {
+            utf++;
+        }
+        ret++;
+    }
+    return(ret);
+}
+
+/**
+ * xmlGetUTF8Char:
+ * @param utf a sequence of UTF-8 encoded bytes
+ * @param len a pointer to bytes len
+ *
+ * Read one UTF8 Char from utf
+ *
+ * Returns the char value or -1 in case of error, and updates *len with the
+ *        number of bytes consumed
+ */
+XMLPUBFUNEXPORT int
+xmlGetUTF8Char(const unsigned char *utf, int *len) {
+    unsigned int c;
+
+    if (utf == NULL)
+        goto error;
+    if (len == NULL)
+        goto error;
+    if (*len < 1)
+        goto error;
+
+    c = utf[0];
+    if (c & 0x80) {
+        if (*len < 2)
+            goto error;
+        if ((utf[1] & 0xc0) != 0x80)
+            goto error;
+        if ((c & 0xe0) == 0xe0) {
+            if (*len < 3)
+                goto error;
+            if ((utf[2] & 0xc0) != 0x80)
+                goto error;
+            if ((c & 0xf0) == 0xf0) {
+                if (*len < 4)
+                    goto error;
+                if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
+                    goto error;
+                *len = 4;
+                /* 4-byte code */
+                c = (utf[0] & 0x7) << 18;
+                c |= (utf[1] & 0x3f) << 12;
+                c |= (utf[2] & 0x3f) << 6;
+                c |= utf[3] & 0x3f;
+            } else {
+              /* 3-byte code */
+                *len = 3;
+                c = (utf[0] & 0xf) << 12;
+                c |= (utf[1] & 0x3f) << 6;
+                c |= utf[2] & 0x3f;
+            }
+        } else {
+          /* 2-byte code */
+            *len = 2;
+            c = (utf[0] & 0x1f) << 6;
+            c |= utf[1] & 0x3f;
+        }
+    } else {
+        /* 1-byte code */
+        *len = 1;
+    }
+    return(c);
+
+error:
+    *len = 0;
+    return(-1);
+}
+
+
+#ifndef XMLENGINE_EXCLUDE_UNUSED
+/**
+ * xmlCheckUTF8:
+ * @param utf Pointer to putative UTF-8 encoded string.
+ *
+ * Checks utf for being valid UTF-8. utf is assumed to be
+ * null-terminated. This function is not super-strict, as it will
+ * allow longer UTF-8 sequences than necessary. Note that Java is
+ * capable of producing these sequences if provoked. Also note, this
+ * routine checks for the 4-byte maximum size, but does not check for
+ * 0x10ffff maximum value.
+ *
+ * Return value: true if utf is valid.
+ **/
+int
+xmlCheckUTF8(const unsigned char *utf)
+{
+    int ix;
+    unsigned char c;
+
+    for (ix = 0; (c = utf[ix]);) {
+        if (c & 0x80) {
+            if ((utf[ix + 1] & 0xc0) != 0x80)
+                return(0);
+            if ((c & 0xe0) == 0xe0) {
+                if ((utf[ix + 2] & 0xc0) != 0x80)
+                    return(0);
+                if ((c & 0xf0) == 0xf0) {
+                    if ((c & 0xf8) != 0xf0 || (utf[ix + 3] & 0xc0) != 0x80)
+                        return(0);
+                    ix += 4;
+                    /* 4-byte code */
+                } else
+                    /* 3-byte code */
+                    ix += 3;
+            } else
+                /* 2-byte code */
+                ix += 2;
+        } else
+            /* 1-byte code */
+            ix++;
+      }
+      return(1);
+}
+
+#endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */
+
+
+/**
+ * xmlUTF8Strsize:
+ * @param utf a sequence of UTF-8 encoded bytes
+ * @param len the number of characters in the array
+ *
+ * storage size of an UTF8 string
+ *
+ * Returns the storage size of
+ * the first 'len' characters of ARRAY
+ *
+ */
+
+XMLPUBFUNEXPORT int
+xmlUTF8Strsize(const xmlChar *utf, int len) {
+    const xmlChar   *ptr=utf;
+    xmlChar         ch;
+
+    if (len <= 0)
+        return(0);
+
+    while ( len-- > 0) {
+        if ( !*ptr )
+            break;
+        if ( (ch = *ptr++) & 0x80)
+            while ( (ch<<=1) & 0x80 )
+                ptr++;
+    }
+    return (ptr - utf);
+}
+
+
+/**
+ * xmlUTF8Strndup:
+ * @param utf the input UTF8 *
+ * @param len the len of utf (in chars)
+ *
+ * a strndup for array of UTF8's
+ *
+ * Returns a new UTF8 * or NULL
+ */
+XMLPUBFUNEXPORT xmlChar *
+xmlUTF8Strndup(const xmlChar *utf, int len) {
+    xmlChar *ret;
+    int i;
+
+    if ((utf == NULL) || (len < 0)) return(NULL);
+    i = xmlUTF8Strsize(utf, len);
+    ret = (xmlChar *) xmlMallocAtomic((i + 1) * sizeof(xmlChar));
+    if (ret == NULL) {
+/*      
+        xmlGenericError(xmlGenericErrorContext,
+                EMBED_ERRTXT("malloc of %ld byte failed\n"),
+                (len + 1) * (long)sizeof(xmlChar));
+ */
+        return(NULL);
+    }
+    memcpy(ret, utf, i * sizeof(xmlChar));
+    ret[i] = 0;
+    return(ret);
+}
+
+/**
+ * xmlUTF8Strpos:
+ * @param utf the input UTF8 *
+ * @param pos the position of the desired UTF8 char (in chars)
+ *
+ * a function to provide the equivalent of fetching a
+ * character from a string array
+ *
+ * Returns a pointer to the UTF8 character or NULL
+ */
+XMLPUBFUNEXPORT xmlChar *
+xmlUTF8Strpos(const xmlChar *utf, int pos) {
+    xmlChar ch;
+
+    if (utf == NULL) return(NULL);
+    if ( (pos < 0) || (pos >= xmlUTF8Strlen(utf)) )
+        return(NULL);
+    while (pos--) {
+        if ((ch=*utf++) == 0) return(NULL);
+        if ( ch & 0x80 ) {
+            /* if not simple ascii, verify proper format */
+            if ( (ch & 0xc0) != 0xc0 )
+                return(NULL);
+            /* then skip over remaining bytes for this char */
+            while ( (ch <<= 1) & 0x80 )
+                if ( (*utf++ & 0xc0) != 0x80 )
+                    return(NULL);
+        }
+    }
+    return((xmlChar *)utf);
+}
+
+/**
+ * xmlUTF8Strloc:
+ * @param utf the input UTF8 *
+ * @param utfchar the UTF8 character to be found
+ *
+ * a function to provide the relative location of a UTF8 char
+ *
+ * Returns the relative character position of the desired char
+ * or -1 if not found
+ */
+XMLPUBFUNEXPORT int
+xmlUTF8Strloc(const xmlChar *utf, const xmlChar *utfchar) {
+    int i, size;
+    xmlChar ch;
+
+    if (utf==NULL || utfchar==NULL) return -1;
+    size = xmlUTF8Strsize(utfchar, 1);
+        for(i=0; (ch=*utf) != 0; i++) {
+            if (xmlStrncmp(utf, utfchar, size)==0)
+                return(i);
+            utf++;
+            if ( ch & 0x80 ) {
+                /* if not simple ascii, verify proper format */
+                if ( (ch & 0xc0) != 0xc0 )
+                    return(-1);
+                /* then skip over remaining bytes for this char */
+                while ( (ch <<= 1) & 0x80 )
+                    if ( (*utf++ & 0xc0) != 0x80 )
+                        return(-1);
+            }
+        }
+
+    return(-1);
+}
+/**
+ * xmlUTF8Strsub:
+ * @param utf a sequence of UTF-8 encoded bytes
+ * @param start relative pos of first char
+ * @param len total number to copy
+ *
+ * Create a substring from a given UTF-8 string
+ * Note:  positions are given in units of UTF-8 chars
+ *
+ * Returns a pointer to a newly created string
+ * or NULL if any problem
+ */
+
+XMLPUBFUNEXPORT xmlChar *
+xmlUTF8Strsub(const xmlChar *utf, int start, int len) {
+    int            i;
+    xmlChar ch;
+
+    if (utf == NULL) return(NULL);
+    if (start < 0) return(NULL);
+    if (len < 0) return(NULL);
+
+    /*
+     * Skip over any leading chars
+     */
+    for (i = 0;i < start;i++) {
+        if ((ch=*utf++) == 0) return(NULL);
+        if ( ch & 0x80 ) {
+            /* if not simple ascii, verify proper format */
+            if ( (ch & 0xc0) != 0xc0 )
+                return(NULL);
+            /* then skip over remaining bytes for this char */
+            while ( (ch <<= 1) & 0x80 )
+                if ( (*utf++ & 0xc0) != 0x80 )
+                    return(NULL);
+        }
+    }
+
+    return(xmlUTF8Strndup(utf, len));
+}
+