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