]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xml.c
* Implement a node cache that can be enabled at compile time.
[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 = 0;
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(*len != 0);
1349     assert(name != 0);
1350     assert(*name != 0);
1351     assert(nlen != 0);
1352     assert(*nlen != 0);
1353
1354     if (*nlen > *len) return 0;
1355
1356     path = *name;
1357     if (*path == '/') path++;
1358     if (*path != '\0')
1359     {
1360         size_t num, blocklen, pathlen, nodelen;
1361         char *node;
1362
1363         node = path;
1364         pathlen = strlen(path);
1365         path = strchr(node, '/');
1366
1367         if (!path) nodelen = pathlen;
1368         else nodelen = path++ - node;
1369
1370         num = 0;
1371         blocklen = *len;
1372
1373 #ifndef XML_USE_NODECACHE
1374         ret = __xmlNodeGet(nc, start, &blocklen, &node, &nodelen, &num);
1375 #else
1376         ret = __xmlNodeGetFromCache(nc, start, &blocklen, &node, &nodelen, &num);
1377 #endif
1378         if (ret)
1379         {
1380             if (path)
1381             {
1382                 ret = __xmlNodeGetPath(nc, ret, &blocklen, &path, &pathlen);
1383                 *name = path;
1384                 *len = blocklen;
1385                 *nlen = pathlen;
1386             }
1387             else
1388             {
1389                *name = node;
1390                *nlen = nodelen;
1391                *len = blocklen;
1392             }
1393         }
1394         else
1395         {
1396             *len = 0;
1397             *nlen = 0;
1398         }
1399     }
1400
1401     return ret;
1402 }
1403
1404 char *
1405 __xmlNodeGet(void *nc, const char *start, size_t *len, char **name, size_t *rlen, size_t *nodenum)
1406 {
1407     char *cdata, *open_element = *name;
1408     char *element, *start_tag=0;
1409     char *new, *cur, *ne, *ret = 0;
1410     size_t restlen, elementlen;
1411     size_t open_len = *rlen;
1412     size_t return_len = 0;
1413     int found, num;
1414     void *nnc = 0;
1415
1416     assert(start != 0);
1417     assert(len != 0);
1418     assert(name != 0);
1419     assert(rlen != 0);
1420     assert(nodenum != 0);
1421
1422     if (open_len == 0 || *name == 0)
1423         SET_ERROR_AND_RETURN((char *)start, XML_INVALID_NODE_NAME);
1424
1425     cdata = (char *)start;
1426     if (*rlen > *len)
1427         SET_ERROR_AND_RETURN((char *)start, XML_UNEXPECTED_EOF);
1428
1429     found = 0;
1430     num = *nodenum;
1431     restlen = *len;
1432     cur = (char *)start;
1433     ne = cur + restlen;
1434
1435 #ifdef XML_USE_NODECACHE
1436     cacheInitLevel(nc);
1437 #endif
1438
1439     /* search for an opening tag */
1440     while ((new = memchr(cur, '<', restlen)) != 0)
1441     {
1442         size_t len_remaining;
1443         char *rptr;
1444
1445         if (*(new+1) == '/')            /* end of section */
1446         {
1447             *len -= restlen;
1448              break;
1449         }
1450
1451         new++;
1452         restlen -= new-cur;
1453         cur = new;
1454
1455         if (*cur == '!') /* comment */
1456         {
1457             char *start = cur;
1458             size_t blocklen = restlen;
1459             new = __xmlProcessCDATA(&start, &blocklen);
1460             if (!new && start && open_len)                       /* CDATA */
1461                 SET_ERROR_AND_RETURN(cur, XML_INVALID_COMMENT);
1462
1463             restlen -= new-cur;
1464             cur = new;
1465             continue;
1466         }
1467         else if (*cur == '?') /* info block */
1468         {
1469             new = __xmlInfoProcess(cur, restlen);
1470             if (!new)
1471                 SET_ERROR_AND_RETURN(cur, XML_INVALID_INFO_BLOCK);
1472
1473             restlen -= new-cur;
1474             cur = new;
1475             continue;
1476         }
1477
1478         /*
1479          * get element name and a pointer to after the opening tag
1480          */
1481         element = *name;
1482         elementlen = *rlen;
1483         len_remaining = restlen;
1484         rptr = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
1485         if (rptr)                       /* requested element was found */
1486         {
1487             new = rptr;
1488             return_len = elementlen;
1489             if (found == num)
1490             {
1491                 ret = new;
1492                 open_len = elementlen;
1493                 start_tag = element;
1494             }
1495             else start_tag = 0;
1496         }
1497         else                            /* different element name was foud */
1498         {
1499             new = cur + (len_remaining - restlen);
1500             if (new >= ne)
1501                 SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
1502
1503             element = *name;
1504         }
1505
1506 #ifdef XML_USE_NODECACHE
1507         nnc = cacheNodeNew(nc);
1508 #endif
1509
1510         if (*(new-2) == '/')                            /* e.g. <test/> */
1511         {
1512             cur = new;
1513             if (rptr)
1514             {
1515 #ifdef XML_USE_NODECACHE
1516                 cacheDataSet(nnc, element, elementlen, rptr, 0);
1517 #endif
1518                 if (found == num)
1519                 {
1520                     open_element = start_tag;
1521                     *len = 0;
1522                 }
1523                 found++;
1524             }
1525             continue;
1526         }
1527
1528         /*
1529          * get the next xml tag
1530          */
1531         /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
1532         cur = new;
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         if (*cur == '!')                                /* comment, CDATA */
1541         {
1542             char *start = cur;
1543             size_t blocklen = restlen;
1544             new = __xmlProcessCDATA(&start, &blocklen);
1545             if (new && start && open_len)                       /* CDATA */
1546             {
1547                 cdata = ret;
1548             }
1549             else if (!new)
1550                 SET_ERROR_AND_RETURN(cur, XML_INVALID_COMMENT);
1551
1552             restlen -= new-cur;
1553             cur = new;
1554
1555             /*
1556              * look for the closing tag of the cascading block
1557              */
1558             new = memchr(cur, '<', restlen);
1559             if (!new)
1560                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1561
1562             new++;
1563             restlen -= new-cur;
1564             cur = new;
1565         }
1566
1567         if (*cur == '/')                /* closing tag of leaf node found */
1568         {
1569             if (!strncasecmp(new+1, element, elementlen))
1570             {
1571 #ifdef XML_USE_NODECACHE
1572                 cacheDataSet(nnc, element, elementlen, rptr, new-rptr-1);
1573 #endif
1574                 if (*(new+elementlen+1) != '>')
1575                     SET_ERROR_AND_RETURN(new+1, XML_ELEMENT_NO_CLOSING_TAG);
1576
1577                 if (found == num)
1578                 {
1579                     if (start_tag)
1580                     {
1581                         *len = new-ret-1;
1582                         open_element = start_tag;
1583                         cdata = (char *)start;
1584                         start_tag = 0;
1585                     }
1586                     else /* report error */
1587                         SET_ERROR_AND_RETURN(new, XML_ELEMENT_NO_OPENING_TAG);
1588                 }
1589                 found++;
1590             }
1591
1592             new = memchr(cur, '>', restlen);
1593             if (!new)
1594                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1595
1596             restlen -= new-cur;
1597             cur = new;
1598             continue;
1599         }
1600
1601         /* no leaf node, continue */
1602         if (*cur != '/')                        /* cascading tag found */
1603         {
1604             char *node = "*";
1605             size_t slen = restlen+1; /* due to cur-1 below*/
1606             size_t nlen = 1;
1607             size_t pos = -1;
1608
1609             /*
1610              * recursively walk the xml tree from here
1611              */
1612             new = __xmlNodeGet(nnc, cur-1, &slen, &node, &nlen, &pos);
1613             if (!new)
1614             {
1615                 if (nlen == 0)          /* error upstream */
1616                 {
1617                     *rlen = nlen;
1618                     *name = node;
1619                     *len = slen;
1620                     return 0;
1621                 }
1622
1623                 if (slen == restlen)
1624                     SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
1625
1626                 slen--;
1627                 new = cur + slen;
1628                 restlen -= slen;
1629             }
1630             else restlen -= slen;
1631
1632             /* 
1633              * look for the closing tag of the cascading block
1634              */
1635             cur = new;
1636             new = memchr(cur, '<', restlen);
1637             if (!new)
1638                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1639
1640             new++;
1641             restlen -= new-cur;
1642             cur = new;
1643         }
1644
1645         if (*cur == '/')                                /* closing tag found */
1646         {
1647             if (!strncasecmp(new+1, element, elementlen))
1648             {
1649                 if (*(new+elementlen+1) != '>')
1650                     SET_ERROR_AND_RETURN(new+1, XML_ELEMENT_NO_CLOSING_TAG);
1651
1652 #ifdef XML_USE_NODECACHE
1653                 cacheDataSet(nnc, element, elementlen, rptr, new-rptr-1);
1654 #endif
1655                 if (found == num)
1656                 {
1657                     if (start_tag)
1658                     {
1659                         *len = new-ret-1;
1660                         open_element = start_tag;
1661                         cdata = (char *)start;
1662                         start_tag = 0;
1663                     }
1664                     else /* report error */
1665                         SET_ERROR_AND_RETURN(new, XML_ELEMENT_NO_OPENING_TAG);
1666                 }
1667                 found++;
1668             }
1669
1670             new = memchr(cur, '>', restlen);
1671             if (!new)
1672                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1673
1674             restlen -= new-cur;
1675             cur = new;
1676         }
1677         else
1678             SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1679
1680     } /* while */
1681
1682     if (found == 0)
1683     {
1684         ret = 0;
1685         *rlen = 0;
1686         *name = start_tag;
1687         *len = XML_NO_ERROR;    /* element not found, no real error */
1688     }
1689     else
1690     {
1691         *rlen = open_len;
1692         *name = open_element;
1693         *nodenum = found;
1694     }
1695
1696     return ret;
1697 }
1698
1699 char *
1700 __xmlProcessCDATA(char **start, size_t *len)
1701 {
1702     char *cur, *new;
1703     size_t restlen = *len;
1704
1705     cur = *start;
1706     if ((restlen > 6) && (*(cur+1) == '-'))             /* comment */
1707     {
1708         new = __xmlCommentSkip(cur, restlen);
1709         if (new)
1710         {
1711             *start = new;
1712             *len = 0;
1713         }
1714         return new;
1715     }
1716
1717     if (restlen < 12) return 0;                         /* ![CDATA[ ]]> */
1718
1719     cur = *start;
1720     new = 0;
1721
1722     if (memcmp(cur, "![CDATA[", 8) == 0)
1723     {
1724         *start = cur+8;
1725         cur += 8;
1726         restlen -= 8;
1727         do
1728         {
1729             new = memchr(cur, ']', restlen);
1730             if (new)
1731             {
1732                 if ((restlen > 3) && (memcmp(new, "]]>", 3) == 0))
1733                 {
1734                     *len = new-1 - *start;
1735                     restlen -= 3;
1736                     new += 3;
1737                     break;
1738                 }
1739                 cur = new+1;
1740             }
1741             else
1742             {
1743                 *len = 0;
1744                 break;
1745             }
1746         }
1747         while (new && (restlen > 2));
1748     }
1749
1750     return new;
1751 }
1752
1753 char *
1754 __xmlCommentSkip(const char *start, size_t len)
1755 {
1756     char *cur, *new;
1757
1758     if (len < 7) return 0;                               /* !-- --> */
1759
1760     cur = (char *)start;
1761     new = 0;
1762
1763     if (memcmp(cur, "!--", 3) == 0)
1764     {
1765         cur += 3;
1766         len -= 3;
1767         do
1768         {
1769             new = memchr(cur, '-', len);
1770             if (new)
1771             {
1772                 len -= new-cur;
1773                 if ((len >= 3) && (memcmp(new, "-->", 3) == 0))
1774                 {
1775                     new += 3;
1776                     /* len -= 3; */
1777                     break;
1778                 }
1779                 cur = new+1;
1780                 len -= cur-new;
1781             }
1782             else break;
1783         }
1784         while (new && (len > 2));
1785     }
1786
1787     return new;
1788 }
1789
1790 char *
1791 __xmlInfoProcess(const char *start, size_t len)
1792 {
1793     char *cur, *new;
1794
1795     cur = (char *)start;
1796     new = 0;
1797
1798     if (*cur == '?')
1799     {
1800         if (len < 3) return 0;                          /* <? ?> */
1801
1802         cur++;
1803         len--;
1804         new = memchr(cur, '?', len);
1805         if (!new || *(new+1) != '>') return 0;
1806
1807         new += 2;
1808     }
1809
1810     return new;
1811 }
1812
1813
1814 static void
1815 __xmlPrepareData(char **start, size_t *blocklen)
1816 {
1817     size_t len = *blocklen;
1818     char *pe, *ps = *start;
1819
1820     if (len > 1)
1821     {
1822         pe = ps + len-1;
1823         while ((ps<pe) && isspace(*ps)) ps++;
1824         while ((pe>ps) && isspace(*pe)) pe--;
1825         len = (pe-ps)+1;
1826     }
1827     else if (isspace(*(ps+1))) len--;
1828
1829     /* CDATA or comment */
1830     if ((len >= 2) && !strncmp(ps, "<!", 2))
1831     {
1832         char *start = ps+1;
1833         size_t blocklen = len-1;
1834         if (blocklen >= 6)                  /* !-- --> */
1835         {
1836             char *new = __xmlProcessCDATA(&start, &len);
1837             if (new)
1838             {
1839                 ps = start;
1840                 pe = ps + len;
1841
1842                 while ((ps<pe) && isspace(*ps)) ps++;
1843                 while ((pe>ps) && isspace(*pe)) pe--;
1844                 len = (pe-ps);
1845             }
1846         }
1847     }
1848
1849     *start = ps;
1850     *blocklen = len;
1851 }
1852
1853 #define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
1854 void *
1855 __xml_memncasecmp(const char *haystack, size_t *haystacklen,
1856                   char **needle, size_t *needlelen)
1857 {
1858     char *rptr = 0;
1859
1860     if (haystack && needle && needlelen && (*needlelen > 0)
1861         && (*haystacklen >= *needlelen))
1862     {
1863         char *hs = (char *)haystack;
1864         char *ns;
1865         size_t i;
1866
1867         ns = *needle;
1868
1869         /* search for everything */
1870         if ((*ns == '*') && (*needlelen == 1))
1871         {
1872            char *he = hs + *haystacklen;
1873
1874            while ((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1875            if (*(hs-1) == '/') hs--;
1876
1877            *needle = (char *)haystack;
1878            *needlelen = hs - haystack;
1879
1880            ns = memchr(hs, '>', he-hs);
1881            if (ns) hs = ns+1;
1882            else hs = he;
1883      
1884            rptr = hs;
1885         }
1886         else
1887         {
1888             size_t nlen = *needlelen;
1889             char *he = hs + *haystacklen;
1890
1891             for (i=0; i<nlen; i++)
1892             {
1893                 if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
1894                 if (isspace(*hs) || (*hs == '/') || (*hs == '>')) break;
1895                 hs++;
1896                 ns++;
1897             }
1898
1899             if (i == nlen)
1900             {
1901                 *needle = (char *)haystack;
1902                 *needlelen = hs - haystack;
1903
1904                 ns = memchr(hs, '>', he-hs);
1905                 if (ns) hs = ns+1;
1906                 else hs = he;
1907
1908                 rptr = hs;
1909             }
1910             else /* not found */
1911             {
1912                 while((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1913                 if (*(hs-1) == '/') hs--;
1914
1915                 *needle = (char *)haystack;
1916                 *needlelen = hs - haystack;
1917
1918                 ns = memchr(hs, '>', he-hs);
1919                 if (ns) hs = ns+1;
1920                 else hs = he;
1921             }
1922         }
1923
1924         *haystacklen -= hs - haystack;
1925     }
1926
1927     return rptr;
1928 }
1929
1930 #ifndef XML_NONVALIDATING
1931 void
1932 __xmlErrorSet(const void *id, const char *pos, unsigned int err_no)
1933 {
1934    struct _xml_id *xid = (struct _xml_id *)id;
1935    struct _root_id *rid;
1936
1937    assert(xid != 0);
1938
1939    if (xid->name) rid = xid->root;
1940    else rid = (struct _root_id *)xid;
1941
1942    assert(rid != 0);
1943    if (rid->info == 0)
1944    {
1945       rid->info = malloc(sizeof(struct _xml_error));
1946    }
1947
1948    if (rid->info)
1949    {
1950       struct _xml_error *err = rid->info;
1951
1952       err->pos = (char *)pos;
1953       err->err_no = err_no;
1954    }
1955 }
1956 #endif
1957
1958 #ifdef WIN32
1959 /* Source:
1960  * https://mollyrocket.com/forums/viewtopic.php?p=2529
1961  */
1962
1963 void *
1964 simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
1965 {
1966     HANDLE f;
1967     HANDLE m;
1968     void *p;
1969
1970     f = (HANDLE)_get_osfhandle(fd);
1971     if (!f) return (void *)-1;
1972
1973     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
1974     if (!m) return (void *)-1;
1975
1976     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
1977     if (!p)
1978     {
1979         CloseHandle(m);
1980         return (void *)-1;
1981     }
1982
1983     if (un)
1984     {
1985         un->m = m;
1986         un->p = p;
1987     }
1988
1989     return p;
1990 }
1991
1992 void
1993 simple_unmmap(SIMPLE_UNMMAP *un)
1994 {
1995     UnmapViewOfFile(un->p);
1996     CloseHandle(un->m);
1997 }
1998 #endif