]> git.mxchange.org Git - flightgear.git/blobdiff - utils/xmlgrep/xml.c
Add a new tool called fgviewer.
[flightgear.git] / utils / xmlgrep / xml.c
index 7c3386d062401ebf664a8f08e04d8505d21706ec..b9016c08e77f041c9d7c2b4a70c4bcd0877d7cff 100644 (file)
@@ -44,44 +44,48 @@ typedef struct
 #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 <stdlib.h>    /* free, malloc */
-#include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <assert.h>
 #include <ctype.h>
-#ifndef _MSC_VER
-# include <strings.h>  /* strncasecmp */
-#else
-# define strncasecmp strnicmp
-#endif
 
-enum
-{
-    XML_NO_ERROR = 0,
-    XML_OUT_OF_MEMORY,
-    XML_FILE_NOT_FOUND,
-    XML_TRUNCATE_RESULT,
-    XML_ELEMENT_NO_OPENING_TAG,
-    XML_ELEMENT_NO_CLOSING_TAG,
-    XML_ATTRIB_NO_OPENING_QUOTE,
-    XML_ATTRIB_NO_CLOSING_QUOTE,
-    XML_MAX_ERROR
-};
-static const char *__xml_error_str[XML_MAX_ERROR];
+#include "xml.h"
 
 #ifndef XML_NONVALIDATING
+static const char *__xml_error_str[XML_MAX_ERROR];
+
 struct _xml_error
 {
     char *pos;
-    int errno;
+    int err_no;
 };
 
 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; }
+
 #else /* !XML_NONVALIDATING */
 # define xmlErrorSet(a, b, c)
+# define SET_ERROR_AND_RETURN(a, b)    return 0;
 #endif
 
 /*
@@ -114,13 +118,14 @@ struct _xml_id
 #endif
 };
 
-static char *__xmlNodeCopy(const char *, size_t, const char *);
 static char *__xmlNodeGetPath(const char *, size_t *, char **, size_t *);
 static char *__xmlNodeGet(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
 /*
@@ -155,24 +160,50 @@ xmlOpen(const char *filename)
     if (filename)
     {
         int fd = open(filename, O_RDONLY);
-        if (fd > 0)
+        if (fd >= 0)
         {
-            rid = malloc(sizeof(struct _root_id));
-            if (rid)
+            struct stat statbuf;
+            void *mm;
+
+            fstat(fd, &statbuf);
+            mm = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0L);
+            if (mm != (void *)-1)
             {
-                struct stat statbuf;
+                rid = malloc(sizeof(struct _root_id));
+                if (rid)
+                {
+                    rid->fd = fd;
+                    rid->start = mm;
+                    rid->len = statbuf.st_size;
+                    rid->name = 0;
+#ifndef XML_NONVALIDATING
+                    rid->info = 0;
+#endif
+                }
+            }
+        }
+    }
+
+    return (void *)rid;
+}
 
-                fstat(fd, &statbuf);
+void *
+xmlInitBuffer(const char *buffer, size_t size)
+{
+    struct _root_id *rid = 0;
 
-                rid->fd = fd;
-                rid->len = statbuf.st_size;
-                rid->start = mmap(0, rid->len, PROT_READ, MAP_PRIVATE, fd, 0L);
-                rid->name = 0;
+    if (buffer && (size > 0))
+    {
+        rid = malloc(sizeof(struct _root_id));
+        if (rid)
+        {
+            rid->fd = -1;
+            rid->start = (char *)buffer;
+            rid->len = size;
+            rid->name = 0;
 #ifndef XML_NONVALIDATING
-                rid->info = 0;
-                __xmlErrorSet(rid, 0, 0);
+            rid->info = 0;
 #endif
-            }
         }
     }
 
@@ -187,9 +218,16 @@ xmlClose(void *id)
      assert(rid != 0);
      assert(rid->name == 0);
 
-     munmap(rid->start, rid->len);
-     close(rid->fd);
-     free(id);
+     if (rid->fd != -1)
+     {
+         munmap(rid->start, rid->len);
+         close(rid->fd);
+     }
+
+#ifndef XML_NONVALIDATING
+     if (rid->info) free(rid->info);
+#endif
+     free(rid);
      id = 0;
 }
 
@@ -225,7 +263,13 @@ xmlNodeGet(const void *id, const char *path)
 #endif
         }
         else
+        {
             xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+        }
+    }
+    else if (slen == 0)
+    {
+        xmlErrorSet(xid, node, len);
     }
 
     return (void *)xsid;
@@ -264,8 +308,14 @@ xmlNodeCopy(const void *id, const char *path)
             memcpy(xsid->start, ptr, len);
         }
         else
+        {
             xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
-   }
+        }
+    }
+    else if (slen == 0)
+    {
+        xmlErrorSet(xid, node, len);
+    }
 
    return (void *)xsid;
 }
@@ -287,7 +337,9 @@ xmlNodeGetName(const void *id)
         *(ret + len) = 0;
     }
     else
+    {
         xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+    }
 
     return ret;
 }
@@ -301,10 +353,10 @@ xmlNodeCopyName(const void *id, char *buf, size_t buflen)
     assert(buf != 0);
     assert(buflen > 0);
 
-    slen = buflen-1;
-    if (slen > xid->name_len)
+    slen = xid->name_len;
+    if (slen >= buflen)
     {
-        slen = xid->name_len;
+        slen = buflen-1;
         xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
     }
     memcpy(buf, xid->name, slen);
@@ -342,6 +394,10 @@ xmlNodeGetNum(const void *id, const char *path)
            slen -= pathname-nodename;
            node = pathname;
            p = __xmlNodeGetPath(xid->start, &len, &node, &slen);
+           if (p == 0 && slen == 0)
+           {
+               xmlErrorSet(xid, node, len);
+           }
         }
         else
         {
@@ -351,8 +407,13 @@ xmlNodeGetNum(const void *id, const char *path)
 
         if (p)
         {
-            char *node = nodename;
-            __xmlNodeGet(p, &len, &node, &slen, &num);
+            char *ret, *node = nodename;
+            ret = __xmlNodeGet(p, &len, &node, &slen, &num);
+            if (ret == 0 && slen == 0)
+            {
+                xmlErrorSet(xid, node, len);
+                num = 0;
+            }
         }
     }
 
@@ -384,6 +445,10 @@ xmlNodeGetPos(const void *pid, void *id, const char *element, size_t num)
          xid->name_len = slen;
          ret = xid;
     }
+    else if (slen == 0)
+    {
+        xmlErrorSet(xpid, node, len);
+    }
 
     return ret;
 }
@@ -398,27 +463,26 @@ xmlGetString(const void *id)
 
     if (xid->len)
     {
-        char *ps, *pe, *pend;
-        int nlen;
+        size_t len;
+        char *ps;
 
         ps = xid->start;
-        nlen = xid->len;
-        pend = ps+nlen;
-        pe = pend;
-
-        while ((ps<pe) && isspace(*ps)) ps++;
-        while ((pe>ps) && isspace(*pe)) pe--;
-        nlen = (pe-ps);
-        if (nlen)
+        len = xid->len-1;
+        __xmlPrepareData(&ps, &len);
+
+        if (len)
         {
-            str = malloc(nlen+1);
+            len++;
+            str = malloc(len+1);
             if (str)
             {
-                memcpy(str, ps, nlen);
-                *(str+nlen) = 0;
+                memcpy(str, ps, len);
+                *(str+len) = 0;
             }
             else
+            {
                 xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+            }
         }
     }
 
@@ -435,34 +499,27 @@ xmlCopyString(const void *id, char *buffer, size_t buflen)
     assert(buffer != 0);
     assert(buflen > 0);
 
+    *buffer = '\0';
     if (xid->len)
     {
-        char *ps, *pe, *pend;
-        size_t slen, nlen;
-
-        *buffer = '\0';
-        nlen = buflen-1;
-        ps = xid->start;
-        slen = xid->len;
-        pend = ps+slen;
-        pe = pend;
-
-        while ((ps<pe) && isspace(*ps)) ps++;
-        while ((pe>ps) && isspace(*pe)) pe--;
-        nlen = (pe-ps);
-        if (nlen > slen) nlen = slen;
+        size_t len;
+        char *p;
 
-        if (nlen)
+        p = xid->start;
+        len = xid->len-1;
+        __xmlPrepareData(&p, &len);
+        if (len)
         {
-            if (nlen >= buflen)
+            len++;
+            if (len >= buflen)
             {
-                nlen = buflen-1;
+                len = buflen-1;
                 xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
             }
-            memcpy(buffer, ps, nlen);
-            *(buffer+nlen) = 0;
-            ret = nlen;
+            memcpy(buffer, p, len);
+            *(buffer+len) = 0;
         }
+        ret = len;
     }
 
     return ret;
@@ -479,17 +536,13 @@ xmlCompareString(const void *id, const char *s)
 
     if (xid->len && (strlen(s) > 0))
     {
-        char *ps, *pe;
+        size_t len;
+        char *ps;
 
         ps = xid->start;
-        pe = ps + xid->len;
-        pe--;
-
-        while ((ps<pe) && isspace(*ps)) ps++;
-        while ((pe>ps) && isspace(*pe)) pe--;
-        pe++;
-
-        ret = strncasecmp(ps, s, pe-ps);
+        len = xid->len-1;
+        __xmlPrepareData(&ps, &len);
+        ret = strncasecmp(ps, s, len+1);
     }
 
     return ret;
@@ -506,24 +559,30 @@ xmlNodeGetString(const void *id, const char *path)
 
     if (xid->len)
     {
-        str = __xmlNodeCopy(xid->start, xid->len, path);
-        if (str)
-        {
-            char *ps, *pe, *pend;
-            int slen;
-
-            ps = str;
-            slen = strlen(str);
-            pend = ps+slen;
-            pe = pend-1;
+        char *p, *node = (char *)path;
+        size_t slen = strlen(node);
+        size_t len = xid->len;
 
-            while ((ps<pe) && isspace(*ps)) ps++;
-            while ((pe>ps) && isspace(*pe)) pe--;
+        slen = strlen(node);
+        p = __xmlNodeGetPath(xid->start, &len, &node, &slen);
+        if (p && len)
+        {
+            __xmlPrepareData(&p, &len);
 
-            *++pe = 0;
-            slen = (pe-ps);
-            if (slen && (ps>str)) memmove(str, ps, slen);
-            else if (!slen) *str = 0;
+            str = malloc(len+1);
+            if (str)
+            {
+               memcpy(str, p, len);
+               *(str+len) = '\0';
+            }
+            else
+            {
+                xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+            }
+        }
+        else
+        {
+            xmlErrorSet(xid, node, len);
         }
     }
 
@@ -541,36 +600,33 @@ xmlNodeCopyString(const void *id, const char *path, char *buffer, size_t buflen)
     assert(buffer != 0);
     assert(buflen > 0);
 
+    *buffer = '\0';
     if (xid->len)
     {
-        char *str, *node;
-        size_t slen, nlen;
+        char *p, *node = (char *)path;
+        size_t slen = strlen(node);
+        size_t len = xid->len;
 
-        *buffer = '\0';
-        nlen = xid->len;
-        slen = strlen(path);
-        node = (char *)path;
-        str = __xmlNodeGetPath(xid->start, &nlen, &node, &slen);
-        if (str)
+        p = __xmlNodeGetPath(xid->start, &len, &node, &slen);
+        if (p)
         {
-            char *ps, *pe;
-
-            ps = str;
-            pe = ps+nlen-1;
-
-            while ((ps<pe) && isspace(*ps)) ps++;
-            while ((pe>ps) && isspace(*pe)) pe--;
-
-            nlen = (pe-ps)+1;
-            if (nlen >= buflen)
+            __xmlPrepareData(&p, &len);
+            if (len)
             {
-                nlen = buflen-1;
-                xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
-            }
+                if (len >= buflen)
+                {
+                    len = buflen-1;
+                    xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
+                }
 
-            memcpy(buffer, ps, nlen);
-            *(buffer + nlen) = '\0';
-            ret = nlen;
+                memcpy(buffer, p, len);
+                *(buffer+len) = '\0';
+            }
+            ret = 0;
+        }
+        else if (slen == 0)
+        {
+            xmlErrorSet(xid, node, len);
         }
     }
 
@@ -599,14 +655,12 @@ xmlNodeCompareString(const void *id, const char *path, const char *s)
         if (str)
         {
             ps = str;
-            pe = ps + len;
-            pe--;
-
-            while ((ps<pe) && isspace(*ps)) ps++;
-            while ((pe>ps) && isspace(*pe)) pe--;
-            pe++;
-
-            ret = strncasecmp(ps, s, pe-ps);
+            __xmlPrepareData(&ps, &len);
+            ret = strncasecmp(ps, s, len);
+        }
+        else if (slen == 0)
+        {
+            xmlErrorSet(xid, node, len);
         }
     }
 
@@ -653,6 +707,10 @@ xmlNodeGetInt(const void *id, const char *path)
             char *end = str+len;
             li = strtol(str, &end, 10);
         }
+        else if (slen == 0)
+        {
+            xmlErrorSet(xid, node, len);
+        }
     }
 
     return li;
@@ -698,6 +756,10 @@ xmlNodeGetDouble(const void *id, const char *path)
             char *end = str+len;
             d = strtod(str, &end);
         }
+        else if (slen == 0)
+        {
+            xmlErrorSet(xid, node, len);
+        }
     }
 
     return d;
@@ -726,19 +788,13 @@ xmlMarkId(const void *id)
         }
         else
         {
-            struct _xml_id *xid = (struct _xml_id *)id;
-
-            xmid->name = xid->name;
-            xmid->start = xid->start;
-            xmid->len = xid->len;
-            xmid->name_len = xid->name_len;
-#ifndef XML_NONVALIDATING
-            xmid->root = xid->root;
-#endif
+            memcpy(xmid, id, sizeof(struct _xml_id));
         }
     }
     else
+    {
         xmlErrorSet(id, 0, XML_OUT_OF_MEMORY);
+    }
 
     return (void *)xmid;
 }
@@ -752,22 +808,19 @@ xmlAttributeGetDouble(const void *id, const char *name)
     assert(xid != 0);
     assert(name != 0);
 
-    if (xid->len && xid->name_len)
+    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) && isspace(*ps)) ps++;
         while (ps<pe)
         {
-            size_t slen = strlen(name);
-            size_t restlen = pe-ps;
-
-            if ((restlen > slen) && (strncasecmp(ps, name, slen) == 0))
+            while ((ps<pe) && isspace(*ps)) ps++;
+            if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
             {
                 ps += slen;
                 if ((ps<pe) && (*ps == '='))
@@ -785,19 +838,25 @@ xmlAttributeGetDouble(const void *id, const char *name)
                     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++;
-            if (ps<pe)
-                while ((ps<pe) && isspace(*ps)) ps++;
         }
     }
 
@@ -813,22 +872,19 @@ xmlAttributeGetInt(const void *id, const char *name)
     assert(xid != 0);
     assert(name != 0);
 
-    if (xid->len && xid->name_len)
+    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) && isspace(*ps)) ps++;
         while (ps<pe)
         {
-            size_t slen = strlen(name);
-            size_t restlen = pe-ps;
-
-            if ((restlen > slen) && (strncasecmp(ps, name, slen) == 0))
+            while ((ps<pe) && isspace(*ps)) ps++;
+            if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
             {
                 ps += slen;
                 if ((ps<pe) && (*ps == '='))
@@ -846,19 +902,25 @@ xmlAttributeGetInt(const void *id, const char *name)
                     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++;
-           if (ps<pe)
-               while ((ps<pe) && isspace(*ps)) ps++;
         }
     }
 
@@ -874,22 +936,19 @@ xmlAttributeGetString(const void *id, const char *name)
     assert(xid != 0);
     assert(name != 0);
 
-    if (xid->len && xid->name_len)
+    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) && isspace(*ps)) ps++;
         while (ps<pe)
         {
-             size_t slen = strlen(name);
-             size_t restlen = pe-ps;
-
-             if ((restlen > slen) && (strncasecmp(ps, name, slen) == 0))
+             while ((ps<pe) && isspace(*ps)) ps++;
+             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
              {
                  ps += slen;
                  if ((ps<pe) && (*ps == '='))
@@ -915,7 +974,9 @@ xmlAttributeGetString(const void *id, const char *name)
                              *(ret+(ps-start)) = '\0';
                          }
                          else
+                         {
                              xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
+                         }
                      }
                      else
                      {
@@ -923,12 +984,17 @@ xmlAttributeGetString(const void *id, const char *name)
                         return 0;
                      }
                  }
+                 else
+                 {
+                     while ((ps<pe) && !isspace(*ps)) ps++;
+                     continue;
+                 }
+
+
                  break;
              }
 
              while ((ps<pe) && !isspace(*ps)) ps++;
-             if (ps<pe)
-                 while ((ps<pe) && isspace(*ps)) ps++;
         }
     }
 
@@ -947,8 +1013,9 @@ xmlAttributeCopyString(const void *id, const char *name,
     assert(buffer != 0);
     assert(buflen > 0);
 
-    if (xid->len && xid->name_len)
+    if (xid->name_len)
     {
+        size_t slen = strlen(name);
         char *ps, *pe;
 
         assert(xid->start > xid->name);
@@ -956,14 +1023,10 @@ xmlAttributeCopyString(const void *id, const char *name,
         *buffer = '\0';
         ps = xid->name + xid->name_len + 1;
         pe = xid->start - 1;
-
-        while ((ps<pe) && isspace(*ps)) ps++;
         while (ps<pe)
         {
-            size_t slen = strlen(name);
-            size_t restlen = pe-ps;
-
-            if ((restlen > slen) && (strncasecmp(ps, name, slen) == 0))
+            while ((ps<pe) && isspace(*ps)) ps++;
+            if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
             {
                 ps += slen;
                 if ((ps<pe) && (*ps == '='))
@@ -982,7 +1045,7 @@ xmlAttributeCopyString(const void *id, const char *name,
                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
                     if (ps<pe)
                     {
-                        restlen = ps-start;
+                        size_t restlen = ps-start;
                         if (restlen >= buflen)
                         {
                             restlen = buflen-1;
@@ -999,12 +1062,16 @@ xmlAttributeCopyString(const void *id, const char *name,
                         return 0;
                     }
                 }
+                else
+                {
+                    while ((ps<pe) && isspace(*ps)) ps++;
+                    continue;
+                }
+
                 break;
             }
 
             while ((ps<pe) && !isspace(*ps)) ps++;
-            if (ps<pe)
-                while ((ps<pe) && isspace(*ps)) ps++;
         }
     }
 
@@ -1021,22 +1088,19 @@ xmlAttributeCompareString(const void *id, const char *name, const char *s)
     assert(name != 0);
     assert(s != 0);
 
-    if (xid->len && xid->name_len && strlen(s))
+    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) && isspace(*ps)) ps++;
         while (ps<pe)
         {
-            size_t slen = strlen(name);
-            size_t restlen = pe-ps;
-
-            if ((restlen > slen) && (strncasecmp(ps, name, slen) == 0))
+            while ((ps<pe) && isspace(*ps)) ps++;
+            if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
             {
                 ps += slen;
                 if ((ps<pe) && (*ps == '='))
@@ -1054,19 +1118,25 @@ xmlAttributeCompareString(const void *id, const char *name, const char *s)
                     start = ps;
                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
                     if (ps<pe)
+                    {
                         ret = strncasecmp(start, s, ps-start);
+                    }
                     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++;
-            if (ps<pe)
-                while ((ps<pe) && isspace(*ps)) ps++;
         }
     }
 
@@ -1076,7 +1146,7 @@ xmlAttributeCompareString(const void *id, const char *name, const char *s)
 
 #ifndef XML_NONVALIDATING
 int
-xmlErrorGetNo(const void *id)
+xmlErrorGetNo(const void *id, int clear)
 {
     int ret = 0;
 
@@ -1094,8 +1164,8 @@ xmlErrorGetNo(const void *id)
         {
             struct _xml_error *err = rid->info;
 
-            ret = err->errno;
-            err->errno = 0;
+            ret = err->err_no;
+            if (clear) err->err_no = 0;
         }
     }
 
@@ -1103,7 +1173,7 @@ xmlErrorGetNo(const void *id)
 }
 
 size_t
-xmlErrorGetLineNo(const void *id)
+xmlErrorGetLineNo(const void *id, int clear)
 {
     size_t ret = 0;
 
@@ -1124,16 +1194,55 @@ xmlErrorGetLineNo(const void *id)
             char *pe = err->pos;
             char *new;
 
+            ret++;
             while (ps<pe)
             {
                new = memchr(ps, '\n', pe-ps);
-               if (new)
-               {
-                  ps = new;
-                  ret++;
-               }
-               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;
         }
     }
 
@@ -1141,7 +1250,7 @@ xmlErrorGetLineNo(const void *id)
 }
 
 const char *
-xmlErrorGetString(const void *id)
+xmlErrorGetString(const void *id, int clear)
 {
     char *ret = 0;
 
@@ -1158,94 +1267,124 @@ xmlErrorGetString(const void *id)
         if (rid->info)
         {
             struct _xml_error *err = rid->info;
-            if (XML_NO_ERROR <= err->errno && err->errno < XML_MAX_ERROR)
-               ret = (char *)__xml_error_str[err->errno];
+            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.",
-    "provided buffer us too small to hold the result, truncating.",
+    "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 *
-__xmlNodeCopy(const char *start, size_t len, const char *path)
-{
-     char *node, *p, *ret = 0;
-     size_t rlen, slen;
-
-     rlen = len;
-     slen = strlen(path);
-     node = (char *)path;
-     p = __xmlNodeGetPath(start, &rlen, &node, &slen);
-     if (p && rlen)
-     {
-         ret = malloc(rlen+1);
-         if (ret)
-         {
-             memcpy(ret, p, rlen);
-             *(ret+rlen+1) = '\0';
-         }
-         else
-             xmlErrorSet(0, 0, XML_OUT_OF_MEMORY);
-     }
-
-     return ret;
-}
-
-char *
-__xmlNodeGetPath(const char *start, size_t *len, char **name, size_t *plen)
+__xmlNodeGetPath(const char *start, size_t *len, char **name, size_t *nlen)
 {
-    char *node;
+    char *path;
     char *ret = 0;
 
-    assert (start != 0);
-    assert (len != 0);
-    assert (name != 0);
-    assert (*name != 0);
-    assert (plen != 0);
+    assert(start != 0);
+    assert(len != 0);
+    assert(*len != 0);
+    assert(name != 0);
+    assert(*name != 0);
+    assert(nlen != 0);
+    assert(*nlen != 0);
 
-    if ((*len == 0) || (*plen == 0) || (*plen > *len))
-        return 0;
+    if (*nlen > *len) return 0;
 
-    node = *name;
-    if (*node == '/') node++;
-    if (*node != 0)
+    path = *name;
+    if (*path == '/') path++;
+    if (*path != '\0')
     {
-        size_t plen, slen;
-        char *path;
-        size_t num;
+        size_t num, blocklen, pathlen, nodelen;
+        char *node;
 
-        slen = strlen(node);
+        node = path;
+        pathlen = strlen(path);
         path = strchr(node, '/');
 
-        if (!path) plen = slen;
-        else plen = path++ - node;
+        if (!path) nodelen = pathlen;
+        else nodelen = path++ - node;
 
         num = 0;
-        ret = __xmlNodeGet(start, len, &node, &plen, &num);
-        if (ret && path)
+        blocklen = *len;
+        ret = __xmlNodeGet(start, &blocklen, &node, &nodelen, &num);
+        if (ret)
         {
-            plen = slen - (path - *name);
-            ret = __xmlNodeGetPath(ret, len, &path, &plen);
+            if (path)
+            {
+                ret = __xmlNodeGetPath(ret, &blocklen, &path, &pathlen);
+                *name = path;
+                *len = blocklen;
+                *nlen = pathlen;
+            }
+            else
+            {
+               *name = node;
+               *nlen = nodelen;
+               *len = blocklen;
+            }
+        }
+        else
+        {
+            *len = 0;
+            *nlen = 0;
         }
-
-        *name = path;
     }
 
     return ret;
@@ -1254,21 +1393,26 @@ __xmlNodeGetPath(const char *start, size_t *len, char **name, size_t *plen)
 char *
 __xmlNodeGet(const char *start, size_t *len, char **name, size_t *rlen, size_t *nodenum)
 {
-    char *new, *cur, *ne, *ret = 0;
+    char *cdata, *open_element = *name;
     char *element, *start_tag=0;
+    char *new, *cur, *ne, *ret = 0;
     size_t restlen, elementlen;
-    size_t retlen = 0;
+    size_t open_len = *rlen;
+    size_t return_len = 0;
     int found, num;
 
-    assert (start != 0);
-    assert (len != 0);
-    assert (name != 0);
-    assert (*name != 0);
-    assert (rlen != 0);
-    assert (nodenum != 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);
 
-    if ((*len == 0) || (*rlen == 0) || (*rlen > *len))
-        return 0;
+    cdata = (char *)start;
+    if (*rlen > *len)
+        SET_ERROR_AND_RETURN((char *)start, XML_UNEXPECTED_EOF);
 
     found = 0;
     num = *nodenum;
@@ -1276,9 +1420,13 @@ __xmlNodeGet(const char *start, size_t *len, char **name, size_t *rlen, size_t *
     cur = (char *)start;
     ne = cur + restlen;
 
+    /* search for an opening tag */
     while ((new = memchr(cur, '<', restlen)) != 0)
     {
-        if (*(new+1) == '/')           /* cascading closing tag found */
+        size_t len_remaining;
+        char *rptr;
+
+        if (*(new+1) == '/')           /* end of section */
         {
             *len -= restlen;
              break;
@@ -1288,131 +1436,318 @@ __xmlNodeGet(const char *start, size_t *len, char **name, size_t *rlen, size_t *
         restlen -= new-cur;
         cur = new;
 
-        if (*cur == '!')
+        if (*cur == '!') /* comment */
         {
-            new = __xmlCommentSkip(cur, restlen);
-            if (!new) return 0;
+            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 == '?')
+        else if (*cur == '?') /* info block */
         {
             new = __xmlInfoProcess(cur, restlen);
-            if (!new) return 0;
+            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;
-        new = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
-        if (new)
+        len_remaining = restlen;
+        new = rptr = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
+        if (rptr)                      /* requested element was found */
         {
-            retlen = elementlen;
-            if (found == num )
+            return_len = elementlen;
+            if (found == num)
             {
-              ret = new+1;
-              start_tag = element;
+                ret = new;
+                open_len = elementlen;
+                start_tag = element;
             }
             else start_tag = 0;
         }
-        else
+        else                           /* different element name was foud */
         {
-            new = cur+elementlen;
-            if (new >= ne) return 0;
+            new = cur + (len_remaining - restlen);
+            if (new >= ne)
+                SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
+
             element = *name;
         }
 
+        if (*(new-2) == '/')                           /* e.g. <test/> */
+        {
+            cur = new;
+            if (rptr)
+            {
+                if (found == num)
+                {
+                    open_element = start_tag;
+                    *len = 0;
+                }
+                found++;
+            }
+            continue;
+        }
+
+        /*
+         * get the next xml tag
+         */
         /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
         cur = new;
         new = memchr(cur, '<', restlen);
-        if (!new) return 0;
+        if (!new)
+            SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
 
+        new++;
         restlen -= new-cur;
         cur = new;
-        if (*(cur+1) != '/')                            /* new node found */
+        if (*cur == '!')                               /* comment, CDATA */
+        {
+            char *start = cur;
+            size_t blocklen = restlen;
+            new = __xmlProcessCDATA(&start, &blocklen);
+            if (new && start && open_len)                      /* CDATA */
+            {
+                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))
+            {
+                if (*(new+elementlen+1) != '>')
+                    SET_ERROR_AND_RETURN(new+1, XML_ELEMENT_NO_CLOSING_TAG);
+
+                if (found == num)
+                {
+                    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++;
+            }
+
+            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;
+            size_t slen = restlen+1; /* due to cur-1 below*/
             size_t nlen = 1;
             size_t pos = -1;
 
-            new = __xmlNodeGet(cur, &slen, &node, &nlen, &pos);
+            /*
+             * recursively walk the xml tree from here
+             */
+            new = __xmlNodeGet(cur-1, &slen, &node, &nlen, &pos);
             if (!new)
             {
-                if (slen == restlen) return 0;
-                else new = cur + slen;
+                if (nlen == 0)         /* error upstream */
+                {
+                    *rlen = nlen;
+                    *name = node;
+                    *len = slen;
+                    return 0;
+                }
+
+                if (slen == restlen)
+                    SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
+
+                slen--;
+                new = cur + slen;
+                restlen -= slen;
             }
+            else restlen -= slen;
 
-            restlen -= slen;
+            /* 
+             * look for the closing tag of the cascading block
+             */
             cur = new;
-
             new = memchr(cur, '<', restlen);
-            if (!new) return 0;
+            if (!new)
+                SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
 
+            new++;
             restlen -= new-cur;
             cur = new;
         }
 
-        if (*(cur+1) == '/')                           /* closing tag found */
+        if (*cur == '/')                               /* closing tag found */
         {
-            if (!strncasecmp(new+2, element, elementlen))
+            if (!strncasecmp(new+1, element, elementlen))
             {
-                if (found == num) 
+                if (*(new+elementlen+1) != '>')
+                    SET_ERROR_AND_RETURN(new+1, XML_ELEMENT_NO_CLOSING_TAG);
+
+                if (found == num)
                 {
-                   assert(start_tag != 0);
-                   *len = new-ret;
-                   *name = start_tag;
+                    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++;
             }
 
             new = memchr(cur, '>', restlen);
-            if (!new) return 0;
+            if (!new)
+                SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
 
             restlen -= new-cur;
             cur = new;
         }
-        else return 0;
-    }
+        else
+            SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
 
-    *rlen = retlen;
-    *nodenum = found;
+    } /* while */
+
+    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;
+    }
 
     return ret;
 }
 
+char *
+__xmlProcessCDATA(char **start, size_t *len)
+{
+    char *cur, *new;
+    size_t restlen = *len;
+
+    cur = *start;
+    if ((restlen > 6) && (*(cur+1) == '-'))             /* comment */
+    {
+        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
+        {
+            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;
+}
+
 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)
     {
-        if (len < 6) return 0;
-
         cur += 3;
         len -= 3;
-
         do
         {
             new = memchr(cur, '-', len);
             if (new)
             {
-                len -= new - cur;
-                if ((len > 3) && (memcmp(new, "-->", 3) == 0))
+                len -= new-cur;
+                if ((len >= 3) && (memcmp(new, "-->", 3) == 0))
                 {
                     new += 3;
-                    len -= 3;
+                    /* len -= 3; */
                     break;
                 }
                 cur = new+1;
+                len -= cur-new;
             }
             else break;
         }
@@ -1432,7 +1767,7 @@ __xmlInfoProcess(const char *start, size_t len)
 
     if (*cur == '?')
     {
-        if (len < 3) return 0;
+        if (len < 3) return 0;                         /* <? ?> */
 
         cur++;
         len--;
@@ -1446,12 +1781,47 @@ __xmlInfoProcess(const char *start, size_t len)
 }
 
 
+static void
+__xmlPrepareData(char **start, size_t *blocklen)
+{
+    size_t len = *blocklen;
+    char *pe, *ps = *start;
+
+    pe = ps + len;
+    while ((ps<pe) && isspace(*ps)) ps++;
+    while ((pe>ps) && isspace(*pe)) pe--;
+    len = (pe-ps);
+
+    /* 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)
 {
-    void *rptr = 0;
+    char *rptr = 0;
 
     if (haystack && needle && needlelen && (*needlelen > 0)
         && (*haystacklen >= *needlelen))
@@ -1467,10 +1837,16 @@ __xml_memncasecmp(const char *haystack, size_t *haystacklen,
         {
            char *he = hs + *haystacklen;
 
-           while ((hs < he) && (*hs != ' ') && (*hs != '>')) hs++;
+           while ((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
+           if (*(hs-1) == '/') hs--;
+
            *needle = (char *)haystack;
            *needlelen = hs - haystack;
-           while ((hs < he) && (*hs != '>')) hs++;
+
+           ns = memchr(hs, '>', he-hs);
+           if (ns) hs = ns+1;
+           else hs = he;
+     
            rptr = hs;
         }
         else
@@ -1481,23 +1857,33 @@ __xml_memncasecmp(const char *haystack, size_t *haystacklen,
             for (i=0; i<nlen; i++)
             {
                 if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
-                if ((*hs == ' ') || (*hs == '>')) break;
+                if (isspace(*hs) || (*hs == '/') || (*hs == '>')) break;
                 hs++;
                 ns++;
             }
 
-            if (i != nlen)
+            if (i == nlen)
             {
-                while((hs < he) && (*hs != ' ') && (*hs != '>')) hs++;
                 *needle = (char *)haystack;
                 *needlelen = hs - haystack;
+
+                ns = memchr(hs, '>', he-hs);
+                if (ns) hs = ns+1;
+                else hs = he;
+
+                rptr = hs;
             }
-            else
+            else /* not found */
             {
+                while((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
+                if (*(hs-1) == '/') hs--;
+
                 *needle = (char *)haystack;
                 *needlelen = hs - haystack;
-                while ((hs < he) && (*hs != '>')) hs++;
-                rptr = hs;
+
+                ns = memchr(hs, '>', he-hs);
+                if (ns) hs = ns+1;
+                else hs = he;
             }
         }
 
@@ -1509,7 +1895,7 @@ __xml_memncasecmp(const char *haystack, size_t *haystacklen,
 
 #ifndef XML_NONVALIDATING
 void
-__xmlErrorSet(const void *id, const char *pos, unsigned int errno)
+__xmlErrorSet(const void *id, const char *pos, unsigned int err_no)
 {
    struct _xml_id *xid = (struct _xml_id *)id;
    struct _root_id *rid;
@@ -1520,16 +1906,17 @@ __xmlErrorSet(const void *id, const char *pos, unsigned int errno)
    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->errno = errno;
+      err->err_no = err_no;
    }
 }
 #endif
@@ -1547,16 +1934,16 @@ simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
     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 (un)