]> git.mxchange.org Git - flightgear.git/blobdiff - utils/xmlgrep/xml.c
Allow setting of NED velocities.
[flightgear.git] / utils / xmlgrep / xml.c
index fc1c040ce31b4ee6930b8507019fa508068b11cf..5357ed81afd4d2706b9dffab66d81f3275dfac85 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (c) 2007,2008 by Adalin B.V.
- * Copyright (c) 2007,2008 by Erik Hofman
+/* Copyright (c) 2007-2009 by Adalin B.V.
+ * Copyright (c) 2007-2009 by Erik Hofman
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 #ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-typedef struct
-{
-   HANDLE m;
-   void *p;
-} SIMPLE_UNMMAP;
-
-static SIMPLE_UNMMAP un;
-
-/*
- * map 'filename' and return a pointer to it.
- */
-void *simple_mmap(int, unsigned int, SIMPLE_UNMMAP *);
-void simple_unmmap(SIMPLE_UNMMAP *);
-
-#define mmap(a,b,c,d,e,f)      simple_mmap((e), (b), &un)
-#define munmap(a,b)            simple_unmmap(&un)
+# include <io.h>
 
 #else  /* !WIN32 */
 # include <sys/mman.h>
-# include <fcntl.h>
+# include <unistd.h>
 #endif
 
+#ifndef NDEBUG
+# include <stdio.h>
+#endif
+#include <stdlib.h>     /* free, malloc */
+#include <malloc.h>
+#include <string.h>    /* memcmp */
+#ifndef _MSC_VER
+#include <strings.h>   /* strncasecmp */
+#else
+# define strncasecmp strnicmp
+#endif
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <unistd.h>
+#include <assert.h>
 #include <ctype.h>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "xml.h"
 
-struct _xml_id
-{
-    char *start;
-    size_t len;
-    int fd;
-};
+#ifndef XML_NONVALIDATING
+static const char *__xml_error_str[XML_MAX_ERROR];
+
+static void __xmlErrorSet(const void *, const char *, unsigned int);
+# define xmlErrorSet(a, b, c)  __xmlErrorSet(a, b, c)
+
+# ifndef NDEBUG
+# define PRINT_INFO(a) \
+       assert((a) < XML_MAX_ERROR); \
+       printf("at line %i: %s\n", __LINE__, __xml_error_str[(a)])
+# else
+# define PRINT_INFO(a)
+# endif
+
+# define SET_ERROR_AND_RETURN(a, b) \
+       { *rlen = 0; *name = (a); *len = (b); PRINT_INFO(b); return 0; }
 
-static char *__xmlCopyNode(char *, size_t, const char *);
-static char *__xmlGetNode(char *, size_t, const char *, size_t *);
-static char *__xmlFindNextElement(char *, size_t, const char *);
-static void *memncasemem(const void *, size_t, const void *, size_t);
+#else /* !XML_NONVALIDATING */
+# define xmlErrorSet(a, b, c)
+# define SET_ERROR_AND_RETURN(a, b)    return 0;
+#endif
+
+static char *__xmlNodeGetPath(void **, const char *, size_t *, char **, size_t *);
+static char *__xmlNodeGet(void *, const char *, size_t *, char **, size_t *, size_t *);
+static char *__xmlProcessCDATA(char **, size_t *);
+static char *__xmlCommentSkip(const char *, size_t);
+static char *__xmlInfoProcess(const char *, size_t);
+
+static void *__xml_memncasecmp(const char *, size_t *, char **, size_t *);
+static void __xmlPrepareData(char **, size_t *);
+
+#ifdef WIN32
+/*
+ * map 'filename' and return a pointer to it.
+ */
+static void *simple_mmap(int, size_t, SIMPLE_UNMMAP *);
+static void simple_unmmap(SIMPLE_UNMMAP *);
+
+# define mmap(a,b,c,d,e,f)       simple_mmap((e), (b), &rid->un)
+# define munmap(a,b)             simple_unmmap(&rid->un)
+#endif
+
+#ifndef NDEBUG
+# define PRINT(a, b, c) { \
+   size_t l1 = (b), l2 = (c); \
+   char *s = (a); \
+   if (s) { \
+      size_t q, len = l2; \
+      if (l1 < l2) len = l1; \
+      if (len < 50000) { \
+         printf("(%i) '", len); \
+         for (q=0; q<len; q++) printf("%c", s[q]); \
+         printf("'\n"); \
+      } else printf("Length (%u) seems too large at line %i\n",len, __LINE__); \
+   } else printf("NULL pointer at line %i\n", __LINE__); \
+}
+#endif
 
 void *
-xmlOpen(char *fn)
+xmlOpen(const char *filename)
 {
-    struct _xml_id *id = 0;
+    struct _root_id *rid = 0;
 
-    if (fn)
+    if (filename)
     {
-        int fd = open(fn, O_RDONLY);
-        if (fd > 0)
+        int fd = open(filename, O_RDONLY);
+        if (fd >= 0)
         {
-            id = malloc(sizeof(struct _xml_id));
-            if (id)
-            {
-                struct stat statbuf;
+            struct stat statbuf;
+            void *mm;
 
-                fstat(fd, &statbuf);
+            fstat(fd, &statbuf);
+            mm = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0L);
+            if (mm != (void *)-1)
+            {
+                rid = calloc(1, sizeof(struct _root_id));
+                if (rid)
+                {
+                    size_t blen = statbuf.st_size;
+#ifdef XML_USE_NODECACHE
+                    size_t num = 0, nlen = 1;
+                    char *n = "*";
 
-                id->fd = fd;
-                id->len = statbuf.st_size;
-                id->start = mmap(0, id->len, PROT_READ, MAP_PRIVATE, fd, 0L);
+                    rid->node = cacheInit();
+                    __xmlNodeGet(rid->node, mm, &blen, &n, &nlen, &num);
+#endif
+                    rid->fd = fd;
+                    rid->start = mm;
+                    rid->len = blen;
+                }
             }
         }
     }
 
-    return (void*)id;
+    return (void *)rid;
+}
+
+void *
+xmlInitBuffer(const char *buffer, size_t size)
+{
+    struct _root_id *rid = 0;
+
+    if (buffer && (size > 0))
+    {
+        rid = calloc(1, sizeof(struct _root_id));
+        if (rid)
+        {
+#ifdef XML_USE_NODECACHE
+            size_t num = 0, nlen = 1;
+            size_t blen = size;
+            char *n = "*";
+
+            rid->node = cacheInit();
+            __xmlNodeGet(rid->node, buffer, &blen, &n, &nlen, &num);
+#endif
+           rid->fd = -1;
+            rid->start = (char *)buffer;
+            rid->len = size;
+        }
+    }
+
+    return (void *)rid;
 }
 
 void
 xmlClose(void *id)
 {
-    if (id)
+     struct _root_id *rid = (struct _root_id *)id;
+
+     assert(rid != 0);
+     assert(rid->name == 0);
+
+     if (rid->fd != -1)
+     {
+         munmap(rid->start, rid->len);
+         close(rid->fd);
+     }
+
+#ifdef XML_USE_NODECACHE
+     if (rid->node) cacheFree(rid->node);
+#endif
+#ifndef XML_NONVALIDATING
+     if (rid->info) free(rid->info);
+#endif
+     free(rid);
+     id = 0;
+}
+
+void *
+xmlNodeGet(const void *id, const char *path)
+{
+    struct _xml_id *xid = (struct _xml_id *)id;
+    struct _xml_id *xsid = 0;
+    size_t len, slen;
+    char *ptr, *node;
+    void *nc, *nnc;
+
+    assert(id != 0);
+    assert(path != 0);
+
+    node = (char *)path;
+    len = xid->len;
+    slen = strlen(path);
+
+    nnc = nc = cacheNodeGet(xid);
+    ptr = __xmlNodeGetPath(&nnc, xid->start, &len, &node, &slen);
+    if (ptr)
     {
-        struct _xml_id *xid = (struct _xml_id *)id;
-        munmap(xid->start, xid->len);
-        close(xid->fd);
-        free(id);
-        id = 0;
+        xsid = malloc(sizeof(struct _xml_id));
+        if (xsid)
+        {
+             xsid->name = node;
+             xsid->name_len = slen;
+             xsid->start = ptr;
+             xsid->len = len;
+#ifdef XML_USE_NODECACHE
+             xsid->node = nnc;
+#endif
+#ifndef XML_NONVALIDATING
+             if (xid->name)
+                xsid->root = xid->root;
+             else
+                xsid->root = (struct _root_id *)xid;
+#endif
+        }
+        else
+        {
+            xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+        }
+    }
+    else if (slen == 0)
+    {
+        xmlErrorSet(xid, node, len);
     }
+
+    return (void *)xsid;
 }
 
 void *
-xmlCopyNode(void *id, char *path)
+xmlNodeCopy(const void *id, const char *path)
 {
+    struct _xml_id *xid = (struct _xml_id *)id;
     struct _xml_id *xsid = 0;
+    char *ptr, *node, *p;
+    size_t slen, len;
+    void *nc, *nnc;
 
-    if (id && path)
+    node = (char *)path;
+    len = xid->len;
+    slen = strlen(path);
+
+    nnc = nc = cacheNodeGet(xid);
+    ptr = __xmlNodeGetPath(&nnc, xid->start, &len, &node, &slen);
+    if (ptr)
     {
-        struct _xml_id *xid = (struct _xml_id *)id;
-        char *ptr, *p;
-        size_t rlen;
+        xsid = malloc(sizeof(struct _xml_id) + len);
+        if (xsid)
+        {
+            p = (char *)xsid + sizeof(struct _xml_id);
+
+            xsid->len = len;
+            xsid->start = p;
+            xsid->name_len = slen;
+            xsid->name = node;
+#ifdef XML_USE_NODECACHE
+                 xsid->node = nc;
+#endif
+#ifndef XML_NONVALIDATING
+            if (xid->name)
+                xsid->root = xid->root;
+            else
+                xsid->root = (struct _root_id *)xid;
+#endif
 
-        rlen = strlen(path);
-        ptr = __xmlGetNode(xid->start, xid->len, path, &rlen);
-        if (ptr)
+            memcpy(xsid->start, ptr, len);
+        }
+        else
         {
-            xsid = malloc(sizeof(struct _xml_id) + rlen);
-            if (xsid)
-            {
-                p = (char *)xsid + sizeof(struct _xml_id);
+            xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+        }
+    }
+    else if (slen == 0)
+    {
+        xmlErrorSet(xid, node, len);
+    }
+
+   return (void *)xsid;
+}
 
-                xsid->len = rlen;
-                xsid->start = p;
-                xsid->fd = 0;
+char *
+xmlNodeGetName(const void *id)
+{
+    struct _xml_id *xid = (struct _xml_id *)id;
+    size_t len;
+    char *ret;
 
-                memcpy(xsid->start, ptr, rlen);
-           }
-       }
-   }
+    assert(xid != 0);
 
-   return (void *)xsid;
+    len = xid->name_len;
+    ret = malloc(len+1);
+    if (ret)
+    {
+        memcpy(ret, xid->name, len);
+        *(ret + len) = 0;
+    }
+    else
+    {
+        xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+    }
+
+    return ret;
 }
 
-void *
-xmlGetNode(void *id, char *path)
+size_t
+xmlNodeCopyName(const void *id, char *buf, size_t buflen)
 {
-   struct _xml_id *xsid = 0;
+    struct _xml_id *xid = (struct _xml_id *)id;
+    size_t slen = 0;
+    assert(buf != 0);
+    assert(buflen > 0);
 
-   if (id && path)
-   {
-      struct _xml_id *xid = (struct _xml_id *)id;
-      size_t rlen;
-      char *ptr;
-
-      rlen = strlen(path);
-      ptr = __xmlGetNode(xid->start, xid->len, path, &rlen);
-      if (ptr)
-      {
-         xsid = malloc(sizeof(struct _xml_id));
-         xsid->len = rlen;
-         xsid->start = ptr;
-         xsid->fd = 0;
-      }
-   }
+    slen = xid->name_len;
+    if (slen >= buflen)
+    {
+        slen = buflen-1;
+        xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
+    }
+    memcpy(buf, xid->name, slen);
+    *(buf + slen) = 0;
 
-   return (void *)xsid;
+    return slen;
+}
+
+unsigned int
+xmlNodeGetNum(const void *id, const char *path)
+{
+    struct _xml_id *xid = (struct _xml_id *)id;
+    size_t num = 0;
+
+    assert(xid != 0);
+    assert(path != 0);
+
+    if (xid->len)
+    {
+        char *nodename, *pathname;
+        size_t len, slen;
+        void *nc;
+        char *p;
+
+        nodename = (char *)path;
+        if (*path == '/') nodename++;
+        slen = strlen(nodename);
+
+        nc = cacheNodeGet(xid);
+        pathname = strchr(nodename, '/');
+        if (pathname)
+        {
+           char *node;
+
+           len = xid->len;
+           pathname++;
+           slen -= pathname-nodename;
+           node = pathname;
+           p = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
+           if (p == 0 && slen == 0)
+           {
+               xmlErrorSet(xid, node, len);
+           }
+        }
+        else
+        {
+            p = xid->start;
+            len = xid->len;
+        }
+
+        if (p)
+        {
+            char *ret, *node = nodename;
+#ifndef XML_USE_NODECACHE
+            ret = __xmlNodeGet(nc, p, &len, &node, &slen, &num);
+#else
+            ret = __xmlNodeGetFromCache(&nc, p, &len, &node, &slen, &num);
+#endif
+            if (ret == 0 && slen == 0)
+            {
+                xmlErrorSet(xid, node, len);
+                num = 0;
+            }
+        }
+    }
+
+    return num;
 }
 
 void *
-xmlGetNextElement(const void *pid, void *id, char *path)
+xmlNodeGetPos(const void *pid, void *id, const char *element, size_t num)
 {
     struct _xml_id *xpid = (struct _xml_id *)pid;
-    struct _xml_id *xsid = 0;
-
-    if (id && path)
+    struct _xml_id *xid = (struct _xml_id *)id;
+    size_t len, slen;
+    char *ptr, *node;
+    void *ret = 0;
+    void *nc;
+
+    assert(xpid != 0);
+    assert(xid != 0);
+    assert(element != 0);
+
+    len = xpid->len;
+    slen = strlen(element);
+    node = (char *)element;
+    nc = cacheNodeGet(xpid);
+#ifndef XML_USE_NODECACHE
+    ptr = __xmlNodeGet(nc, xpid->start, &len, &node, &slen, &num);
+#else
+    ptr = __xmlNodeGetFromCache(&nc, xpid->start, &len, &node, &slen, &num);
+#endif
+    if (ptr)
     {
-        struct _xml_id *xid = (struct _xml_id *)id;
-        size_t rlen, nlen;
-        char *ptr;
+         xid->len = len;
+         xid->start = ptr;
+         xid->name = node;
+         xid->name_len = slen;
+#ifdef XML_USE_NODECACHE
+         /* unused for the cache but tested at the start of this function */
+         if (len == 0) xid->len = 1;
+         xid->node = nc;
+#endif
+         ret = xid;
+    }
+    else if (slen == 0)
+    {
+        xmlErrorSet(xpid, node, len);
+    }
+
+    return ret;
+}
 
-        if (xid->len < xpid->len) xid->start += xid->len;
-        nlen = xpid->len - (xid->start - xpid->start);
+char *
+xmlGetString(const void *id)
+{
+    struct _xml_id *xid = (struct _xml_id *)id;
+    char *str = 0;
 
-        rlen = strlen(path);
-        ptr = __xmlGetNode(xid->start, nlen, path, &rlen);
-        if (ptr)
+    assert(xid != 0);
+
+    if (xid->len)
+    {
+        size_t len;
+        char *ps;
+
+        ps = xid->start;
+        len = xid->len-1;
+        __xmlPrepareData(&ps, &len);
+        if (len)
         {
-             xid->len = rlen;
-             xid->start = ptr;
-             xsid = xid;
+            len++;
+            str = malloc(len+1);
+            if (str)
+            {
+                memcpy(str, ps, len);
+                *(str+len) = 0;
+            }
+            else
+            {
+                xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+            }
         }
     }
 
-    return (void *)xsid;
+    return str;
 }
 
-int
-xmlCompareString(const void *id, const char *s)
+size_t
+xmlCopyString(const void *id, char *buffer, size_t buflen)
 {
     struct _xml_id *xid = (struct _xml_id *)id;
-    int ret = -1;
+    size_t ret = 0;
+    assert(xid != 0);
+    assert(buffer != 0);
+    assert(buflen > 0);
 
-    if (xid && xid->len && s && (strlen(s) > 0))
+    *buffer = '\0';
+    if (xid->len)
     {
-        ret = strncasecmp(xid->start, s, xid->len);
+        size_t len;
+        char *ps;
+
+        ps = xid->start;
+        len = xid->len;
+        __xmlPrepareData(&ps, &len);
+        if (len)
+        {
+            if (len >= buflen)
+            {
+                len = buflen-1;
+                xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
+            }
+            memcpy(buffer, ps, len);
+            *(buffer+len) = 0;
+        }
+        ret = len;
     }
 
     return ret;
 }
 
 int
-xmlCompareNodeString(const void *id, const char *path, const char *s)
+xmlCompareString(const void *id, const char *s)
 {
     struct _xml_id *xid = (struct _xml_id *)id;
     int ret = -1;
 
-    if (xid && xid->len && path && s && (strlen(s) > 0))
+    assert(xid != 0);
+    assert(s != 0);
+
+    if (xid->len && (strlen(s) > 0))
     {
-        size_t rlen;
-        char *str;
+        size_t len;
+        char *ps;
 
-        rlen = strlen(path);
-        str = __xmlGetNode(xid->start, xid->len, path, &rlen);
-        if (str) ret = strncasecmp(str, s, rlen);
+        ps = xid->start;
+        len = xid->len;
+        __xmlPrepareData(&ps, &len);
+        ret = strncasecmp(ps, s, len);
     }
 
     return ret;
 }
 
 char *
-xmlGetNodeString(void *id, const char *path)
+xmlNodeGetString(const void *id, const char *path)
 {
     struct _xml_id *xid = (struct _xml_id *)id;
     char *str = 0;
 
-    if (xid && xid->len && path)
+    assert(xid != 0);
+    assert(path != 0);
+
+    if (xid->len)
     {
-        str = __xmlCopyNode(xid->start, xid->len, path);
-        if (str)
+        char *ptr, *node = (char *)path;
+        size_t slen = strlen(node);
+        size_t len = xid->len;
+        void *nc;
+
+        nc = cacheNodeGet(xid);
+        ptr = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
+        if (ptr && len)
         {
-            char *ps, *pe, *pem;
-            int slen;
-
-            slen = strlen(str);
-            ps = str;
-            pe = pem = ps+slen;
-
-            while ((ps<pe) && isspace(*ps)) ps++;
-            while ((pe>ps) && isspace(*pe)) pe--;
-
-            if (pe<pem) *++pe = 0;
-            slen = (pe-ps);
-            if ((ps>str) && slen) memmove(str, ps, slen+1);
-            else if (!slen) *str = 0;
+            __xmlPrepareData(&ptr, &len);
+            str = malloc(len+1);
+            if (str)
+            {
+               memcpy(str, ptr, len);
+               *(str+len) = '\0';
+            }
+            else
+            {
+                xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+            }
+        }
+        else
+        {
+            xmlErrorSet(xid, node, len);
         }
     }
 
     return str;
 }
 
-char *
-xmlGetString(void *id)
+size_t
+xmlNodeCopyString(const void *id, const char *path, char *buffer, size_t buflen)
 {
     struct _xml_id *xid = (struct _xml_id *)id;
-    char *str = 0;
+    size_t ret = 0;
 
-    if (xid && xid->len)
+    assert(xid != 0);
+    assert(path != 0);
+    assert(buffer != 0);
+    assert(buflen > 0);
+
+    *buffer = '\0';
+    if (xid->len)
     {
-        str = malloc(xid->len+1);
-        if (str)
+        char *p, *node = (char *)path;
+        size_t slen = strlen(node);
+        size_t len = xid->len;
+        void *nc;
+
+        nc = cacheNodeGet(xid);
+        p = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
+        if (p)
         {
-            char *ps, *pe, *pem;
-            int slen;
-
-            slen = xid->len;
-            memcpy(str, xid->start, slen);
-            *(str+slen) = 0;
-
-            ps = str;
-            pe = pem = ps+slen;
-
-            while ((ps<pe) && isspace(*ps)) ps++;
-            while ((pe>ps) && isspace(*pe)) pe--;
+            __xmlPrepareData(&p, &len);
+            if (len)
+            {
+                if (len >= buflen)
+                {
+                    len = buflen-1;
+                    xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
+                }
 
-            if (pe<pem) *++pe = 0;
-            slen = (pe-ps);
-            if ((ps>str) && slen) memmove(str, ps, slen+1);
-            else if (!slen) *str = 0;
+                memcpy(buffer, p, len);
+                *(buffer+len) = '\0';
+            }
+            ret = len;
+        }
+        else if (slen == 0)
+        {
+            xmlErrorSet(xid, node, len);
         }
     }
 
-    return str;
+    return ret;
 }
 
-unsigned int
-xmlCopyString(void *id, const char *path, char *buffer, unsigned int buflen)
+int
+xmlNodeCompareString(const void *id, const char *path, const char *s)
 {
     struct _xml_id *xid = (struct _xml_id *)id;
-    unsigned int rlen = 0;
+    int ret = -1;
 
-    if (xid && xid->len && path && buffer && buflen)
-    {
-        char *str;
+    assert(xid != 0);
+    assert(path != 0);
+    assert(s != 0);
 
-        *buffer = 0;
-        rlen = strlen(path);
-        str = __xmlGetNode(xid->start, xid->len, path, &rlen);
+    if (xid->len && (strlen(s) > 0))
+    {
+        char *node, *str, *ps, *pe;
+        size_t len, slen;
+        void *nc;
+
+        len = xid->len;
+        slen = strlen(path);
+        node = (char *)path;
+        nc = cacheNodeGet(xid);
+        str = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
         if (str)
         {
-            char *ps, *pe;
-
             ps = str;
-            pe = ps+rlen-1;
-
-            while ((ps<pe) && isspace(*ps)) ps++;
-            while ((pe>ps) && isspace(*pe)) pe--;
-
-            rlen = (pe-ps)+1;
-            if (rlen >= buflen) rlen = buflen-1;
-
-            memcpy(buffer, ps, rlen);
-            str = buffer + rlen;
-            *str = 0;
+            __xmlPrepareData(&ps, &len);
+            ret = strncasecmp(ps, s, len);
+        }
+        else if (slen == 0)
+        {
+            xmlErrorSet(xid, node, len);
         }
     }
 
-    return rlen;
+    return ret;
 }
 
 long int
-xmlGetNodeInt(void *id, const char *path)
+xmlGetInt(const void *id)
 {
     struct _xml_id *xid = (struct _xml_id *)id;
     long int li = 0;
 
-    if (path && xid && xid->len)
-    {
-        unsigned int rlen;
-        char *str;
+    assert(xid != 0);
 
-        rlen = strlen(path);
-        str = __xmlGetNode(xid->start, xid->len, path, &rlen);
-        if (str) li = strtol(str, (char **)NULL, 10);
+    if (xid->len)
+    {
+        char *end = xid->start + xid->len;
+        li = strtol(xid->start, &end, 10);
     }
 
     return li;
 }
 
 long int
-xmlGetInt(void *id)
+xmlNodeGetInt(const void *id, const char *path)
 {
     struct _xml_id *xid = (struct _xml_id *)id;
     long int li = 0;
 
-    if (xid && xid->len)
-        li = strtol(xid->start, (char **)NULL, 10);
+    assert(xid != 0);
+    assert(path != 0);
+
+    if (xid->len)
+    {
+        size_t len, slen;
+        char *str, *node;
+        void *nc;
+
+        len = xid->len;
+        slen = strlen(path);
+        node = (char *)path;
+        nc = cacheNodeGet(xid);
+        str = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
+        if (str)
+        {
+            char *end = str+len;
+            li = strtol(str, &end, 10);
+        }
+        else if (slen == 0)
+        {
+            xmlErrorSet(xid, node, len);
+        }
+    }
 
     return li;
 }
 
 double
-xmlGetNodeDouble(void *id, const char *path)
+xmlGetDouble(const void *id)
 {
-   struct _xml_id *xid = (struct _xml_id *)id;
-   double d = 0.0;
-
-    if (path && xid && xid->len)
-    {
-        unsigned int rlen;
-        char *str;
+    struct _xml_id *xid = (struct _xml_id *)id;
+    double d = 0.0;
 
-        rlen = strlen(path);
-        str = __xmlGetNode(xid->start, xid->len, path, &rlen);
+    assert(xid != 0);
 
-        if (str) d = strtod(str, (char **)NULL);
+    if (xid->len)
+    {
+        char *end = xid->start + xid->len;
+        d = strtod(xid->start, &end);
     }
 
     return d;
 }
 
 double
-xmlGetDouble(void *id)
+xmlNodeGetDouble(const void *id, const char *path)
 {
-   struct _xml_id *xid = (struct _xml_id *)id;
-   double d = 0.0;
+    struct _xml_id *xid = (struct _xml_id *)id;
+    double d = 0.0;
+
+    assert(xid != 0);
+    assert(path != 0);
 
-    if (xid && xid->len)
-        d = strtod(xid->start, (char **)NULL);
+    if (xid->len)
+    {
+        size_t len, slen;
+        char *str, *node;
+        void *nc;
+
+        len = xid->len;
+        slen = strlen(path);
+        node = (char *)path;
+        nc = cacheNodeGet(xid);
+        str = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
+        if (str)
+        {
+            char *end = str+len;
+            d = strtod(str, &end);
+        }
+        else if (slen == 0)
+        {
+            xmlErrorSet(xid, node, len);
+        }
+    }
 
     return d;
 }
 
-
-unsigned int
-xmlGetNumElements(void *id, const char *path)
+void *
+xmlMarkId(const void *id)
 {
-    struct _xml_id *xid = (struct _xml_id *)id;
-    unsigned ret = 0;
-
-    if (xid && xid->len && path)
-    {
-        unsigned int clen;
-        char *p, *pathname;
-        char *pname, *nname;
+    struct _xml_id *xmid = 0;
 
-        pathname = (char *)path;
-        if (*path == '/') pathname++;
+    assert(id != 0);
 
-        nname = strrchr(pathname, '/');
-        if (nname)
+    xmid = malloc(sizeof(struct _xml_id));
+    if (xmid)
+    {
+        struct _root_id *xrid = (struct _root_id *)id;
+        if (xrid->name == 0)
         {
-           clen = nname-pathname;
-           p = __xmlGetNode(xid->start, xid->len, pname, &clen);
+            xmid->name = "";
+            xmid->name_len = 0;
+            xmid->start = xrid->start;
+            xmid->len = xrid->len;
+#ifdef XML_USE_NODECACHE
+            xmid->node = xrid->node;
+#endif
+#ifndef XML_NONVALIDATING
+            xmid->root = xrid;
+#endif
         }
         else
         {
-            nname = (char *)pathname;
-            p = (char *)xid->start;
-            clen = xid->len;
+            memcpy(xmid, id, sizeof(struct _xml_id));
         }
-           
-        while ((p = __xmlFindNextElement(p, clen, nname)) != 0)
-            ret++;
+    }
+    else
+    {
+        xmlErrorSet(id, 0, XML_OUT_OF_MEMORY);
     }
 
-    return ret;
+    return (void *)xmid;
 }
 
-void *
-xmlMarkId(void *id)
+double
+xmlAttributeGetDouble(const void *id, const char *name)
 {
-   struct _xml_id *xmid = 0;
+    struct _xml_id *xid = (struct _xml_id *)id;
+    double ret = 0.0;
 
-   if (id)
-   {
-      xmid = malloc(sizeof(struct _xml_id));
-      if (xmid)
-      {
-          memcpy(xmid, id, sizeof(struct _xml_id));
-          xmid->fd = 0;
-      }
-   }
+    assert(xid != 0);
+    assert(name != 0);
 
-   return (void *)xmid;
-}
+    if (xid->name_len)
+    {
+        size_t slen = strlen(name);
+        char *ps, *pe;
 
-/* -------------------------------------------------------------------------- */
+        assert(xid->start > xid->name);
 
-char *
-__xmlCopyNode(char *start, size_t len, const char *path)
+        ps = xid->name + xid->name_len + 1;
+        pe = xid->start - 1;
+        while (ps<pe)
+        {
+            while ((ps<pe) && isspace(*ps)) ps++;
+            if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
+            {
+                ps += slen;
+                if ((ps<pe) && (*ps == '='))
+                {
+                    char *start;
+
+                    ps++;
+                    if (*ps == '"' || *ps == '\'') ps++;
+                    else
+                    {
+                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
+                        return 0;
+                    }
+
+                    start = ps;
+                    while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
+                    if (ps<pe)
+                    {
+                        ret = strtod(start, &ps);
+                    }
+                    else
+                    {
+                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
+                        return 0;
+                    }
+                }
+                else
+                {
+                    while ((ps<pe) && !isspace(*ps)) ps++;
+                    continue;
+                }
+
+                break;
+            }
+
+            while ((ps<pe) && !isspace(*ps)) ps++;
+        }
+    }
+
+    return ret;
+}
+
+long int
+xmlAttributeGetInt(const void *id, const char *name)
 {
-   char *p, *ret = 0;
-   size_t rlen;
+    struct _xml_id *xid = (struct _xml_id *)id;
+    long int ret = 0;
 
-   rlen = strlen(path);
-   p = __xmlGetNode(start, len, path, &rlen);
-   if (p && rlen)
-   {
-      ret = calloc(1, rlen+1);
-      memcpy(ret, p, rlen);
-   }
+    assert(xid != 0);
+    assert(name != 0);
+
+    if (xid->name_len)
+    {
+        size_t slen = strlen(name);
+        char *ps, *pe;
+
+        assert(xid->start > xid->name);
+
+        ps = xid->name + xid->name_len + 1;
+        pe = xid->start - 1;
+        while (ps<pe)
+        {
+            while ((ps<pe) && isspace(*ps)) ps++;
+            if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
+            {
+                ps += slen;
+                if ((ps<pe) && (*ps == '='))
+                {
+                    char *start;
+
+                    ps++;
+                    if (*ps == '"' || *ps == '\'') ps++;
+                    else
+                    {
+                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
+                        return 0;
+                    }
+
+                    start = ps;
+                    while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
+                    if (ps<pe)
+                    {
+                        ret = strtol(start, &ps, 10);
+                    }
+                    else
+                    {
+                       xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
+                       return 0;
+                   }
+               }
+               else
+               {
+                   while ((ps<pe) && isspace(*ps)) ps++;
+                   continue;
+               }
+
+               break;
+           }
+
+           while ((ps<pe) && !isspace(*ps)) ps++;
+        }
+    }
 
-   return ret;
+    return ret;
 }
 
 char *
-__xmlGetNode(char *start, size_t len, const char *path, size_t *rlen)
+xmlAttributeGetString(const void *id, const char *name)
 {
+    struct _xml_id *xid = (struct _xml_id *)id;
     char *ret = 0;
 
-    if (len)
+    assert(xid != 0);
+    assert(name != 0);
+
+    if (xid->name_len)
     {
-        char last_node = 0;
-        char *ptr, *name;
-        int plen;
+        size_t slen = strlen(name);
+        char *ps, *pe;
 
-        name = (char *)path;
-        if (*name == '/') name++;      /* skip the leading '/' character */
+        assert(xid->start > xid->name);
 
-        ptr = strchr(name, '/');
-        if (!ptr)
+        ps = xid->name + xid->name_len + 1;
+        pe = xid->start - 1;
+        while (ps<pe)
         {
-           last_node = 1;
-           ptr = name + *rlen;
+             while ((ps<pe) && isspace(*ps)) ps++;
+             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
+             {
+                 ps += slen;
+                 if ((ps<pe) && (*ps == '='))
+                 {
+                     char *start;
+
+                     ps++;
+                     if (*ps == '"' || *ps == '\'') ps++;
+                     else
+                     {
+                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
+                         return 0;
+                     }
+
+                     start = ps;
+                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
+                     if (ps<pe)
+                     {
+                         ret = malloc(ps-start);
+                         if (ret)
+                         {
+                             memcpy(ret, start, (ps-start));
+                             *(ret+(ps-start)) = '\0';
+                         }
+                         else
+                         {
+                             xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+                         }
+                     }
+                     else
+                     {
+                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
+                        return 0;
+                     }
+                 }
+                 else
+                 {
+                     while ((ps<pe) && !isspace(*ps)) ps++;
+                     continue;
+                 }
+
+
+                 break;
+             }
+
+             while ((ps<pe) && !isspace(*ps)) ps++;
         }
-        plen = ptr - name;
-         
-        if (plen)
-        {
-            char *p, *cur;
+    }
+
+    return ret;
+}
+
+size_t
+xmlAttributeCopyString(const void *id, const char *name,
+                                       char *buffer, size_t buflen)
+{
+    struct _xml_id *xid = (struct _xml_id *)id;
+    size_t ret = 0;
+
+    assert(xid != 0);
+    assert(name != 0);
+    assert(buffer != 0);
+    assert(buflen > 0);
 
-            cur = start;
-            do
+    if (xid->name_len)
+    {
+        size_t slen = strlen(name);
+        char *ps, *pe;
+
+        assert(xid->start > xid->name);
+
+        *buffer = '\0';
+        ps = xid->name + xid->name_len + 1;
+        pe = xid->start - 1;
+        while (ps<pe)
+        {
+            while ((ps<pe) && isspace(*ps)) ps++;
+            if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
             {
-                if ((p = memncasemem(cur, len, name, plen)) != 0)
+                ps += slen;
+                if ((ps<pe) && (*ps == '='))
+                {
+                    char *start;
+
+                    ps++;
+                    if (*ps == '"' || *ps == '\'') ps++;
+                    else
+                    {
+                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
+                        return 0;
+                    }
+
+                    start = ps;
+                    while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
+                    if (ps<pe)
+                    {
+                        size_t restlen = ps-start;
+                        if (restlen >= buflen)
+                        {
+                            restlen = buflen-1;
+                            xmlErrorSet(xid, ps, XML_TRUNCATE_RESULT);
+                        }
+
+                        memcpy(buffer, start, restlen);
+                        *(buffer+restlen) = 0;
+                        ret = restlen;
+                    }
+                    else
+                    {
+                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
+                        return 0;
+                    }
+                }
+                else
                 {
-                    len -= (p + plen) - cur;
-                    cur = p + plen;
+                    while ((ps<pe) && isspace(*ps)) ps++;
+                    continue;
                 }
+
+                break;
             }
-            while (p && (*(p-1) != '<'));
 
-            if (p)
-            {
-                p = cur;
-                while ((*cur++ != '>') && (cur<(p+len)));
-                len -= cur - p;
+            while ((ps<pe) && !isspace(*ps)) ps++;
+        }
+    }
 
-                if (last_node)
+    return ret;
+}
+
+int
+xmlAttributeCompareString(const void *id, const char *name, const char *s)
+{
+    struct _xml_id *xid = (struct _xml_id *)id;
+    int ret = -1;
+    assert(xid != 0);
+    assert(name != 0);
+    assert(s != 0);
+
+    if (xid->name_len && strlen(s))
+    {
+        size_t slen = strlen(name);
+        char *ps, *pe;
+
+        assert(xid->start > xid->name);
+
+        ps = xid->name + xid->name_len + 1;
+        pe = xid->start - 1;
+        while (ps<pe)
+        {
+            while ((ps<pe) && isspace(*ps)) ps++;
+            if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
+            {
+                ps += slen;
+                if ((ps<pe) && (*ps == '='))
                 {
-                    char *rptr = cur;
-                    do
+                    char *start;
+
+                    ps++;
+                    if (*ps == '"' || *ps == '\'') ps++;
+                    else
                     {
-                        if ((p = memncasemem(cur, len, name, plen)) != 0) 
-                        {
-                            len -= (p + plen) - cur;
-                            cur = p + plen;
-                            if (*(p-2) == '<' && *(p-1) == '/'
-                                && *(p+plen) == '>') break;
-                        }
+                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
+                        return 0;
                     }
-                    while (p);
 
-                    if (p)
+                    start = ps;
+                    while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
+                    if (ps<pe)
                     {
-                        *rlen = p-rptr-2;
-                        ret = rptr;
+                        ret = strncasecmp(start, s, ps-start);
+                    }
+                    else
+                    {
+                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
+                        return 0;
                     }
                 }
                 else
                 {
-                    ret = __xmlGetNode(cur, len, ptr+1, rlen);
+                    while ((ps<pe) && !isspace(*ps)) ps++;
+                    continue;
                 }
+
+                break;
+            }
+
+            while ((ps<pe) && !isspace(*ps)) ps++;
+        }
+    }
+
+    return ret;
+}
+
+
+#ifndef XML_NONVALIDATING
+int
+xmlErrorGetNo(const void *id, int clear)
+{
+    int ret = 0;
+
+    if (id)
+    {
+        struct _xml_id *xid = (struct _xml_id *)id;
+        struct _root_id *rid;
+
+        if (xid->name) rid = xid->root;
+        else rid = (struct _root_id *)xid;
+
+        assert(rid != 0);
+
+        if (rid->info)
+        {
+            struct _xml_error *err = rid->info;
+
+            ret = err->err_no;
+            if (clear) err->err_no = 0;
+        }
+    }
+
+    return ret;
+}
+
+size_t
+xmlErrorGetLineNo(const void *id, int clear)
+{
+    size_t ret = 0;
+
+    if (id)
+    {
+        struct _xml_id *xid = (struct _xml_id *)id;
+        struct _root_id *rid;
+
+        if (xid->name) rid = xid->root;
+        else rid = (struct _root_id *)xid;
+
+        assert(rid != 0);
+
+        if (rid->info)
+        {
+            struct _xml_error *err = rid->info;
+            char *ps = rid->start;
+            char *pe = err->pos;
+            char *new;
+
+            ret++;
+            while (ps<pe)
+            {
+               new = memchr(ps, '\n', pe-ps);
+               if (new) ret++;
+               else break;
+               ps = new+1;
+            }       
+
+            if (clear) err->err_no = 0;
+        }
+    }
+
+    return ret;
+}
+
+size_t
+xmlErrorGetColumnNo(const void *id, int clear)
+{
+    size_t ret = 0;
+
+    if (id)
+    {
+        struct _xml_id *xid = (struct _xml_id *)id;
+        struct _root_id *rid;
+
+        if (xid->name) rid = xid->root;
+        else rid = (struct _root_id *)xid;
+
+        assert(rid != 0);
+
+        if (rid->info)
+        {
+            struct _xml_error *err = rid->info;
+            char *ps = rid->start;
+            char *pe = err->pos;
+            char *new;
+
+            while (ps<pe)
+            {
+               new = memchr(ps, '\n', pe-ps);
+               new = memchr(ps, '\n', pe-ps);
+               if (new) ret++;
+               else break;
+               ps = new+1;
+            }
+            ret = pe-ps;
+
+            if (clear) err->err_no = 0;
+        }
+    }
+
+    return ret;
+}
+
+const char *
+xmlErrorGetString(const void *id, int clear)
+{
+    char *ret = 0;
+
+    if (id)
+    {
+        struct _xml_id *xid = (struct _xml_id *)id;
+        struct _root_id *rid;
+
+        if (xid->name) rid = xid->root;
+        else rid = (struct _root_id *)xid;
+
+        assert(rid != 0);
+
+        if (rid->info)
+        {
+            struct _xml_error *err = rid->info;
+            if (XML_NO_ERROR <= err->err_no && err->err_no < XML_MAX_ERROR)
+            {
+               ret = (char *)__xml_error_str[err->err_no];
             }
+            else
+            {
+               ret = "incorrect error number.";
+            }
+
+            if (clear) err->err_no = 0;
         }
     }
 
     return ret;
 }
 
+#else
+
+int
+xmlErrorGetNo(const void *id, int clear)
+{
+    return XML_NO_ERROR;
+}
+
+size_t
+xmlErrorGetLineNo(const void *id, int clear)
+{
+    return 0;
+}
+
+size_t
+xmlErrorGetColumnNo(const void *id, int clear)
+{
+    return 0;
+}
+
+const char *
+xmlErrorGetString(const void *id, int clear)
+{
+   return "error detection was not enabled at compile time: no error.";
+}
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+#ifndef XML_NONVALIDATING
+static const char *__xml_error_str[XML_MAX_ERROR] =
+{
+    "no error.",
+    "unable to allocate enough memory.",
+    "unable to open file for reading.",
+    "requested node name is invalid.",
+    "unexpected end of section.",
+    "buffer too small to hold all data, truncating.",
+    "incorrect comment section.",
+    "bad information block.",
+    "incompatible opening tag for element.",
+    "missing or invalid closing tag for element.",
+    "missing or invalid opening quote for attribute.",
+    "missing or invalid closing quote for attribute."
+};
+#endif
+
 char *
-__xmlFindNextElement(char *start, size_t len, const char *name)
+__xmlNodeGetPath(void **nc, const char *start, size_t *len, char **name, size_t *nlen)
 {
+    char *path;
     char *ret = 0;
 
-    if (start && len && name)
+    assert(start != 0);
+    assert(len != 0);
+    assert(name != 0);
+    assert(*name != 0);
+    assert(nlen != 0);
+
+    path = *name;
+    if (*path == '/') path++;
+    if (*path != '\0')
+    {
+        size_t num, blocklen, pathlen, nodelen;
+        char *node;
+
+        node = path;
+        pathlen = strlen(path);
+        path = strchr(node, '/');
+
+        if (!path) nodelen = pathlen;
+        else nodelen = path++ - node;
+
+        num = 0;
+        blocklen = *len;
+
+#ifndef XML_USE_NODECACHE
+        ret = __xmlNodeGet(nc, start, &blocklen, &node, &nodelen, &num);
+#else
+        ret = __xmlNodeGetFromCache(nc, start, &blocklen, &node, &nodelen, &num);
+#endif
+        if (ret)
+        {
+            if (path)
+            {
+                ret = __xmlNodeGetPath(nc, ret, &blocklen, &path, &pathlen);
+                *name = path;
+                *len = blocklen;
+                *nlen = pathlen;
+            }
+            else
+            {
+               *name = node;
+               *nlen = nodelen;
+               *len = blocklen;
+            }
+        }
+        else
+        {
+            *len = 0;
+            *nlen = 0;
+        }
+    }
+
+    return ret;
+}
+
+char *
+__xmlNodeGet(void *nc, const char *start, size_t *len, char **name, size_t *rlen, size_t *nodenum)
+{
+    char *cdata, *open_element = *name;
+    char *element, *start_tag=0;
+    char *new, *cur, *ne, *ret = 0;
+    size_t restlen, elementlen;
+    size_t open_len = *rlen;
+    size_t return_len = 0;
+    int found, num;
+    void *nnc = 0;
+
+    assert(start != 0);
+    assert(len != 0);
+    assert(name != 0);
+    assert(rlen != 0);
+    assert(nodenum != 0);
+
+    if (open_len == 0 || *name == 0)
+        SET_ERROR_AND_RETURN((char *)start, XML_INVALID_NODE_NAME);
+
+    cdata = (char *)start;
+    if (*rlen > *len)
+        SET_ERROR_AND_RETURN((char *)start, XML_UNEXPECTED_EOF);
+
+    found = 0;
+    num = *nodenum;
+    restlen = *len;
+    cur = (char *)start;
+    ne = cur + restlen;
+
+#ifdef XML_USE_NODECACHE
+    cacheInitLevel(nc);
+#endif
+
+    /* search for an opening tag */
+    while ((new = memchr(cur, '<', restlen)) != 0)
     {
-        unsigned int plen;
+        size_t len_remaining;
+        char *rptr;
+
+        if (*(new+1) == '/')           /* end of section */
+        {
+            *len -= restlen;
+             break;
+        }
+
+        new++;
+        restlen -= new-cur;
+        cur = new;
+
+        if (*cur == '!') /* comment */
+        {
+            char *start = cur;
+            size_t blocklen = restlen;
+            new = __xmlProcessCDATA(&start, &blocklen);
+            if (!new && start && open_len)                       /* CDATA */
+                SET_ERROR_AND_RETURN(cur, XML_INVALID_COMMENT);
+
+            restlen -= new-cur;
+            cur = new;
+            continue;
+        }
+        else if (*cur == '?') /* info block */
+        {
+            new = __xmlInfoProcess(cur, restlen);
+            if (!new)
+                SET_ERROR_AND_RETURN(cur, XML_INVALID_INFO_BLOCK);
+
+            restlen -= new-cur;
+            cur = new;
+            continue;
+        }
+
+        /*
+         * get element name and a pointer to after the opening tag
+         */
+        element = *name;
+        elementlen = *rlen;
+        len_remaining = restlen;
+        rptr = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
+        if (rptr)                      /* requested element was found */
+        {
+            new = rptr;
+            return_len = elementlen;
+            if (found == num)
+            {
+                ret = new;
+                open_len = elementlen;
+                start_tag = element;
+            }
+            else start_tag = 0;
+        }
+        else                           /* different element name was foud */
+        {
+            new = cur + (len_remaining - restlen);
+            if (new >= ne)
+                SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
+
+            element = *name;
+        }
 
-        plen = strlen(name);
-        if (plen)
+#ifdef XML_USE_NODECACHE
+        nnc = cacheNodeNew(nc);
+#endif
+
+        if (*(new-2) == '/')                           /* e.g. <test/> */
         {
-            char *p, *cur;
+            cur = new;
+            if (rptr)
+            {
+#ifdef XML_USE_NODECACHE
+                cacheDataSet(nnc, element, elementlen, rptr, 0);
+#endif
+                if (found == num)
+                {
+                    open_element = start_tag;
+                    *len = 0;
+                }
+                found++;
+            }
+            continue;
+        }
 
-            cur = start;
-            do
+        /*
+         * get the next xml tag
+         */
+        /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
+        cur = new;
+        new = memchr(cur, '<', restlen);
+        if (!new)
+            SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
+
+        new++;
+        restlen -= new-cur;
+        cur = new;
+        if (*cur == '!')                               /* comment, CDATA */
+        {
+            char *start = cur;
+            size_t blocklen = restlen;
+            new = __xmlProcessCDATA(&start, &blocklen);
+            if (new && start && open_len)                      /* CDATA */
             {
-                if ((p = memncasemem(cur, len, name, plen)) != 0)
+                cdata = ret;
+            }
+            else if (!new)
+                SET_ERROR_AND_RETURN(cur, XML_INVALID_COMMENT);
+
+            restlen -= new-cur;
+            cur = new;
+
+            /*
+             * look for the closing tag of the cascading block
+             */
+            new = memchr(cur, '<', restlen);
+            if (!new)
+                SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
+
+            new++;
+            restlen -= new-cur;
+            cur = new;
+        }
+
+        if (*cur == '/')               /* closing tag of leaf node found */
+        {
+            if (!strncasecmp(new+1, element, elementlen))
+            {
+#ifdef XML_USE_NODECACHE
+                cacheDataSet(nnc, element, elementlen, rptr, new-rptr-1);
+#endif
+                if (*(new+elementlen+1) != '>')
+                    SET_ERROR_AND_RETURN(new+1, XML_ELEMENT_NO_CLOSING_TAG);
+
+                if (found == num)
                 {
-                    len -= (p + plen) - cur;
-                    cur = p + plen;
+                    if (start_tag)
+                    {
+                        *len = new-ret-1;
+                        open_element = start_tag;
+                        cdata = (char *)start;
+                        start_tag = 0;
+                    }
+                    else /* report error */
+                        SET_ERROR_AND_RETURN(new, XML_ELEMENT_NO_OPENING_TAG);
                 }
+                found++;
             }
-            while (p && (*(p-1) != '<'));
 
-            if (p)
+            new = memchr(cur, '>', restlen);
+            if (!new)
+                SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
+
+            restlen -= new-cur;
+            cur = new;
+            continue;
+        }
+
+        /* no leaf node, continue */
+        if (*cur != '/')                       /* cascading tag found */
+        {
+            char *node = "*";
+            size_t slen = restlen+1; /* due to cur-1 below*/
+            size_t nlen = 1;
+            size_t pos = -1;
+
+            /*
+             * recursively walk the xml tree from here
+             */
+            new = __xmlNodeGet(nnc, cur-1, &slen, &node, &nlen, &pos);
+            if (!new)
             {
-                char *rptr = cur;
+                if (nlen == 0)         /* error upstream */
+                {
+                    *rlen = nlen;
+                    *name = node;
+                    *len = slen;
+                    return 0;
+                }
+
+                if (slen == restlen)
+                    SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
 
-                p = cur;
-                while ((*cur++ != '>') && (cur<(p+len)));
-                len -= cur - p;
+                slen--;
+                new = cur + slen;
+                restlen -= slen;
+            }
+            else restlen -= slen;
+
+            /* 
+             * look for the closing tag of the cascading block
+             */
+            cur = new;
+            new = memchr(cur, '<', restlen);
+            if (!new)
+                SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
+
+            new++;
+            restlen -= new-cur;
+            cur = new;
+        }
 
-                do
+        if (*cur == '/')                               /* closing tag found */
+        {
+            if (!strncasecmp(new+1, element, elementlen))
+            {
+                if (*(new+elementlen+1) != '>')
+                    SET_ERROR_AND_RETURN(new+1, XML_ELEMENT_NO_CLOSING_TAG);
+
+#ifdef XML_USE_NODECACHE
+                cacheDataSet(nnc, element, elementlen, rptr, new-rptr-1);
+#endif
+                if (found == num)
                 {
-                    if ((p = memncasemem(cur, len, name, plen)) != 0)
+                    if (start_tag)
                     {
-                        len -= (p + plen) - cur;
-                        cur = p + plen;
-                        if (*(p-2) == '<' && *(p-1) == '/' && *(p+plen) == '>')
-                            break;
+                        *len = new-ret-1;
+                        open_element = start_tag;
+                        cdata = (char *)start;
+                        start_tag = 0;
                     }
+                    else /* report error */
+                        SET_ERROR_AND_RETURN(new, XML_ELEMENT_NO_OPENING_TAG);
                 }
-                while (p);
+                found++;
+            }
 
-                ret = rptr;
-          }
-      }
-   }
+            new = memchr(cur, '>', restlen);
+            if (!new)
+                SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
 
-   return ret;
-}
+            restlen -= new-cur;
+            cur = new;
+        }
+        else
+            SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
 
+    } /* while */
 
-#define CASECMP(a,b)   ( ((a) & 0xdf) == ((b) & 0xdf) )
-#define NOCASECMP(a,b) ( ((a)^(b)) & 0xdf )
+    if (found == 0)
+    {
+        ret = 0;
+        *rlen = 0;
+        *name = start_tag;
+        *len = XML_NO_ERROR;   /* element not found, no real error */
+    }
+    else
+    {
+        *rlen = open_len;
+        *name = open_element;
+        *nodenum = found;
+    }
 
-void *
-memncasemem(const void *haystack, size_t haystacklen,
-                         const void *needle, size_t needlelen)
+    return ret;
+}
+
+char *
+__xmlProcessCDATA(char **start, size_t *len)
 {
-    void *rptr = 0;
+    char *cur, *new;
+    size_t restlen = *len;
 
-    if (haystack && needle && (needlelen > 0) && (haystacklen >= needlelen))
+    cur = *start;
+    if ((restlen > 6) && (*(cur+1) == '-'))             /* comment */
     {
-        const char *ne = (const char *)needle + needlelen;
-        const char *he = (const char *)haystack + haystacklen;
-        const char *hne = he - needlelen;
-        char *ns, *hs = (char *)haystack;
+        new = __xmlCommentSkip(cur, restlen);
+        if (new)
+        {
+            *start = new;
+            *len = 0;
+        }
+        return new;
+    }
+
+    if (restlen < 12) return 0;                         /* ![CDATA[ ]]> */
+
+    cur = *start;
+    new = 0;
 
+    if (memcmp(cur, "![CDATA[", 8) == 0)
+    {
+        *start = cur+8;
+        cur += 8;
+        restlen -= 8;
         do
         {
-            rptr = 0;
-            ns = (char *)needle;
-            while((hs <= hne) && NOCASECMP(*hs,*ns))
-               hs++;
+            new = memchr(cur, ']', restlen);
+            if (new)
+            {
+                if ((restlen > 3) && (memcmp(new, "]]>", 3) == 0))
+                {
+                    *len = new-1 - *start;
+                    restlen -= 3;
+                    new += 3;
+                    break;
+                }
+                cur = new+1;
+            }
+            else
+            {
+                *len = 0;
+                break;
+            }
+        }
+        while (new && (restlen > 2));
+    }
+
+    return new;
+}
 
-            if (hs < hne)
+char *
+__xmlCommentSkip(const char *start, size_t len)
+{
+    char *cur, *new;
+
+    if (len < 7) return 0;                              /* !-- --> */
+
+    cur = (char *)start;
+    new = 0;
+
+    if (memcmp(cur, "!--", 3) == 0)
+    {
+        cur += 3;
+        len -= 3;
+        do
+        {
+            new = memchr(cur, '-', len);
+            if (new)
             {
-                rptr = hs;
-                while((hs < he) && (ns < ne) && !NOCASECMP(*hs,*ns))
+                len -= new-cur;
+                if ((len >= 3) && (memcmp(new, "-->", 3) == 0))
                 {
-                    hs++;
-                    ns++;
+                    new += 3;
+                    /* len -= 3; */
+                    break;
                 }
+                cur = new+1;
+                len -= cur-new;
             }
             else break;
         }
-        while (ns < ne);
+        while (new && (len > 2));
     }
 
-    return rptr;
+    return new;
 }
 
-#if 0
-const unsigned char *
-boyermoore_horspool_memmem(const unsigned char* haystack, size_t hlen,
-                           const unsigned char* needle,   size_t nlen)
+char *
+__xmlInfoProcess(const char *start, size_t len)
 {
-    size_t scan = 0;
-    size_t bad_char_skip[UCHAR_MAX + 1]; /* Officially called:
-                                          * bad character shift */
-    /* Sanity checks on the parameters */
-    if (nlen <= 0 || !haystack || !needle)
-        return NULL;
-    /* ---- Preprocess ---- */
-    /* Initialize the table to default value */
-    /* When a character is encountered that does not occur
-     * in the needle, we can safely skip ahead for the whole
-     * length of the needle.
-     */
-    for (scan = 0; scan <= UCHAR_MAX; scan = scan + 1)
-        bad_char_skip[scan] = nlen;
-    /* C arrays have the first byte at [0], therefore:
-     * [nlen - 1] is the last byte of the array. */
-    size_t last = nlen - 1;
-    /* Then populate it with the analysis of the needle */
-    for (scan = 0; scan < last; scan = scan + 1)
-        bad_char_skip[needle[scan]] = last - scan;
-    /* ---- Do the matching ---- */
-    /* Search the haystack, while the needle can still be within it. */
-    while (hlen >= nlen)
+    char *cur, *new;
+
+    cur = (char *)start;
+    new = 0;
+
+    if (*cur == '?')
     {
-        /* scan from the end of the needle */
-        for (scan = last; haystack[scan] == needle[scan]; scan = scan - 1)
-            if (scan == 0) /* If the first byte matches, we've found it. */
-                return haystack;
-        /* otherwise, we need to skip some bytes and start again. 
-           Note that here we are getting the skip value based on the last byte
-           of needle, no matter where we didn't match. So if needle is: "abcd"
-           then we are skipping based on 'd' and that value will be 4, and
-           for "abcdd" we again skip on 'd' but the value will be only 1.
-           The alternative of pretending that the mismatched character was 
-           the last character is slower in the normal case (Eg. finding 
-           "abcd" in "...azcd..." gives 4 by using 'd' but only 
-           4-2==2 using 'z'. */
-        hlen     -= bad_char_skip[haystack[last]];
-        haystack += bad_char_skip[haystack[last]];
+        if (len < 3) return 0;                         /* <? ?> */
+
+        cur++;
+        len--;
+        new = memchr(cur, '?', len);
+        if (!new || *(new+1) != '>') return 0;
+
+        new += 2;
     }
-    return NULL;
+
+    return new;
+}
+
+
+static void
+__xmlPrepareData(char **start, size_t *blocklen)
+{
+    size_t len = *blocklen;
+    char *pe, *ps = *start;
+
+    if (len > 1)
+    {
+        pe = ps + len-1;
+        while ((ps<pe) && isspace(*ps)) ps++;
+        while ((pe>ps) && isspace(*pe)) pe--;
+        len = (pe-ps)+1;
+    }
+    else if (isspace(*(ps+1))) len--;
+
+    /* CDATA or comment */
+    if ((len >= 2) && !strncmp(ps, "<!", 2))
+    {
+        char *start = ps+1;
+        size_t blocklen = len-1;
+        if (blocklen >= 6)                  /* !-- --> */
+        {
+            char *new = __xmlProcessCDATA(&start, &len);
+            if (new)
+            {
+                ps = start;
+                pe = ps + len;
+
+                while ((ps<pe) && isspace(*ps)) ps++;
+                while ((pe>ps) && isspace(*pe)) pe--;
+                len = (pe-ps);
+            }
+        }
+    }
+
+    *start = ps;
+    *blocklen = len;
+}
+
+#define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
+void *
+__xml_memncasecmp(const char *haystack, size_t *haystacklen,
+                  char **needle, size_t *needlelen)
+{
+    char *rptr = 0;
+
+    if (haystack && needle && needlelen && (*needlelen > 0)
+        && (*haystacklen >= *needlelen))
+    {
+        char *hs = (char *)haystack;
+        char *ns;
+        size_t i;
+
+        ns = *needle;
+
+        /* search for everything */
+        if ((*ns == '*') && (*needlelen == 1))
+        {
+           char *he = hs + *haystacklen;
+
+           while ((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
+           if (*(hs-1) == '/') hs--;
+
+           *needle = (char *)haystack;
+           *needlelen = hs - haystack;
+
+           ns = memchr(hs, '>', he-hs);
+           if (ns) hs = ns+1;
+           else hs = he;
+     
+           rptr = hs;
+        }
+        else
+        {
+            size_t nlen = *needlelen;
+            char *he = hs + *haystacklen;
+
+            for (i=0; i<nlen; i++)
+            {
+                if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
+                if (isspace(*hs) || (*hs == '/') || (*hs == '>')) break;
+                hs++;
+                ns++;
+            }
+
+            if (i == nlen)
+            {
+                *needle = (char *)haystack;
+                *needlelen = hs - haystack;
+
+                ns = memchr(hs, '>', he-hs);
+                if (ns) hs = ns+1;
+                else hs = he;
+
+                rptr = hs;
+            }
+            else /* not found */
+            {
+                while((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
+                if (*(hs-1) == '/') hs--;
+
+                *needle = (char *)haystack;
+                *needlelen = hs - haystack;
+
+                ns = memchr(hs, '>', he-hs);
+                if (ns) hs = ns+1;
+                else hs = he;
+            }
+        }
+
+        *haystacklen -= hs - haystack;
+    }
+
+    return rptr;
+}
+
+#ifndef XML_NONVALIDATING
+void
+__xmlErrorSet(const void *id, const char *pos, unsigned int err_no)
+{
+   struct _xml_id *xid = (struct _xml_id *)id;
+   struct _root_id *rid;
+
+   assert(xid != 0);
+
+   if (xid->name) rid = xid->root;
+   else rid = (struct _root_id *)xid;
+
+   assert(rid != 0);
+   if (rid->info == 0)
+   {
+      rid->info = malloc(sizeof(struct _xml_error));
+   }
+
+   if (rid->info)
+   {
+      struct _xml_error *err = rid->info;
+
+      err->pos = (char *)pos;
+      err->err_no = err_no;
+   }
 }
 #endif
 
@@ -698,27 +1958,25 @@ boyermoore_horspool_memmem(const unsigned char* haystack, size_t hlen,
  */
 
 void *
-simple_mmap(int fd, unsigned int length, SIMPLE_UNMMAP *un)
+simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
 {
     HANDLE f;
     HANDLE m;
     void *p;
 
     f = (HANDLE)_get_osfhandle(fd);
-    if (!f) return NULL;
+    if (!f) return (void *)-1;
 
     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
-    if (!m) return NULL;
+    if (!m) return (void *)-1;
 
     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
     if (!p)
     {
         CloseHandle(m);
-        return NULL;
+        return (void *)-1;
     }
 
-    if (n) *n = GetFileSize(f, NULL);
-
     if (un)
     {
         un->m = m;
@@ -731,7 +1989,7 @@ simple_mmap(int fd, unsigned int length, SIMPLE_UNMMAP *un)
 void
 simple_unmmap(SIMPLE_UNMMAP *un)
 {
-   UnmapViewOfFile(un->p);
-   CloseHandle(un->m);
+    UnmapViewOfFile(un->p);
+    CloseHandle(un->m);
 }
 #endif