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