]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xml.c
* Setting an error when a node isn't found isn't he best way,
[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 <fcntl.h>
48 #include <stdlib.h>     /* free, malloc */
49 #include <string.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 = buflen-1;
310     if (slen > xid->name_len)
311     {
312         slen = xid->name_len;
313     }
314     else
315     {
316         xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
317     }
318     memcpy(buf, xid->name, slen);
319     *(buf + slen) = 0;
320
321     return slen;
322 }
323
324 unsigned int
325 xmlNodeGetNum(const void *id, const char *path)
326 {
327     struct _xml_id *xid = (struct _xml_id *)id;
328     size_t num = 0;
329
330     assert(xid != 0);
331     assert(path != 0);
332
333     if (xid->len)
334     {
335         char *nodename, *pathname;
336         size_t len, slen;
337         char *p;
338
339         nodename = (char *)path;
340         if (*path == '/') nodename++;
341         slen = strlen(nodename);
342
343         pathname = strchr(nodename, '/');
344         if (pathname)
345         {
346            char *node;
347
348            len = xid->len;
349            pathname++;
350            slen -= pathname-nodename;
351            node = pathname;
352            p = __xmlNodeGetPath(xid->start, &len, &node, &slen);
353            if (p == 0 && slen == 0)
354            {
355                xmlErrorSet(xid, node, len);
356            }
357         }
358         else
359         {
360             p = xid->start;
361             len = xid->len;
362         }
363
364         if (p)
365         {
366             char *ret, *node = nodename;
367
368             ret = __xmlNodeGet(p, &len, &node, &slen, &num);
369             if (ret == 0 && slen == 0)
370             {
371                 xmlErrorSet(xid, node, len);
372                 num = 0;
373             }
374         }
375     }
376
377     return num;
378 }
379
380 void *
381 xmlNodeGetPos(const void *pid, void *id, const char *element, size_t num)
382 {
383     struct _xml_id *xpid = (struct _xml_id *)pid;
384     struct _xml_id *xid = (struct _xml_id *)id;
385     size_t len, slen;
386     char *ptr, *node;
387     void *ret = 0;
388
389     assert(xpid != 0);
390     assert(xid != 0);
391     assert(element != 0);
392
393     len = xpid->len;
394     slen = strlen(element);
395     node = (char *)element;
396     ptr = __xmlNodeGet(xpid->start, &len, &node, &slen, &num);
397     if (ptr)
398     {
399          xid->len = len;
400          xid->start = ptr;
401          xid->name = node;
402          xid->name_len = slen;
403          ret = xid;
404     }
405     else if (slen == 0)
406     {
407         xmlErrorSet(xpid, node, len);
408     }
409
410     return ret;
411 }
412
413 char *
414 xmlGetString(const void *id)
415 {
416     struct _xml_id *xid = (struct _xml_id *)id;
417     char *str = 0;
418
419     assert(xid != 0);
420
421     if (xid->len)
422     {
423         char *ps, *pe, *pend;
424         int nlen;
425
426         ps = xid->start;
427         nlen = xid->len;
428         pend = ps+nlen;
429         pe = pend;
430
431         while ((ps<pe) && isspace(*ps)) ps++;
432         while ((pe>ps) && isspace(*pe)) pe--;
433         nlen = (pe-ps);
434         if (nlen)
435         {
436             str = malloc(nlen+1);
437             if (str)
438             {
439                 memcpy(str, ps, nlen);
440                 *(str+nlen) = 0;
441             }
442             else
443             {
444                 xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
445             }
446         }
447     }
448
449     return str;
450 }
451
452 size_t
453 xmlCopyString(const void *id, char *buffer, size_t buflen)
454 {
455     struct _xml_id *xid = (struct _xml_id *)id;
456     size_t ret = 0;
457  
458     assert(xid != 0);
459     assert(buffer != 0);
460     assert(buflen > 0);
461
462     if (xid->len)
463     {
464         char *ps, *pe, *pend;
465         size_t slen, nlen;
466
467         *buffer = '\0';
468         nlen = buflen-1;
469         ps = xid->start;
470         slen = xid->len;
471         pend = ps+slen;
472         pe = pend;
473
474         while ((ps<pe) && isspace(*ps)) ps++;
475         while ((pe>ps) && isspace(*pe)) pe--;
476         nlen = (pe-ps);
477         if (nlen > slen) nlen = slen;
478
479         if (nlen)
480         {
481             if (nlen >= buflen)
482             {
483                 nlen = buflen-1;
484                 xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
485             }
486             memcpy(buffer, ps, nlen);
487             *(buffer+nlen) = 0;
488             ret = nlen;
489         }
490     }
491
492     return ret;
493 }
494
495 int
496 xmlCompareString(const void *id, const char *s)
497 {
498     struct _xml_id *xid = (struct _xml_id *)id;
499     int ret = -1;
500
501     assert(xid != 0);
502     assert(s != 0);
503
504     if (xid->len && (strlen(s) > 0))
505     {
506         char *ps, *pe;
507
508         ps = xid->start;
509         pe = ps + xid->len;
510         pe--;
511
512         while ((ps<pe) && isspace(*ps)) ps++;
513         while ((pe>ps) && isspace(*pe)) pe--;
514         pe++;
515
516         ret = strncasecmp(ps, s, pe-ps);
517     }
518
519     return ret;
520 }
521
522 char *
523 xmlNodeGetString(const void *id, const char *path)
524 {
525     struct _xml_id *xid = (struct _xml_id *)id;
526     char *str = 0;
527
528     assert(xid != 0);
529     assert(path != 0);
530
531     if (xid->len)
532     {
533         size_t len = xid->len;
534         char *node = (char *)path;
535
536         str = __xmlNodeCopy(xid->start, &len, &path);
537         if (str)
538         {
539             char *ps, *pe, *pend;
540             int slen;
541
542             ps = str;
543             slen = strlen(str);
544             pend = ps+slen;
545             pe = pend-1;
546
547             while ((ps<pe) && isspace(*ps)) ps++;
548             while ((pe>ps) && isspace(*pe)) pe--;
549
550             *++pe = 0;
551             slen = (pe-ps);
552             if (slen && (ps>str)) memmove(str, ps, slen);
553             else if (!slen) *str = 0;
554         }
555         else
556         {
557             xmlErrorSet(xid, node, len);
558         }
559     }
560
561     return str;
562 }
563
564 size_t
565 xmlNodeCopyString(const void *id, const char *path, char *buffer, size_t buflen)
566 {
567     struct _xml_id *xid = (struct _xml_id *)id;
568     size_t ret = 0;
569
570     assert(xid != 0);
571     assert(path != 0);
572     assert(buffer != 0);
573     assert(buflen > 0);
574
575     if (xid->len)
576     {
577         char *str, *node;
578         size_t slen, nlen;
579
580         *buffer = '\0';
581         nlen = xid->len;
582         slen = strlen(path);
583         node = (char *)path;
584         str = __xmlNodeGetPath(xid->start, &nlen, &node, &slen);
585         if (str)
586         {
587             char *ps, *pe;
588
589             ps = str;
590             pe = ps+nlen-1;
591
592             while ((ps<pe) && isspace(*ps)) ps++;
593             while ((pe>ps) && isspace(*pe)) pe--;
594
595             nlen = (pe-ps)+1;
596             if (nlen >= buflen)
597             {
598                 nlen = buflen-1;
599                 xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
600             }
601
602             memcpy(buffer, ps, nlen);
603             *(buffer + nlen) = '\0';
604             ret = nlen;
605         }
606         else if (slen == 0)
607         {
608             xmlErrorSet(xid, node, nlen);
609         }
610     }
611
612     return ret;
613 }
614
615 int
616 xmlNodeCompareString(const void *id, const char *path, const char *s)
617 {
618     struct _xml_id *xid = (struct _xml_id *)id;
619     int ret = -1;
620
621     assert(xid != 0);
622     assert(path != 0);
623     assert(s != 0);
624
625     if (xid->len && (strlen(s) > 0))
626     {
627         char *node, *str, *ps, *pe;
628         size_t len, slen;
629
630         len = xid->len;
631         slen = strlen(path);
632         node = (char *)path;
633         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
634         if (str)
635         {
636             ps = str;
637             pe = ps + len;
638             pe--;
639
640             while ((ps<pe) && isspace(*ps)) ps++;
641             while ((pe>ps) && isspace(*pe)) pe--;
642             pe++;
643
644             ret = strncasecmp(ps, s, pe-ps);
645         }
646         else if (slen == 0)
647         {
648             xmlErrorSet(xid, node, len);
649         }
650     }
651
652     return ret;
653 }
654
655 long int
656 xmlGetInt(const void *id)
657 {
658     struct _xml_id *xid = (struct _xml_id *)id;
659     long int li = 0;
660
661     assert(xid != 0);
662
663     if (xid->len)
664     {
665         char *end = xid->start + xid->len;
666         li = strtol(xid->start, &end, 10);
667     }
668
669     return li;
670 }
671
672 long int
673 xmlNodeGetInt(const void *id, const char *path)
674 {
675     struct _xml_id *xid = (struct _xml_id *)id;
676     long int li = 0;
677
678     assert(xid != 0);
679     assert(path != 0);
680
681     if (xid->len)
682     {
683         size_t len, slen;
684         char *str, *node;
685
686         len = xid->len;
687         slen = strlen(path);
688         node = (char *)path;
689         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
690         if (str)
691         {
692             char *end = str+len;
693             li = strtol(str, &end, 10);
694         }
695         else if (slen == 0)
696         {
697             xmlErrorSet(xid, node, len);
698         }
699     }
700
701     return li;
702 }
703
704 double
705 xmlGetDouble(const void *id)
706 {
707     struct _xml_id *xid = (struct _xml_id *)id;
708     double d = 0.0;
709
710     assert(xid != 0);
711
712     if (xid->len)
713     {
714         char *end = xid->start + xid->len;
715         d = strtod(xid->start, &end);
716     }
717
718     return d;
719 }
720
721 double
722 xmlNodeGetDouble(const void *id, const char *path)
723 {
724     struct _xml_id *xid = (struct _xml_id *)id;
725     double d = 0.0;
726
727     assert(xid != 0);
728     assert(path != 0);
729
730     if (xid->len)
731     {
732         size_t len, slen;
733         char *str, *node;
734
735         len = xid->len;
736         slen = strlen(path);
737         node = (char *)path;
738         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
739         if (str)
740         {
741             char *end = str+len;
742             d = strtod(str, &end);
743         }
744         else if (slen == 0)
745         {
746             xmlErrorSet(xid, node, len);
747         }
748     }
749
750     return d;
751 }
752
753 void *
754 xmlMarkId(const void *id)
755 {
756     struct _xml_id *xmid = 0;
757
758     assert(id != 0);
759
760     xmid = malloc(sizeof(struct _xml_id));
761     if (xmid)
762     {
763         struct _root_id *xrid = (struct _root_id *)id;
764         if (xrid->name == 0)
765         {
766             xmid->name = "";
767             xmid->start = xrid->start;
768             xmid->len = xrid->len;
769             xmid->name_len = 0;
770 #ifndef XML_NONVALIDATING
771             xmid->root = xrid;
772 #endif
773         }
774         else
775         {
776             memcpy(xmid, id, sizeof(struct _xml_id));
777         }
778     }
779     else
780     {
781         xmlErrorSet(id, 0, XML_OUT_OF_MEMORY);
782     }
783
784     return (void *)xmid;
785 }
786
787 double
788 xmlAttributeGetDouble(const void *id, const char *name)
789 {
790     struct _xml_id *xid = (struct _xml_id *)id;
791     double ret = 0.0;
792
793     assert(xid != 0);
794     assert(name != 0);
795
796     if (xid->len && xid->name_len)
797     {
798         size_t slen = strlen(name);
799         char *ps, *pe;
800
801         assert(xid->start > xid->name);
802
803         ps = xid->name + xid->name_len + 1;
804         pe = xid->start - 1;
805         while (ps<pe)
806         {
807             while ((ps<pe) && isspace(*ps)) ps++;
808             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
809             {
810                 ps += slen;
811                 if ((ps<pe) && (*ps == '='))
812                 {
813                     char *start;
814
815                     ps++;
816                     if (*ps == '"' || *ps == '\'') ps++;
817                     else
818                     {
819                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
820                         return 0;
821                     }
822
823                     start = ps;
824                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
825                     if (ps<pe)
826                     {
827                         ret = strtod(start, &ps);
828                     }
829                     else
830                     {
831                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
832                         return 0;
833                     }
834                 }
835                 else
836                 {
837                     while ((ps<pe) && !isspace(*ps)) ps++;
838                     continue;
839                 }
840
841                 break;
842             }
843
844             while ((ps<pe) && !isspace(*ps)) ps++;
845         }
846     }
847
848     return ret;
849 }
850
851 long int
852 xmlAttributeGetInt(const void *id, const char *name)
853 {
854     struct _xml_id *xid = (struct _xml_id *)id;
855     long int ret = 0;
856
857     assert(xid != 0);
858     assert(name != 0);
859
860     if (xid->len && xid->name_len)
861     {
862         size_t slen = strlen(name);
863         char *ps, *pe;
864
865         assert(xid->start > xid->name);
866
867         ps = xid->name + xid->name_len + 1;
868         pe = xid->start - 1;
869         while (ps<pe)
870         {
871             while ((ps<pe) && isspace(*ps)) ps++;
872             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
873             {
874                 ps += slen;
875                 if ((ps<pe) && (*ps == '='))
876                 {
877                     char *start;
878
879                     ps++;
880                     if (*ps == '"' || *ps == '\'') ps++;
881                     else
882                     {
883                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
884                         return 0;
885                     }
886
887                     start = ps;
888                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
889                     if (ps<pe)
890                     {
891                         ret = strtol(start, &ps, 10);
892                     }
893                     else
894                     {
895                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
896                        return 0;
897                    }
898                }
899                else
900                {
901                    while ((ps<pe) && isspace(*ps)) ps++;
902                    continue;
903                }
904
905                break;
906            }
907
908            while ((ps<pe) && !isspace(*ps)) ps++;
909         }
910     }
911
912     return ret;
913 }
914
915 char *
916 xmlAttributeGetString(const void *id, const char *name)
917 {
918     struct _xml_id *xid = (struct _xml_id *)id;
919     char *ret = 0;
920
921     assert(xid != 0);
922     assert(name != 0);
923
924     if (xid->len && xid->name_len)
925     {
926         size_t slen = strlen(name);
927         char *ps, *pe;
928
929         assert(xid->start > xid->name);
930
931         ps = xid->name + xid->name_len + 1;
932         pe = xid->start - 1;
933         while (ps<pe)
934         {
935              while ((ps<pe) && isspace(*ps)) ps++;
936              if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
937              {
938                  ps += slen;
939                  if ((ps<pe) && (*ps == '='))
940                  {
941                      char *start;
942
943                      ps++;
944                      if (*ps == '"' || *ps == '\'') ps++;
945                      else
946                      {
947                          xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
948                          return 0;
949                      }
950
951                      start = ps;
952                      while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
953                      if (ps<pe)
954                      {
955                          ret = malloc(ps-start);
956                          if (ret)
957                          {
958                              memcpy(ret, start, (ps-start));
959                              *(ret+(ps-start)) = '\0';
960                          }
961                          else
962                          {
963                              xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
964                          }
965                      }
966                      else
967                      {
968                          xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
969                         return 0;
970                      }
971                  }
972                  else
973                  {
974                      while ((ps<pe) && !isspace(*ps)) ps++;
975                      continue;
976                  }
977
978
979                  break;
980              }
981
982              while ((ps<pe) && !isspace(*ps)) ps++;
983         }
984     }
985
986     return ret;
987 }
988
989 size_t
990 xmlAttributeCopyString(const void *id, const char *name,
991                                        char *buffer, size_t buflen)
992 {
993     struct _xml_id *xid = (struct _xml_id *)id;
994     size_t ret = 0;
995
996     assert(xid != 0);
997     assert(name != 0);
998     assert(buffer != 0);
999     assert(buflen > 0);
1000
1001     if (xid->len && xid->name_len)
1002     {
1003         size_t slen = strlen(name);
1004         char *ps, *pe;
1005
1006         assert(xid->start > xid->name);
1007
1008         *buffer = '\0';
1009         ps = xid->name + xid->name_len + 1;
1010         pe = xid->start - 1;
1011         while (ps<pe)
1012         {
1013             while ((ps<pe) && isspace(*ps)) ps++;
1014             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
1015             {
1016                 ps += slen;
1017                 if ((ps<pe) && (*ps == '='))
1018                 {
1019                     char *start;
1020
1021                     ps++;
1022                     if (*ps == '"' || *ps == '\'') ps++;
1023                     else
1024                     {
1025                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
1026                         return 0;
1027                     }
1028
1029                     start = ps;
1030                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
1031                     if (ps<pe)
1032                     {
1033                         size_t restlen = ps-start;
1034                         if (restlen >= buflen)
1035                         {
1036                             restlen = buflen-1;
1037                             xmlErrorSet(xid, ps, XML_TRUNCATE_RESULT);
1038                         }
1039
1040                         memcpy(buffer, start, restlen);
1041                         *(buffer+restlen) = 0;
1042                         ret = restlen;
1043                     }
1044                     else
1045                     {
1046                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
1047                         return 0;
1048                     }
1049                 }
1050                 else
1051                 {
1052                     while ((ps<pe) && isspace(*ps)) ps++;
1053                     continue;
1054                 }
1055
1056                 break;
1057             }
1058
1059             while ((ps<pe) && !isspace(*ps)) ps++;
1060         }
1061     }
1062
1063     return ret;
1064 }
1065
1066 int
1067 xmlAttributeCompareString(const void *id, const char *name, const char *s)
1068 {
1069     struct _xml_id *xid = (struct _xml_id *)id;
1070     int ret = -1;
1071  
1072     assert(xid != 0);
1073     assert(name != 0);
1074     assert(s != 0);
1075
1076     if (xid->len && xid->name_len && strlen(s))
1077     {
1078         size_t slen = strlen(name);
1079         char *ps, *pe;
1080
1081         assert(xid->start > xid->name);
1082
1083         ps = xid->name + xid->name_len + 1;
1084         pe = xid->start - 1;
1085         while (ps<pe)
1086         {
1087             while ((ps<pe) && isspace(*ps)) ps++;
1088             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
1089             {
1090                 ps += slen;
1091                 if ((ps<pe) && (*ps == '='))
1092                 {
1093                     char *start;
1094
1095                     ps++;
1096                     if (*ps == '"' || *ps == '\'') ps++;
1097                     else
1098                     {
1099                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
1100                         return 0;
1101                     }
1102
1103                     start = ps;
1104                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
1105                     if (ps<pe)
1106                     {
1107                         ret = strncasecmp(start, s, ps-start);
1108                     }
1109                     else
1110                     {
1111                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
1112                         return 0;
1113                     }
1114                 }
1115                 else
1116                 {
1117                     while ((ps<pe) && !isspace(*ps)) ps++;
1118                     continue;
1119                 }
1120
1121                 break;
1122             }
1123
1124             while ((ps<pe) && !isspace(*ps)) ps++;
1125         }
1126     }
1127
1128     return ret;
1129 }
1130
1131
1132 #ifndef XML_NONVALIDATING
1133 int
1134 xmlErrorGetNo(const void *id, int clear)
1135 {
1136     int ret = 0;
1137
1138     if (id)
1139     {
1140         struct _xml_id *xid = (struct _xml_id *)id;
1141         struct _root_id *rid;
1142
1143         if (xid->name) rid = xid->root;
1144         else rid = (struct _root_id *)xid;
1145
1146         assert(rid != 0);
1147
1148         if (rid->info)
1149         {
1150             struct _xml_error *err = rid->info;
1151
1152             ret = err->err_no;
1153             if (clear) err->err_no = 0;
1154         }
1155     }
1156
1157     return ret;
1158 }
1159
1160 size_t
1161 xmlErrorGetLineNo(const void *id, int clear)
1162 {
1163     size_t ret = 0;
1164
1165     if (id)
1166     {
1167         struct _xml_id *xid = (struct _xml_id *)id;
1168         struct _root_id *rid;
1169
1170         if (xid->name) rid = xid->root;
1171         else rid = (struct _root_id *)xid;
1172
1173         assert(rid != 0);
1174
1175         if (rid->info)
1176         {
1177             struct _xml_error *err = rid->info;
1178             char *ps = rid->start;
1179             char *pe = err->pos;
1180             char *new;
1181
1182             ret++;
1183             while (ps<pe)
1184             {
1185                new = memchr(ps, '\n', pe-ps);
1186                if (new)
1187                {
1188                   ps = new;
1189                   ret++;
1190                }
1191                ps++;
1192             }       
1193
1194             if (clear) err->err_no = 0;
1195         }
1196     }
1197
1198     return ret;
1199 }
1200
1201 const char *
1202 xmlErrorGetString(const void *id, int clear)
1203 {
1204     char *ret = 0;
1205
1206     if (id)
1207     {
1208         struct _xml_id *xid = (struct _xml_id *)id;
1209         struct _root_id *rid;
1210
1211         if (xid->name) rid = xid->root;
1212         else rid = (struct _root_id *)xid;
1213
1214         assert(rid != 0);
1215
1216         if (rid->info)
1217         {
1218             struct _xml_error *err = rid->info;
1219             if (XML_NO_ERROR <= err->err_no && err->err_no < XML_MAX_ERROR)
1220             {
1221                ret = (char *)__xml_error_str[err->err_no];
1222             }
1223             else
1224             {
1225                ret = "incorrect error number.";
1226             }
1227
1228             if (clear) err->err_no = 0;
1229         }
1230     }
1231
1232     return ret;
1233 }
1234 #endif
1235
1236 /* -------------------------------------------------------------------------- */
1237
1238 #ifndef XML_NONVALIDATING
1239 static const char *__xml_error_str[XML_MAX_ERROR] =
1240 {
1241     "no error.",
1242     "unable to allocate enough memory.",
1243     "unable to open file for reading.",
1244     "buffer too small to hold all data, truncating.",
1245     "incorrect comment section.",
1246     "bad information block.",
1247     "unexpected end of section.",
1248     "incompatible opening tag for element.",
1249     "missing or invalid closing tag for element.",
1250     "missing or invalid opening quote for attribute.",
1251     "missing or invalid closing quote for attribute."
1252 };
1253 #endif
1254
1255 char *
1256 __xmlNodeCopy(const char *start, size_t *len, const char **path)
1257 {
1258     char *node, *p, *ret = 0;
1259     size_t rlen, slen;
1260
1261     rlen = *len;
1262     slen = strlen(*path);
1263     node = (char *)*path;
1264     p = __xmlNodeGetPath(start, &rlen, &node, &slen);
1265     if (p && rlen)
1266     {
1267         ret = malloc(rlen+1);
1268         if (ret)
1269         {
1270             memcpy(ret, p, rlen);
1271             *(ret+rlen+1) = '\0';
1272         }
1273         else
1274         {
1275             xmlErrorSet(0, 0, XML_OUT_OF_MEMORY);
1276         }
1277     }
1278     else if (slen == 0)
1279     {
1280         *path = node;
1281         *len = rlen;
1282     }
1283
1284     return ret;
1285 }
1286
1287 char *
1288 __xmlNodeGetPath(const char *start, size_t *len, char **name, size_t *plen)
1289 {
1290     char *node;
1291     char *ret = 0;
1292
1293     assert(start != 0);
1294     assert(len != 0);
1295     assert(name != 0);
1296     assert(*name != 0);
1297     assert(plen != 0);
1298     assert(*plen != 0);
1299
1300     if ((*len == 0) || (*plen == 0) || (*plen > *len))
1301         return 0;
1302
1303     node = *name;
1304     if (*node == '/') node++;
1305     if (*node != 0)
1306     {
1307         size_t plen, slen;
1308         char *path;
1309         size_t num;
1310
1311         slen = strlen(node);
1312         path = strchr(node, '/');
1313
1314         if (!path) plen = slen;
1315         else plen = path++ - node;
1316
1317         if (path)
1318         {
1319             num = 0;
1320             ret = __xmlNodeGet(start, len, &node, &plen, &num);
1321             if (ret)
1322             {
1323                 plen = slen - (path - *name);
1324                 ret = __xmlNodeGetPath(ret, len, &path, &plen);
1325                 *name = path;
1326             }
1327             else if (plen == 0)
1328             {
1329                *name = node;
1330             }
1331         }
1332     }
1333
1334     return ret;
1335 }
1336
1337 char *
1338 __xmlNodeGet(const char *start, size_t *len, char **name, size_t *rlen, size_t *nodenum)
1339 {
1340     char *new, *cur, *ne, *ret = 0;
1341     char *element, *start_tag=0;
1342     size_t restlen, elementlen;
1343     size_t retlen = 0;
1344     int found, num;
1345
1346     assert(start != 0);
1347     assert(len != 0);
1348     assert(*len != 0);
1349     assert(name != 0);
1350     assert(*name != 0);
1351     assert(rlen != 0);
1352     assert(*rlen != 0);
1353     assert(nodenum != 0);
1354
1355     if (*rlen > *len)
1356     {
1357         *rlen = 0;
1358         *name = start;
1359         *len = XML_UNEXPECTED_EOF;
1360         return 0;
1361     }
1362
1363     found = 0;
1364     num = *nodenum;
1365     restlen = *len;
1366     cur = (char *)start;
1367     ne = cur + restlen;
1368
1369     while ((new = memchr(cur, '<', restlen)) != 0)
1370     {
1371         if (*(new+1) == '/')            /* cascading closing tag found */
1372         {
1373             *len -= restlen;
1374              break;
1375         }
1376
1377         new++;
1378         restlen -= new-cur;
1379         cur = new;
1380
1381         if (*cur == '!')
1382         {
1383             new = __xmlCommentSkip(cur, restlen);
1384             if (!new)
1385             {
1386                 *rlen = 0;
1387                 *name = cur;
1388                 *len = XML_INVALID_COMMENT;
1389                 return 0;
1390             }
1391             restlen -= new-cur;
1392             cur = new;
1393             continue;
1394         }
1395         else if (*cur == '?')
1396         {
1397             new = __xmlInfoProcess(cur, restlen);
1398             if (!new)
1399             {
1400                 *rlen = 0;
1401                 *name = cur;
1402                 *len = XML_INVALID_INFO_BLOCK;
1403                 return 0;
1404             }
1405
1406             restlen -= new-cur;
1407             cur = new;
1408             continue;
1409         }
1410
1411         element = *name;
1412         elementlen = *rlen;
1413         new = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
1414         if (new)
1415         {
1416             retlen = elementlen;
1417             if (found == num)
1418             {
1419                 ret = new+1;
1420                 start_tag = element;
1421                 *rlen = elementlen;
1422             }
1423             else start_tag = 0;
1424         }
1425         else
1426         {
1427             new = cur+elementlen;
1428             if (new >= ne)
1429             {
1430                 *rlen = 0;
1431                 *name = cur;
1432                 *len = XML_UNEXPECTED_EOF;
1433                 return 0;
1434             }
1435             element = *name;
1436         }
1437
1438         if (*(new-1) == '/')                            /* e.g. <test/> */
1439         {
1440             if (found == num)
1441             {
1442                *len = 0;
1443                *name = start_tag;
1444             }
1445             found++;
1446
1447             if ((restlen < 1) || (*new != '>'))
1448             {
1449                 *rlen = 0;
1450                 *name = cur;
1451                 *len = XML_ELEMENT_NO_CLOSING_TAG;
1452                 return 0;
1453             }
1454
1455             restlen -= new+1-cur;
1456             cur = new+1;
1457             continue;
1458         }
1459
1460         /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
1461         cur = new;
1462         new = memchr(cur, '<', restlen);
1463         if (!new)
1464         {
1465             *rlen = 0;
1466             *name = cur;
1467             *len = XML_ELEMENT_NO_CLOSING_TAG;
1468             return 0;
1469         }       
1470
1471         restlen -= new-cur;
1472         cur = new;
1473         if (*(cur+1) != '/')                            /* new node found */
1474         {
1475             char *node = "*";
1476             size_t slen = restlen;
1477             size_t nlen = 1;
1478             size_t pos = -1;
1479
1480             new = __xmlNodeGet(cur, &slen, &node, &nlen, &pos);
1481             if (!new)
1482             {
1483                 if (slen == restlen)
1484                 {
1485                     *rlen = 0;
1486                     *name = cur;
1487                     *len = XML_UNEXPECTED_EOF;
1488                     return 0;
1489                 }
1490                 else new = cur + slen;
1491             }
1492
1493             restlen -= slen;
1494             cur = new;
1495
1496             new = memchr(cur, '<', restlen);
1497             if (!new)
1498             {
1499                 *rlen = 0;
1500                 *name = cur;
1501                 *len = XML_ELEMENT_NO_CLOSING_TAG;
1502                 return 0;
1503             }
1504
1505             restlen -= new-cur;
1506             cur = new;
1507         }
1508
1509         if (*(cur+1) == '/')                            /* closing tag found */
1510         {
1511             if (!strncasecmp(new+2, element, elementlen))
1512             {
1513                 if (found == num)
1514                 {
1515                    if (start_tag)
1516                    {
1517                        *len = new-ret;
1518                        *name = start_tag;
1519                    }
1520                    else /* report error */
1521                    {
1522                        *rlen = 0;
1523                        *name = new;
1524                        *len = XML_ELEMENT_NO_OPENING_TAG;
1525                        return 0;
1526                    }
1527                 }
1528                 found++;
1529             }
1530
1531             new = memchr(cur, '>', restlen);
1532             if (!new)
1533             {
1534                 *rlen = 0;
1535                 *name = cur;
1536                 *len = XML_ELEMENT_NO_CLOSING_TAG;
1537                 return 0;
1538             }
1539
1540             restlen -= new-cur;
1541             cur = new;
1542         }
1543         else
1544         {
1545             *rlen = 0;
1546             *name = cur;
1547             return 0;
1548         }
1549     }
1550
1551     if ((ret == 0) && (start_tag == 0) && (*rlen > 1))
1552     {
1553         ret = 0;
1554         *rlen = 0;
1555         *name = start_tag;
1556         *len = XML_NO_ERROR;    /* element not found */
1557     }
1558     else
1559     {
1560         *rlen = retlen;
1561         *nodenum = found;
1562     }
1563
1564     return ret;
1565 }
1566
1567 char *
1568 __xmlCommentSkip(const char *start, size_t len)
1569 {
1570     char *cur, *new;
1571
1572     cur = (char *)start;
1573     new = 0;
1574
1575     if (memcmp(cur, "!--", 3) == 0)
1576     {
1577         if (len < 6) return 0;                          /* <!-- --> */
1578
1579         cur += 3;
1580         len -= 3;
1581         do
1582         {
1583             new = memchr(cur, '-', len);
1584             if (new)
1585             {
1586                 len -= new - cur;
1587                 if ((len > 3) && (memcmp(new, "-->", 3) == 0))
1588                 {
1589                     new += 3;
1590                     len -= 3;
1591                     break;
1592                 }
1593                 cur = new+1;
1594             }
1595             else break;
1596         }
1597         while (new && (len > 2));
1598     }
1599
1600     return new;
1601 }
1602
1603 char *
1604 __xmlInfoProcess(const char *start, size_t len)
1605 {
1606     char *cur, *new;
1607
1608     cur = (char *)start;
1609     new = 0;
1610
1611     if (*cur == '?')
1612     {
1613         if (len < 3) return 0;                          /* <? ?> */
1614
1615         cur++;
1616         len--;
1617         new = memchr(cur, '?', len);
1618         if (!new || *(new+1) != '>') return 0;
1619
1620         new += 2;
1621     }
1622
1623     return new;
1624 }
1625
1626
1627 #define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
1628 void *
1629 __xml_memncasecmp(const char *haystack, size_t *haystacklen,
1630                   char **needle, size_t *needlelen)
1631 {
1632     void *rptr = 0;
1633
1634     if (haystack && needle && needlelen && (*needlelen > 0)
1635         && (*haystacklen >= *needlelen))
1636     {
1637         char *hs = (char *)haystack;
1638         char *ns;
1639         size_t i;
1640
1641         ns = *needle;
1642
1643         /* search for everything */
1644         if ((*ns == '*') && (*needlelen == 1))
1645         {
1646            char *he = hs + *haystacklen;
1647
1648            while ((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1649            *needle = (char *)haystack;
1650            *needlelen = hs - haystack;
1651            while ((hs < he) && (*hs != '>')) hs++;
1652            rptr = hs;
1653         }
1654         else
1655         {
1656             size_t nlen = *needlelen;
1657             char *he = hs + *haystacklen;
1658
1659             for (i=0; i<nlen; i++)
1660             {
1661                 if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
1662                 if (isspace(*hs) || (*hs == '>')) break;
1663                 hs++;
1664                 ns++;
1665             }
1666
1667             if (i != nlen)
1668             {
1669                 while((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1670                 *needle = (char *)haystack;
1671                 *needlelen = hs - haystack;
1672             }
1673             else
1674             {
1675                 int found = (isspace(*hs) || (*hs == '>'));
1676
1677                 *needle = (char *)haystack;
1678                 *needlelen = hs - haystack;
1679
1680                 while ((hs < he) && (*hs != '>')) hs++;
1681
1682                 if (!found) *needlelen = hs - haystack;
1683                 else rptr = hs;
1684             }
1685         }
1686
1687         *haystacklen -= hs - haystack;
1688     }
1689
1690     return rptr;
1691 }
1692
1693 #ifndef XML_NONVALIDATING
1694 void
1695 __xmlErrorSet(const void *id, const char *pos, unsigned int err_no)
1696 {
1697    struct _xml_id *xid = (struct _xml_id *)id;
1698    struct _root_id *rid;
1699
1700    assert(xid != 0);
1701
1702    if (xid->name) rid = xid->root;
1703    else rid = (struct _root_id *)xid;
1704
1705    assert(rid != 0);
1706    if (rid->info == 0)
1707    {
1708       rid->info = malloc(sizeof(struct _xml_error));
1709    }
1710
1711    if (rid->info)
1712    {
1713       struct _xml_error *err = rid->info;
1714
1715       err->pos = (char *)pos;
1716       err->err_no = err_no;
1717    }
1718 }
1719 #endif
1720
1721 #ifdef WIN32
1722 /* Source:
1723  * https://mollyrocket.com/forums/viewtopic.php?p=2529
1724  */
1725
1726 void *
1727 simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
1728 {
1729     HANDLE f;
1730     HANDLE m;
1731     void *p;
1732
1733     f = (HANDLE)_get_osfhandle(fd);
1734     if (!f) return NULL;
1735
1736     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
1737     if (!m) return NULL;
1738
1739     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
1740     if (!p)
1741     {
1742         CloseHandle(m);
1743         return NULL;
1744     }
1745
1746     if (un)
1747     {
1748         un->m = m;
1749         un->p = p;
1750     }
1751
1752     return p;
1753 }
1754
1755 void
1756 simple_unmmap(SIMPLE_UNMMAP *un)
1757 {
1758     UnmapViewOfFile(un->p);
1759     CloseHandle(un->m);
1760 }
1761 #endif