]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xml.c
Various bugfixes. This allows me to run fgrun on all FlightGear aircraft in the base...
[flightgear.git] / utils / xmlgrep / xml.c
1 /* Copyright (c) 2007-2009 by Adalin B.V.
2  * Copyright (c) 2007-2009 by Erik Hofman
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *      * Redistributions of source code must retain the above copyright
8  *         notice, this list of conditions and the following disclaimer.
9  *      * Redistributions in binary form must reproduce the above copyright
10  *         notice, this list of conditions and the following disclaimer in the
11  *         documentation and/or other materials provided with the distribution.
12  *      * Neither the name of (any of) the copyrightholder(s) nor the
13  *         names of its contributors may be used to endorse or promote products
14  *         derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #ifdef WIN32
29 # define WIN32_LEAN_AND_MEAN
30 # include <windows.h>
31 # include <io.h>
32
33 typedef struct
34 {
35     HANDLE m;
36     void *p;
37 } SIMPLE_UNMMAP;
38
39 #else   /* !WIN32 */
40 # include <sys/mman.h>
41 # include <unistd.h>
42 #endif
43
44 #ifndef NDEBUG
45 # include <stdio.h>
46 #endif
47 #include <stdlib.h>     /* free, malloc */
48 #include <string.h>     /* memcmp */
49 #ifndef _MSC_VER
50 #include <strings.h>    /* strncasecmp */
51 #else
52 # define strncasecmp strnicmp
53 #endif
54 #include <fcntl.h>
55 #include <sys/stat.h>
56 #include <sys/types.h>
57 #include <assert.h>
58 #include <ctype.h>
59
60 #ifndef XML_NONVALIDATING
61 #include "xml.h"
62
63 static const char *__xml_error_str[XML_MAX_ERROR];
64
65 struct _xml_error
66 {
67     char *pos;
68     int err_no;
69 };
70
71 static void __xmlErrorSet(const void *, const char *, unsigned int);
72 # define xmlErrorSet(a, b, c)   __xmlErrorSet(a, b, c)
73
74 # ifndef NDEBUG
75 # define PRINT_INFO(a) \
76         assert((a) < XML_MAX_ERROR); \
77         printf("at line %i: %s\n", __LINE__, __xml_error_str[(a)])
78 # else
79 # define PRINT_INFO(a)
80 # endif
81
82 # define SET_ERROR_AND_RETURN(a, b) \
83        { *rlen = 0; *name = (a); *len = (b); PRINT_INFO(b); return 0; }
84
85 #else /* !XML_NONVALIDATING */
86 # define xmlErrorSet(a, b, c)
87 # define SET_ERROR_AND_RETURN(a, b)     return 0;
88 #endif
89
90 /*
91  * It is required for both the rood node and the normal xml nodes to both
92  * have 'char *name' defined as the first entry. The code tests whether
93  * name == 0 to detect the root node.
94  */
95 struct _root_id
96 {
97     char *name;
98     char *start;
99     size_t len;
100     int fd;
101 #ifndef XML_NONVALIDATING
102     struct _xml_error *info;
103 #endif
104 # ifdef WIN32
105     SIMPLE_UNMMAP un;
106 # endif
107 };
108
109 struct _xml_id
110 {
111     char *name;
112     char *start;
113     size_t len;
114     size_t name_len;
115 #ifndef XML_NONVALIDATING
116     struct _root_id *root;
117 #endif
118 };
119
120 static char *__xmlNodeCopy(const char *, size_t *, const char **);
121 static char *__xmlNodeGetPath(const char *, size_t *, char **, size_t *);
122 static char *__xmlNodeGet(const char *, size_t *, char **, size_t *, size_t *);
123 static char *__xmlProcessCDATA(char **, size_t *);
124 static char *__xmlCommentSkip(const char *, size_t);
125 static char *__xmlInfoProcess(const char *, size_t);
126
127 static void *__xml_memncasecmp(const char *, size_t *, char **, size_t *);
128 static void __xmlPrepareData(char **, size_t *);
129
130 #ifdef WIN32
131 /*
132  * map 'filename' and return a pointer to it.
133  */
134 static void *simple_mmap(int, size_t, SIMPLE_UNMMAP *);
135 static void simple_unmmap(SIMPLE_UNMMAP *);
136
137 # define mmap(a,b,c,d,e,f)       simple_mmap((e), (b), &rid->un)
138 # define munmap(a,b)             simple_unmmap(&rid->un)
139 #endif
140
141 #ifndef NDEBUG
142 # define PRINT(a, b, c) { \
143    if (a) { \
144       size_t q, len = c; \
145       if (b < c) len = b; \
146       if (len < 50000) { \
147          printf("(%i) '", len); \
148          for (q=0; q<len; q++) printf("%c", ((char *)(a))[q]); \
149          printf("'\n"); \
150       } else printf("Length (%u) seems too large at line %i\n",len, __LINE__); \
151    } else printf("NULL pointer at line %i\n", __LINE__); \
152 }
153 #endif
154
155 void *
156 xmlOpen(const char *filename)
157 {
158     struct _root_id *rid = 0;
159
160     if (filename)
161     {
162         int fd = open(filename, O_RDONLY);
163         if (fd >= 0)
164         {
165             struct stat statbuf;
166             void *mm;
167
168             fstat(fd, &statbuf);
169             mm = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0L);
170             if (mm != (void *)-1)
171             {
172                 rid = malloc(sizeof(struct _root_id));
173                 if (rid)
174                 {
175                     rid->fd = fd;
176                     rid->start = mm;
177                     rid->len = statbuf.st_size;
178                     rid->name = 0;
179 #ifndef XML_NONVALIDATING
180                     rid->info = 0;
181 #endif
182                 }
183             }
184         }
185     }
186
187     return (void *)rid;
188 }
189
190 void *
191 xmlInitBuffer(const char *buffer, size_t size)
192 {
193     struct _root_id *rid = 0;
194
195     if (buffer && (size > 0))
196     {
197         rid = malloc(sizeof(struct _root_id));
198         if (rid)
199         {
200             rid->fd = -1;
201             rid->start = (char *)buffer;
202             rid->len = size;
203             rid->name = 0;
204 #ifndef XML_NONVALIDATING
205             rid->info = 0;
206 #endif
207         }
208     }
209
210     return (void *)rid;
211 }
212
213 void
214 xmlClose(void *id)
215 {
216      struct _root_id *rid = (struct _root_id *)id;
217
218      assert(rid != 0);
219      assert(rid->name == 0);
220
221      if (rid->fd != -1)
222      {
223          munmap(rid->start, rid->len);
224          close(rid->fd);
225      }
226
227      if (rid->info) free(rid->info);
228      free(rid);
229      id = 0;
230 }
231
232 void *
233 xmlNodeGet(const void *id, const char *path)
234 {
235     struct _xml_id *xid = (struct _xml_id *)id;
236     struct _xml_id *xsid = 0;
237     size_t len, slen;
238     char *ptr, *node;
239
240     assert(id != 0);
241     assert(path != 0);
242
243     node = (char *)path;
244     len = xid->len;
245     slen = strlen(path);
246     ptr = __xmlNodeGetPath(xid->start, &len, &node, &slen);
247     if (ptr)
248     {
249         xsid = malloc(sizeof(struct _xml_id));
250         if (xsid)
251         {
252              xsid->len = len;
253              xsid->start = ptr;
254              xsid->name_len = slen;
255              xsid->name = node;
256 #ifndef XML_NONVALIDATING
257              if (xid->name)
258                 xsid->root = xid->root;
259              else
260                 xsid->root = (struct _root_id *)xid;
261 #endif
262         }
263         else
264         {
265             xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
266         }
267     }
268     else if (slen == 0)
269     {
270         xmlErrorSet(xid, node, len);
271     }
272
273     return (void *)xsid;
274 }
275
276 void *
277 xmlNodeCopy(const void *id, const char *path)
278 {
279     struct _xml_id *xid = (struct _xml_id *)id;
280     struct _xml_id *xsid = 0;
281     char *ptr, *node, *p;
282     size_t slen, len;
283
284     node = (char *)path;
285     len = xid->len;
286     slen = strlen(path);
287     ptr = __xmlNodeGetPath(xid->start, &len, &node, &slen);
288     if (ptr)
289     {
290         xsid = malloc(sizeof(struct _xml_id) + len);
291         if (xsid)
292         {
293             p = (char *)xsid + sizeof(struct _xml_id);
294
295             xsid->len = len;
296             xsid->start = p;
297             xsid->name_len = slen;
298             xsid->name = node;
299 #ifndef XML_NONVALIDATING
300             if (xid->name)
301                 xsid->root = xid->root;
302             else
303                 xsid->root = (struct _root_id *)xid;
304 #endif
305
306             memcpy(xsid->start, ptr, len);
307         }
308         else
309         {
310             xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
311         }
312     }
313     else if (slen == 0)
314     {
315         xmlErrorSet(xid, node, len);
316     }
317
318    return (void *)xsid;
319 }
320
321 char *
322 xmlNodeGetName(const void *id)
323 {
324     struct _xml_id *xid = (struct _xml_id *)id;
325     size_t len;
326     char *ret;
327
328     assert(xid != 0);
329
330     len = xid->name_len;
331     ret = malloc(len+1);
332     if (ret)
333     {
334         memcpy(ret, xid->name, len);
335         *(ret + len) = 0;
336     }
337     else
338     {
339         xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
340     }
341
342     return ret;
343 }
344
345 size_t
346 xmlNodeCopyName(const void *id, char *buf, size_t buflen)
347 {
348     struct _xml_id *xid = (struct _xml_id *)id;
349     size_t slen = 0;
350  
351     assert(buf != 0);
352     assert(buflen > 0);
353
354     slen = xid->name_len;
355     if (slen >= buflen)
356     {
357         slen = buflen-1;
358         xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
359     }
360     memcpy(buf, xid->name, slen);
361     *(buf + slen) = 0;
362
363     return slen;
364 }
365
366 unsigned int
367 xmlNodeGetNum(const void *id, const char *path)
368 {
369     struct _xml_id *xid = (struct _xml_id *)id;
370     size_t num = 0;
371
372     assert(xid != 0);
373     assert(path != 0);
374
375     if (xid->len)
376     {
377         char *nodename, *pathname;
378         size_t len, slen;
379         char *p;
380
381         nodename = (char *)path;
382         if (*path == '/') nodename++;
383         slen = strlen(nodename);
384
385         pathname = strchr(nodename, '/');
386         if (pathname)
387         {
388            char *node;
389
390            len = xid->len;
391            pathname++;
392            slen -= pathname-nodename;
393            node = pathname;
394            p = __xmlNodeGetPath(xid->start, &len, &node, &slen);
395            if (p == 0 && slen == 0)
396            {
397                xmlErrorSet(xid, node, len);
398            }
399         }
400         else
401         {
402             p = xid->start;
403             len = xid->len;
404         }
405
406         if (p)
407         {
408             char *ret, *node = nodename;
409             ret = __xmlNodeGet(p, &len, &node, &slen, &num);
410             if (ret == 0 && slen == 0)
411             {
412                 xmlErrorSet(xid, node, len);
413                 num = 0;
414             }
415         }
416     }
417
418     return num;
419 }
420
421 void *
422 xmlNodeGetPos(const void *pid, void *id, const char *element, size_t num)
423 {
424     struct _xml_id *xpid = (struct _xml_id *)pid;
425     struct _xml_id *xid = (struct _xml_id *)id;
426     size_t len, slen;
427     char *ptr, *node;
428     void *ret = 0;
429
430     assert(xpid != 0);
431     assert(xid != 0);
432     assert(element != 0);
433
434     len = xpid->len;
435     slen = strlen(element);
436     node = (char *)element;
437     ptr = __xmlNodeGet(xpid->start, &len, &node, &slen, &num);
438     if (ptr)
439     {
440          xid->len = len;
441          xid->start = ptr;
442          xid->name = node;
443          xid->name_len = slen;
444          ret = xid;
445     }
446     else if (slen == 0)
447     {
448         xmlErrorSet(xpid, node, len);
449     }
450
451     return ret;
452 }
453
454 char *
455 xmlGetString(const void *id)
456 {
457     struct _xml_id *xid = (struct _xml_id *)id;
458     char *str = 0;
459
460     assert(xid != 0);
461
462     if (xid->len)
463     {
464         size_t len;
465         char *ps;
466
467         ps = xid->start;
468         len = xid->len;
469         __xmlPrepareData(&ps, &len);
470
471         if (len)
472         {
473             str = malloc(len+1);
474             if (str)
475             {
476                 memcpy(str, ps, len);
477                 *(str+len) = 0;
478             }
479             else
480             {
481                 xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
482             }
483         }
484     }
485
486     return str;
487 }
488
489 size_t
490 xmlCopyString(const void *id, char *buffer, size_t buflen)
491 {
492     struct _xml_id *xid = (struct _xml_id *)id;
493     size_t ret = 0;
494  
495     assert(xid != 0);
496     assert(buffer != 0);
497     assert(buflen > 0);
498
499     if (xid->len)
500     {
501         size_t len;
502         char *ps,
503
504         *buffer = '\0';
505         ps = xid->start;
506         len = xid->len;
507         __xmlPrepareData(&ps, &len);
508
509         if (len)
510         {
511             if (len >= buflen)
512             {
513                 len = buflen-1;
514                 xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
515             }
516             memcpy(buffer, ps, len);
517             *(buffer+len) = 0;
518             ret = len;
519         }
520     }
521
522     return ret;
523 }
524
525 int
526 xmlCompareString(const void *id, const char *s)
527 {
528     struct _xml_id *xid = (struct _xml_id *)id;
529     int ret = -1;
530
531     assert(xid != 0);
532     assert(s != 0);
533
534     if (xid->len && (strlen(s) > 0))
535     {
536         size_t len;
537         char *ps;
538
539         ps = xid->start;
540         len = xid->len-1;
541         __xmlPrepareData(&ps, &len);
542         ret = strncasecmp(ps, s, len);
543     }
544
545     return ret;
546 }
547
548 char *
549 xmlNodeGetString(const void *id, const char *path)
550 {
551     struct _xml_id *xid = (struct _xml_id *)id;
552     char *str = 0;
553
554     assert(xid != 0);
555     assert(path != 0);
556
557     if (xid->len)
558     {
559         size_t len = xid->len;
560         char *node = (char *)path;
561
562         str = __xmlNodeCopy(xid->start, &len, &path);
563         if (str)
564         {
565             size_t len;
566             char *ps, *pe;
567
568             ps = str;
569             len = strlen(str);
570             __xmlPrepareData(&ps, &len);
571             pe = ps + len;
572
573             *++pe = 0;
574             if (len && (ps>str)) memmove(str, ps, len);
575             else if (!len) *str = 0;
576         }
577         else
578         {
579             xmlErrorSet(xid, node, len);
580         }
581     }
582
583     return str;
584 }
585
586 size_t
587 xmlNodeCopyString(const void *id, const char *path, char *buffer, size_t buflen)
588 {
589     struct _xml_id *xid = (struct _xml_id *)id;
590     size_t ret = 0;
591
592     assert(xid != 0);
593     assert(path != 0);
594     assert(buffer != 0);
595     assert(buflen > 0);
596
597     if (xid->len)
598     {
599         char *str, *node;
600         size_t slen, len;
601
602         *buffer = '\0';
603         len = xid->len;
604         slen = strlen(path);
605         node = (char *)path;
606         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
607         if (str)
608         {
609             char *ps = str;
610             __xmlPrepareData(&ps, &len);
611
612             if (len >= buflen)
613             {
614                 len = buflen-1;
615                 xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
616             }
617
618             memcpy(buffer, ps, len);
619             *(buffer + len) = '\0';
620             ret = len;
621         }
622         else if (slen == 0)
623         {
624             xmlErrorSet(xid, node, len);
625         }
626     }
627
628     return ret;
629 }
630
631 int
632 xmlNodeCompareString(const void *id, const char *path, const char *s)
633 {
634     struct _xml_id *xid = (struct _xml_id *)id;
635     int ret = -1;
636
637     assert(xid != 0);
638     assert(path != 0);
639     assert(s != 0);
640
641     if (xid->len && (strlen(s) > 0))
642     {
643         char *node, *str, *ps, *pe;
644         size_t len, slen;
645
646         len = xid->len;
647         slen = strlen(path);
648         node = (char *)path;
649         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
650         if (str)
651         {
652             ps = str;
653             __xmlPrepareData(&ps, &len);
654             ret = strncasecmp(ps, s, len);
655         }
656         else if (slen == 0)
657         {
658             xmlErrorSet(xid, node, len);
659         }
660     }
661
662     return ret;
663 }
664
665 long int
666 xmlGetInt(const void *id)
667 {
668     struct _xml_id *xid = (struct _xml_id *)id;
669     long int li = 0;
670
671     assert(xid != 0);
672
673     if (xid->len)
674     {
675         char *end = xid->start + xid->len;
676         li = strtol(xid->start, &end, 10);
677     }
678
679     return li;
680 }
681
682 long int
683 xmlNodeGetInt(const void *id, const char *path)
684 {
685     struct _xml_id *xid = (struct _xml_id *)id;
686     long int li = 0;
687
688     assert(xid != 0);
689     assert(path != 0);
690
691     if (xid->len)
692     {
693         size_t len, slen;
694         char *str, *node;
695
696         len = xid->len;
697         slen = strlen(path);
698         node = (char *)path;
699         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
700         if (str)
701         {
702             char *end = str+len;
703             li = strtol(str, &end, 10);
704         }
705         else if (slen == 0)
706         {
707             xmlErrorSet(xid, node, len);
708         }
709     }
710
711     return li;
712 }
713
714 double
715 xmlGetDouble(const void *id)
716 {
717     struct _xml_id *xid = (struct _xml_id *)id;
718     double d = 0.0;
719
720     assert(xid != 0);
721
722     if (xid->len)
723     {
724         char *end = xid->start + xid->len;
725         d = strtod(xid->start, &end);
726     }
727
728     return d;
729 }
730
731 double
732 xmlNodeGetDouble(const void *id, const char *path)
733 {
734     struct _xml_id *xid = (struct _xml_id *)id;
735     double d = 0.0;
736
737     assert(xid != 0);
738     assert(path != 0);
739
740     if (xid->len)
741     {
742         size_t len, slen;
743         char *str, *node;
744
745         len = xid->len;
746         slen = strlen(path);
747         node = (char *)path;
748         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
749         if (str)
750         {
751             char *end = str+len;
752             d = strtod(str, &end);
753         }
754         else if (slen == 0)
755         {
756             xmlErrorSet(xid, node, len);
757         }
758     }
759
760     return d;
761 }
762
763 void *
764 xmlMarkId(const void *id)
765 {
766     struct _xml_id *xmid = 0;
767
768     assert(id != 0);
769
770     xmid = malloc(sizeof(struct _xml_id));
771     if (xmid)
772     {
773         struct _root_id *xrid = (struct _root_id *)id;
774         if (xrid->name == 0)
775         {
776             xmid->name = "";
777             xmid->start = xrid->start;
778             xmid->len = xrid->len;
779             xmid->name_len = 0;
780 #ifndef XML_NONVALIDATING
781             xmid->root = xrid;
782 #endif
783         }
784         else
785         {
786             memcpy(xmid, id, sizeof(struct _xml_id));
787         }
788     }
789     else
790     {
791         xmlErrorSet(id, 0, XML_OUT_OF_MEMORY);
792     }
793
794     return (void *)xmid;
795 }
796
797 double
798 xmlAttributeGetDouble(const void *id, const char *name)
799 {
800     struct _xml_id *xid = (struct _xml_id *)id;
801     double ret = 0.0;
802
803     assert(xid != 0);
804     assert(name != 0);
805
806     if (xid->name_len)
807     {
808         size_t slen = strlen(name);
809         char *ps, *pe;
810
811         assert(xid->start > xid->name);
812
813         ps = xid->name + xid->name_len + 1;
814         pe = xid->start - 1;
815         while (ps<pe)
816         {
817             while ((ps<pe) && isspace(*ps)) ps++;
818             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
819             {
820                 ps += slen;
821                 if ((ps<pe) && (*ps == '='))
822                 {
823                     char *start;
824
825                     ps++;
826                     if (*ps == '"' || *ps == '\'') ps++;
827                     else
828                     {
829                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
830                         return 0;
831                     }
832
833                     start = ps;
834                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
835                     if (ps<pe)
836                     {
837                         ret = strtod(start, &ps);
838                     }
839                     else
840                     {
841                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
842                         return 0;
843                     }
844                 }
845                 else
846                 {
847                     while ((ps<pe) && !isspace(*ps)) ps++;
848                     continue;
849                 }
850
851                 break;
852             }
853
854             while ((ps<pe) && !isspace(*ps)) ps++;
855         }
856     }
857
858     return ret;
859 }
860
861 long int
862 xmlAttributeGetInt(const void *id, const char *name)
863 {
864     struct _xml_id *xid = (struct _xml_id *)id;
865     long int ret = 0;
866
867     assert(xid != 0);
868     assert(name != 0);
869
870     if (xid->name_len)
871     {
872         size_t slen = strlen(name);
873         char *ps, *pe;
874
875         assert(xid->start > xid->name);
876
877         ps = xid->name + xid->name_len + 1;
878         pe = xid->start - 1;
879         while (ps<pe)
880         {
881             while ((ps<pe) && isspace(*ps)) ps++;
882             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
883             {
884                 ps += slen;
885                 if ((ps<pe) && (*ps == '='))
886                 {
887                     char *start;
888
889                     ps++;
890                     if (*ps == '"' || *ps == '\'') ps++;
891                     else
892                     {
893                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
894                         return 0;
895                     }
896
897                     start = ps;
898                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
899                     if (ps<pe)
900                     {
901                         ret = strtol(start, &ps, 10);
902                     }
903                     else
904                     {
905                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
906                        return 0;
907                    }
908                }
909                else
910                {
911                    while ((ps<pe) && isspace(*ps)) ps++;
912                    continue;
913                }
914
915                break;
916            }
917
918            while ((ps<pe) && !isspace(*ps)) ps++;
919         }
920     }
921
922     return ret;
923 }
924
925 char *
926 xmlAttributeGetString(const void *id, const char *name)
927 {
928     struct _xml_id *xid = (struct _xml_id *)id;
929     char *ret = 0;
930
931     assert(xid != 0);
932     assert(name != 0);
933
934     if (xid->name_len)
935     {
936         size_t slen = strlen(name);
937         char *ps, *pe;
938
939         assert(xid->start > xid->name);
940
941         ps = xid->name + xid->name_len + 1;
942         pe = xid->start - 1;
943         while (ps<pe)
944         {
945              while ((ps<pe) && isspace(*ps)) ps++;
946              if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
947              {
948                  ps += slen;
949                  if ((ps<pe) && (*ps == '='))
950                  {
951                      char *start;
952
953                      ps++;
954                      if (*ps == '"' || *ps == '\'') ps++;
955                      else
956                      {
957                          xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
958                          return 0;
959                      }
960
961                      start = ps;
962                      while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
963                      if (ps<pe)
964                      {
965                          ret = malloc(ps-start);
966                          if (ret)
967                          {
968                              memcpy(ret, start, (ps-start));
969                              *(ret+(ps-start)) = '\0';
970                          }
971                          else
972                          {
973                              xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
974                          }
975                      }
976                      else
977                      {
978                          xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
979                         return 0;
980                      }
981                  }
982                  else
983                  {
984                      while ((ps<pe) && !isspace(*ps)) ps++;
985                      continue;
986                  }
987
988
989                  break;
990              }
991
992              while ((ps<pe) && !isspace(*ps)) ps++;
993         }
994     }
995
996     return ret;
997 }
998
999 size_t
1000 xmlAttributeCopyString(const void *id, const char *name,
1001                                        char *buffer, size_t buflen)
1002 {
1003     struct _xml_id *xid = (struct _xml_id *)id;
1004     size_t ret = 0;
1005
1006     assert(xid != 0);
1007     assert(name != 0);
1008     assert(buffer != 0);
1009     assert(buflen > 0);
1010
1011     if (xid->name_len)
1012     {
1013         size_t slen = strlen(name);
1014         char *ps, *pe;
1015
1016         assert(xid->start > xid->name);
1017
1018         *buffer = '\0';
1019         ps = xid->name + xid->name_len + 1;
1020         pe = xid->start - 1;
1021         while (ps<pe)
1022         {
1023             while ((ps<pe) && isspace(*ps)) ps++;
1024             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
1025             {
1026                 ps += slen;
1027                 if ((ps<pe) && (*ps == '='))
1028                 {
1029                     char *start;
1030
1031                     ps++;
1032                     if (*ps == '"' || *ps == '\'') ps++;
1033                     else
1034                     {
1035                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
1036                         return 0;
1037                     }
1038
1039                     start = ps;
1040                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
1041                     if (ps<pe)
1042                     {
1043                         size_t restlen = ps-start;
1044                         if (restlen >= buflen)
1045                         {
1046                             restlen = buflen-1;
1047                             xmlErrorSet(xid, ps, XML_TRUNCATE_RESULT);
1048                         }
1049
1050                         memcpy(buffer, start, restlen);
1051                         *(buffer+restlen) = 0;
1052                         ret = restlen;
1053                     }
1054                     else
1055                     {
1056                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
1057                         return 0;
1058                     }
1059                 }
1060                 else
1061                 {
1062                     while ((ps<pe) && isspace(*ps)) ps++;
1063                     continue;
1064                 }
1065
1066                 break;
1067             }
1068
1069             while ((ps<pe) && !isspace(*ps)) ps++;
1070         }
1071     }
1072
1073     return ret;
1074 }
1075
1076 int
1077 xmlAttributeCompareString(const void *id, const char *name, const char *s)
1078 {
1079     struct _xml_id *xid = (struct _xml_id *)id;
1080     int ret = -1;
1081  
1082     assert(xid != 0);
1083     assert(name != 0);
1084     assert(s != 0);
1085
1086     if (xid->name_len && strlen(s))
1087     {
1088         size_t slen = strlen(name);
1089         char *ps, *pe;
1090
1091         assert(xid->start > xid->name);
1092
1093         ps = xid->name + xid->name_len + 1;
1094         pe = xid->start - 1;
1095         while (ps<pe)
1096         {
1097             while ((ps<pe) && isspace(*ps)) ps++;
1098             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
1099             {
1100                 ps += slen;
1101                 if ((ps<pe) && (*ps == '='))
1102                 {
1103                     char *start;
1104
1105                     ps++;
1106                     if (*ps == '"' || *ps == '\'') ps++;
1107                     else
1108                     {
1109                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
1110                         return 0;
1111                     }
1112
1113                     start = ps;
1114                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
1115                     if (ps<pe)
1116                     {
1117                         ret = strncasecmp(start, s, ps-start);
1118                     }
1119                     else
1120                     {
1121                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
1122                         return 0;
1123                     }
1124                 }
1125                 else
1126                 {
1127                     while ((ps<pe) && !isspace(*ps)) ps++;
1128                     continue;
1129                 }
1130
1131                 break;
1132             }
1133
1134             while ((ps<pe) && !isspace(*ps)) ps++;
1135         }
1136     }
1137
1138     return ret;
1139 }
1140
1141
1142 #ifndef XML_NONVALIDATING
1143 int
1144 xmlErrorGetNo(const void *id, int clear)
1145 {
1146     int ret = 0;
1147
1148     if (id)
1149     {
1150         struct _xml_id *xid = (struct _xml_id *)id;
1151         struct _root_id *rid;
1152
1153         if (xid->name) rid = xid->root;
1154         else rid = (struct _root_id *)xid;
1155
1156         assert(rid != 0);
1157
1158         if (rid->info)
1159         {
1160             struct _xml_error *err = rid->info;
1161
1162             ret = err->err_no;
1163             if (clear) err->err_no = 0;
1164         }
1165     }
1166
1167     return ret;
1168 }
1169
1170 size_t
1171 xmlErrorGetLineNo(const void *id, int clear)
1172 {
1173     size_t ret = 0;
1174
1175     if (id)
1176     {
1177         struct _xml_id *xid = (struct _xml_id *)id;
1178         struct _root_id *rid;
1179
1180         if (xid->name) rid = xid->root;
1181         else rid = (struct _root_id *)xid;
1182
1183         assert(rid != 0);
1184
1185         if (rid->info)
1186         {
1187             struct _xml_error *err = rid->info;
1188             char *ps = rid->start;
1189             char *pe = err->pos;
1190             char *new;
1191
1192             ret++;
1193             while (ps<pe)
1194             {
1195                new = memchr(ps, '\n', pe-ps);
1196                if (new) ret++;
1197                else break;
1198                ps = new+1;
1199             }       
1200
1201             if (clear) err->err_no = 0;
1202         }
1203     }
1204
1205     return ret;
1206 }
1207
1208 size_t
1209 xmlErrorGetColumnNo(const void *id, int clear)
1210 {
1211     size_t ret = 0;
1212
1213     if (id)
1214     {
1215         struct _xml_id *xid = (struct _xml_id *)id;
1216         struct _root_id *rid;
1217
1218         if (xid->name) rid = xid->root;
1219         else rid = (struct _root_id *)xid;
1220
1221         assert(rid != 0);
1222
1223         if (rid->info)
1224         {
1225             struct _xml_error *err = rid->info;
1226             char *ps = rid->start;
1227             char *pe = err->pos;
1228             char *new;
1229
1230             while (ps<pe)
1231             {
1232                new = memchr(ps, '\n', pe-ps);
1233                new = memchr(ps, '\n', pe-ps);
1234                if (new) ret++;
1235                else break;
1236                ps = new+1;
1237             }
1238             ret = pe-ps;
1239
1240             if (clear) err->err_no = 0;
1241         }
1242     }
1243
1244     return ret;
1245 }
1246
1247 const char *
1248 xmlErrorGetString(const void *id, int clear)
1249 {
1250     char *ret = 0;
1251
1252     if (id)
1253     {
1254         struct _xml_id *xid = (struct _xml_id *)id;
1255         struct _root_id *rid;
1256
1257         if (xid->name) rid = xid->root;
1258         else rid = (struct _root_id *)xid;
1259
1260         assert(rid != 0);
1261
1262         if (rid->info)
1263         {
1264             struct _xml_error *err = rid->info;
1265             if (XML_NO_ERROR <= err->err_no && err->err_no < XML_MAX_ERROR)
1266             {
1267                ret = (char *)__xml_error_str[err->err_no];
1268             }
1269             else
1270             {
1271                ret = "incorrect error number.";
1272             }
1273
1274             if (clear) err->err_no = 0;
1275         }
1276     }
1277
1278     return ret;
1279 }
1280 #endif
1281
1282 /* -------------------------------------------------------------------------- */
1283
1284 #ifndef XML_NONVALIDATING
1285 static const char *__xml_error_str[XML_MAX_ERROR] =
1286 {
1287     "no error.",
1288     "unable to allocate enough memory.",
1289     "unable to open file for reading.",
1290     "requested node name is invalid.",
1291     "unexpected end of section.",
1292     "buffer too small to hold all data, truncating.",
1293     "incorrect comment section.",
1294     "bad information block.",
1295     "incompatible opening tag for element.",
1296     "missing or invalid closing tag for element.",
1297     "missing or invalid opening quote for attribute.",
1298     "missing or invalid closing quote for attribute."
1299 };
1300 #endif
1301
1302 char *
1303 __xmlNodeCopy(const char *start, size_t *len, const char **path)
1304 {
1305     char *node, *p, *ret = 0;
1306     size_t rlen, slen;
1307
1308     rlen = *len;
1309     slen = strlen(*path);
1310     node = (char *)*path;
1311     p = __xmlNodeGetPath(start, &rlen, &node, &slen);
1312     if (p && rlen)
1313     {
1314         ret = malloc(rlen+1);
1315         if (ret)
1316         {
1317             memcpy(ret, p, rlen);
1318             *(ret+rlen) = '\0';
1319         }
1320         else
1321         {
1322             xmlErrorSet(0, 0, XML_OUT_OF_MEMORY);
1323         }
1324     }
1325     else if (slen == 0)
1326     {
1327         *path = node;
1328         *len = rlen;
1329     }
1330
1331     return ret;
1332 }
1333
1334 char *
1335 __xmlNodeGetPath(const char *start, size_t *len, char **name, size_t *nlen)
1336 {
1337     char *node;
1338     char *ret = 0;
1339
1340     assert(start != 0);
1341     assert(len != 0);
1342     assert(*len != 0);
1343     assert(name != 0);
1344     assert(*name != 0);
1345     assert(nlen != 0);
1346     assert(*nlen != 0);
1347
1348     if (*nlen > *len) return 0;
1349
1350     node = *name;
1351     if (*node == '/') node++;
1352     if (*node != 0)
1353     {
1354         size_t blen, plen, slen;
1355         char *path;
1356         size_t num;
1357
1358         slen = strlen(node);
1359         path = strchr(node, '/');
1360
1361         if (!path) plen = slen;
1362         else plen = path++ - node;
1363
1364         num = 0;
1365         blen = *len;
1366         ret = __xmlNodeGet(start, &blen, &node, &plen, &num);
1367         if (ret)
1368         {
1369             if (path)
1370             {
1371                 plen = slen - (path - *name);
1372                 ret = __xmlNodeGetPath(ret, &blen, &path, &plen);
1373                 *name = path;
1374             }
1375             else
1376             {
1377                *name = node;
1378                *nlen = plen;
1379                *len = blen;
1380             }
1381         }
1382         else
1383         {
1384             *len = 0;
1385             *nlen = 0;
1386         }
1387     }
1388
1389     return ret;
1390 }
1391
1392 char *
1393 __xmlNodeGet(const char *start, size_t *len, char **name, size_t *rlen, size_t *nodenum)
1394 {
1395     char *cdata, *open_element = *name;
1396     char *element, *start_tag=0;
1397     char *new, *cur, *ne, *ret = 0;
1398     size_t restlen, elementlen;
1399     size_t open_len = *rlen;
1400     size_t return_len = 0;
1401     int found, num;
1402
1403     assert(start != 0);
1404     assert(len != 0);
1405     assert(name != 0);
1406     assert(rlen != 0);
1407     assert(nodenum != 0);
1408
1409     if (open_len == 0 || *name == 0)
1410         SET_ERROR_AND_RETURN((char *)start, XML_INVALID_NODE_NAME);
1411
1412     cdata = (char *)start;
1413     if (*rlen > *len)
1414         SET_ERROR_AND_RETURN((char *)start, XML_UNEXPECTED_EOF);
1415
1416     found = 0;
1417     num = *nodenum;
1418     restlen = *len;
1419     cur = (char *)start;
1420     ne = cur + restlen;
1421
1422     /* search for an opening tag */
1423     while ((new = memchr(cur, '<', restlen)) != 0)
1424     {
1425         size_t len_remaining;
1426         char *rptr;
1427
1428         if (*(new+1) == '/')            /* end of section */
1429         {
1430             *len -= restlen;
1431              break;
1432         }
1433
1434         new++;
1435         restlen -= new-cur;
1436         cur = new;
1437
1438         if (*cur == '!') /* comment */
1439         {
1440             char *start = cur;
1441             size_t blocklen = restlen;
1442             new = __xmlProcessCDATA(&start, &blocklen);
1443             if (!new && start && open_len)                       /* CDATA */
1444                 SET_ERROR_AND_RETURN(cur, XML_INVALID_COMMENT);
1445
1446             restlen -= new-cur;
1447             cur = new;
1448             continue;
1449         }
1450         else if (*cur == '?') /* info block */
1451         {
1452             new = __xmlInfoProcess(cur, restlen);
1453             if (!new)
1454                 SET_ERROR_AND_RETURN(cur, XML_INVALID_INFO_BLOCK);
1455
1456             restlen -= new-cur;
1457             cur = new;
1458             continue;
1459         }
1460
1461         /*
1462          * get element name and a pointer to after the opening tag
1463          */
1464         element = *name;
1465         elementlen = *rlen;
1466         len_remaining = restlen;
1467         new = rptr = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
1468         if (rptr)                       /* requested element was found */
1469         {
1470             return_len = elementlen;
1471             if (found == num)
1472             {
1473                 ret = new;
1474                 open_len = elementlen;
1475                 start_tag = element;
1476             }
1477             else start_tag = 0;
1478         }
1479         else                            /* different element name was foud */
1480         {
1481             new = cur + (len_remaining - restlen);
1482             if (new >= ne)
1483                 SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
1484
1485             element = *name;
1486         }
1487
1488         if (*(new-2) == '/')                            /* e.g. <test/> */
1489         {
1490             cur = new;
1491             if (rptr)
1492             {
1493                 if (found == num)
1494                 {
1495                     open_element = start_tag;
1496                     *len = 0;
1497                 }
1498                 found++;
1499             }
1500             continue;
1501         }
1502
1503         /*
1504          * get the next xml tag
1505          */
1506         /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
1507         cur = new;
1508         new = memchr(cur, '<', restlen);
1509         if (!new)
1510             SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1511
1512         new++;
1513         restlen -= new-cur;
1514         cur = new;
1515         if (*cur == '!')                                /* comment, CDATA */
1516         {
1517             char *start = cur;
1518             size_t blocklen = restlen;
1519             new = __xmlProcessCDATA(&start, &blocklen);
1520             if (new && start && open_len)                       /* CDATA */
1521             {
1522                 cdata = ret;
1523             }
1524             else if (!new)
1525                 SET_ERROR_AND_RETURN(cur, XML_INVALID_COMMENT);
1526
1527             restlen -= new-cur;
1528             cur = new;
1529
1530             /*
1531              * look for the closing tag of the cascading block
1532              */
1533             new = memchr(cur, '<', restlen);
1534             if (!new)
1535                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1536
1537             new++;
1538             restlen -= new-cur;
1539             cur = new;
1540         }
1541
1542         if (*cur != '/')                        /* cascading tag found */
1543         {
1544             char *node = "*";
1545             size_t slen = restlen+1; /* due to cur-1 below*/
1546             size_t nlen = 1;
1547             size_t pos = -1;
1548
1549             /*
1550              * recursively walk the xml tree from here
1551              */
1552             new = __xmlNodeGet(cur-1, &slen, &node, &nlen, &pos);
1553             if (!new)
1554             {
1555                 if (nlen == 0)          /* error upstream */
1556                 {
1557                     *rlen = nlen;
1558                     *name = node;
1559                     *len = slen;
1560                     return 0;
1561                 }
1562
1563                 if (slen == restlen)
1564                     SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
1565
1566                 slen--;
1567                 new = cur + slen;
1568                 restlen -= slen;
1569             }
1570             else restlen -= slen;
1571
1572             /* 
1573              * look for the closing tag of the cascading block
1574              */
1575             cur = new;
1576             new = memchr(cur, '<', restlen);
1577             if (!new)
1578                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1579
1580             new++;
1581             restlen -= new-cur;
1582             cur = new;
1583         }
1584
1585         if (*cur == '/')                                /* closing tag found */
1586         {
1587             if (!strncasecmp(new+1, element, elementlen))
1588             {
1589                 if (*(new+elementlen+1) != '>')
1590                     SET_ERROR_AND_RETURN(new+1, XML_ELEMENT_NO_CLOSING_TAG);
1591
1592                 if (found == num)
1593                 {
1594                     if (start_tag)
1595                     {
1596                         *len = new-ret-1;
1597 #if 0
1598                         if (cdata == ret)
1599                         {
1600                             ret += 9;           /* ![CDATA[[     */
1601                             *len -= 12;         /* ![CDATA[[ ]]> */
1602                         }
1603 #endif
1604                         open_element = start_tag;
1605                         cdata = (char *)start;
1606                         start_tag = 0;
1607                     }
1608                     else /* report error */
1609                         SET_ERROR_AND_RETURN(new, XML_ELEMENT_NO_OPENING_TAG);
1610                 }
1611                 found++;
1612             }
1613
1614             new = memchr(cur, '>', restlen);
1615             if (!new)
1616                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1617
1618             restlen -= new-cur;
1619             cur = new;
1620         }
1621         else
1622             SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1623
1624     } /* while */
1625
1626     if (found == 0)
1627     {
1628         ret = 0;
1629         *rlen = 0;
1630         *name = start_tag;
1631         *len = XML_NO_ERROR;    /* element not found, no real error */
1632     }
1633     else
1634     {
1635         *rlen = open_len;
1636         *name = open_element;
1637         *nodenum = found;
1638     }
1639
1640     return ret;
1641 }
1642
1643 char *
1644 __xmlProcessCDATA(char **start, size_t *len)
1645 {
1646     char *cur, *new;
1647     size_t restlen = *len;
1648
1649     cur = *start;
1650     if ((restlen > 6) && (*(cur+1) == '-'))             /* comment */
1651     {
1652         new = __xmlCommentSkip(cur, restlen);
1653         if (new)
1654         {
1655             *start += 3;                                /* !-- */
1656             *len = (*start-cur)-3;                      /* --> */
1657         }
1658         return new;
1659     }
1660
1661     if (restlen < 12) return 0;                         /* ![CDATA[ ]]> */
1662
1663     cur = *start;
1664     new = 0;
1665
1666     if (memcmp(cur, "![CDATA[", 8) == 0)
1667     {
1668         *start = cur+8;
1669         cur += 8;
1670         restlen -= 8;
1671         do
1672         {
1673             new = memchr(cur, ']', restlen);
1674             if (new)
1675             {
1676                 if ((restlen > 3) && (memcmp(new, "]]>", 3) == 0))
1677                 {
1678                     *len = new-*start;
1679                     restlen -= 3;
1680                     new += 3;
1681                     break;
1682                 }
1683                 cur = new+1;
1684             }
1685             else
1686             {
1687                 *len = 0;
1688                 break;
1689             }
1690         }
1691         while (new && (restlen > 2));
1692     }
1693
1694     return new;
1695 }
1696
1697 char *
1698 __xmlCommentSkip(const char *start, size_t len)
1699 {
1700     char *cur, *new;
1701
1702     if (len < 7) return 0;                               /* !-- --> */
1703
1704     cur = (char *)start;
1705     new = 0;
1706
1707     if (memcmp(cur, "!--", 3) == 0)
1708     {
1709         cur += 3;
1710         len -= 3;
1711         do
1712         {
1713             new = memchr(cur, '-', len);
1714             if (new)
1715             {
1716                 len -= new - cur;
1717                 if ((len >= 3) && (memcmp(new, "-->", 3) == 0))
1718                 {
1719                     new += 3;
1720                     len -= 3;
1721                     break;
1722                 }
1723                 cur = new+1;
1724             }
1725             else break;
1726         }
1727         while (new && (len > 2));
1728     }
1729
1730     return new;
1731 }
1732
1733 char *
1734 __xmlInfoProcess(const char *start, size_t len)
1735 {
1736     char *cur, *new;
1737
1738     cur = (char *)start;
1739     new = 0;
1740
1741     if (*cur == '?')
1742     {
1743         if (len < 3) return 0;                          /* <? ?> */
1744
1745         cur++;
1746         len--;
1747         new = memchr(cur, '?', len);
1748         if (!new || *(new+1) != '>') return 0;
1749
1750         new += 2;
1751     }
1752
1753     return new;
1754 }
1755
1756
1757 static void __xmlPrepareData(char **start, size_t *blocklen)
1758 {
1759     size_t len = *blocklen;
1760     char *pe, *ps = *start;
1761
1762     pe = ps + len;
1763     while ((ps<pe) && isspace(*ps)) ps++;
1764     while ((pe>ps) && isspace(*pe)) pe--;
1765     len = (pe-ps);
1766
1767     /* CDATA or comment */
1768     if ((len >= 2) && !strncmp(ps, "<!", 2))
1769     {
1770         char *start = ps+1;
1771         size_t blocklen = len-1;
1772         if (blocklen >= 6)                  /* !-- --> */
1773         {
1774             char *new = __xmlProcessCDATA(&start, &blocklen);
1775             if (new)
1776             {
1777                 ps = start;
1778                 len = blocklen;
1779                 pe = ps + len;
1780
1781                 while ((ps<pe) && isspace(*ps)) ps++;
1782                 while ((pe>ps) && isspace(*pe)) pe--;
1783                 len = (pe-ps);
1784             }
1785         }
1786     }
1787
1788     *start = ps;
1789     *blocklen = len;
1790 }
1791
1792 #define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
1793 void *
1794 __xml_memncasecmp(const char *haystack, size_t *haystacklen,
1795                   char **needle, size_t *needlelen)
1796 {
1797     char *rptr = 0;
1798
1799     if (haystack && needle && needlelen && (*needlelen > 0)
1800         && (*haystacklen >= *needlelen))
1801     {
1802         char *hs = (char *)haystack;
1803         char *ns;
1804         size_t i;
1805
1806         ns = *needle;
1807
1808         /* search for everything */
1809         if ((*ns == '*') && (*needlelen == 1))
1810         {
1811            char *he = hs + *haystacklen;
1812
1813            while ((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1814            if (*(hs-1) == '/') hs--;
1815
1816            *needle = (char *)haystack;
1817            *needlelen = hs - haystack;
1818
1819            ns = memchr(hs, '>', he-hs);
1820            if (ns) hs = ns+1;
1821            else hs = he;
1822      
1823            rptr = hs;
1824         }
1825         else
1826         {
1827             size_t nlen = *needlelen;
1828             char *he = hs + *haystacklen;
1829
1830             for (i=0; i<nlen; i++)
1831             {
1832                 if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
1833                 if (isspace(*hs) || (*hs == '/') || (*hs == '>')) break;
1834                 hs++;
1835                 ns++;
1836             }
1837
1838             if (i == nlen)
1839             {
1840                 *needle = (char *)haystack;
1841                 *needlelen = hs - haystack;
1842
1843                 ns = memchr(hs, '>', he-hs);
1844                 if (ns) hs = ns+1;
1845                 else hs = he;
1846
1847                 rptr = hs;
1848             }
1849             else /* not found */
1850             {
1851                 while((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1852                 if (*(hs-1) == '/') hs--;
1853
1854                 *needle = (char *)haystack;
1855                 *needlelen = hs - haystack;
1856
1857                 ns = memchr(hs, '>', he-hs);
1858                 if (ns) hs = ns+1;
1859                 else hs = he;
1860             }
1861         }
1862
1863         *haystacklen -= hs - haystack;
1864     }
1865
1866     return rptr;
1867 }
1868
1869 #ifndef XML_NONVALIDATING
1870 void
1871 __xmlErrorSet(const void *id, const char *pos, unsigned int err_no)
1872 {
1873    struct _xml_id *xid = (struct _xml_id *)id;
1874    struct _root_id *rid;
1875
1876    assert(xid != 0);
1877
1878    if (xid->name) rid = xid->root;
1879    else rid = (struct _root_id *)xid;
1880
1881    assert(rid != 0);
1882    if (rid->info == 0)
1883    {
1884       rid->info = malloc(sizeof(struct _xml_error));
1885    }
1886
1887    if (rid->info)
1888    {
1889       struct _xml_error *err = rid->info;
1890
1891       err->pos = (char *)pos;
1892       err->err_no = err_no;
1893    }
1894 }
1895 #endif
1896
1897 #ifdef WIN32
1898 /* Source:
1899  * https://mollyrocket.com/forums/viewtopic.php?p=2529
1900  */
1901
1902 void *
1903 simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
1904 {
1905     HANDLE f;
1906     HANDLE m;
1907     void *p;
1908
1909     f = (HANDLE)_get_osfhandle(fd);
1910     if (!f) return (void *)-1;
1911
1912     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
1913     if (!m) return (void *)-1;
1914
1915     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
1916     if (!p)
1917     {
1918         CloseHandle(m);
1919         return (void *)-1;
1920     }
1921
1922     if (un)
1923     {
1924         un->m = m;
1925         un->p = p;
1926     }
1927
1928     return p;
1929 }
1930
1931 void
1932 simple_unmmap(SIMPLE_UNMMAP *un)
1933 {
1934     UnmapViewOfFile(un->p);
1935     CloseHandle(un->m);
1936 }
1937 #endif