]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xml.c
* fix a problem where attributes or elements starting with the same letter
[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         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 us too small to hold the result, truncating.",
1242     "incorrect comment section.",
1243     "bad information block.",
1244     "unexpected end of xml section (maybe a missing end tag?)",
1245     "element not found.",
1246     "incompatible opening tag for element.",
1247     "missing or invalid closing tag for element.",
1248     "missing or invalid opening quote for attribute.",
1249     "missing or invalid closing quote for attribute."
1250 };
1251 #endif
1252
1253 char *
1254 __xmlNodeCopy(const char *start, size_t *len, const char **path)
1255 {
1256     char *node, *p, *ret = 0;
1257     size_t rlen, slen;
1258
1259     rlen = *len;
1260     slen = strlen(*path);
1261     node = (char *)*path;
1262     p = __xmlNodeGetPath(start, &rlen, &node, &slen);
1263     if (p && rlen)
1264     {
1265         ret = malloc(rlen+1);
1266         if (ret)
1267         {
1268             memcpy(ret, p, rlen);
1269             *(ret+rlen+1) = '\0';
1270         }
1271         else
1272         {
1273             xmlErrorSet(0, 0, XML_OUT_OF_MEMORY);
1274         }
1275     }
1276     else if (slen == 0)
1277     {
1278         *path = node;
1279         *len = rlen;
1280     }
1281
1282     return ret;
1283 }
1284
1285 char *
1286 __xmlNodeGetPath(const char *start, size_t *len, char **name, size_t *plen)
1287 {
1288     char *node;
1289     char *ret = 0;
1290
1291     assert(start != 0);
1292     assert(len != 0);
1293     assert(name != 0);
1294     assert(*name != 0);
1295     assert(plen != 0);
1296     assert(*plen != 0);
1297
1298     if ((*len == 0) || (*plen == 0) || (*plen > *len))
1299         return 0;
1300
1301     node = *name;
1302     if (*node == '/') node++;
1303     if (*node != 0)
1304     {
1305         size_t plen, slen;
1306         char *path;
1307         size_t num;
1308
1309         slen = strlen(node);
1310         path = strchr(node, '/');
1311
1312         if (!path) plen = slen;
1313         else plen = path++ - node;
1314
1315         if (path)
1316         {
1317             num = 0;
1318             ret = __xmlNodeGet(start, len, &node, &plen, &num);
1319             if (ret)
1320             {
1321                 plen = slen - (path - *name);
1322                 ret = __xmlNodeGetPath(ret, len, &path, &plen);
1323                 *name = path;
1324             }
1325             else if (plen == 0)
1326             {
1327                *name = node;
1328             }
1329         }
1330     }
1331
1332     return ret;
1333 }
1334
1335 char *
1336 __xmlNodeGet(const char *start, size_t *len, char **name, size_t *rlen, size_t *nodenum)
1337 {
1338     char *new, *cur, *ne, *ret = 0;
1339     char *element, *start_tag=0;
1340     size_t restlen, elementlen;
1341     size_t retlen = 0;
1342     int found, num;
1343
1344     assert(start != 0);
1345     assert(len != 0);
1346     assert(*len != 0);
1347     assert(name != 0);
1348     assert(*name != 0);
1349     assert(rlen != 0);
1350     assert(*rlen != 0);
1351     assert(nodenum != 0);
1352
1353     if (*rlen > *len)
1354     {
1355         *rlen = 0;
1356         *name = start;
1357         *len = XML_UNEXPECTED_EOF;
1358         return 0;
1359     }
1360
1361     found = 0;
1362     num = *nodenum;
1363     restlen = *len;
1364     cur = (char *)start;
1365     ne = cur + restlen;
1366
1367     while ((new = memchr(cur, '<', restlen)) != 0)
1368     {
1369         if (*(new+1) == '/')            /* cascading closing tag found */
1370         {
1371             *len -= restlen;
1372              break;
1373         }
1374
1375         new++;
1376         restlen -= new-cur;
1377         cur = new;
1378
1379         if (*cur == '!')
1380         {
1381             new = __xmlCommentSkip(cur, restlen);
1382             if (!new)
1383             {
1384                 *rlen = 0;
1385                 *name = cur;
1386                 *len = XML_INVALID_COMMENT;
1387                 return 0;
1388             }
1389             restlen -= new-cur;
1390             cur = new;
1391             continue;
1392         }
1393         else if (*cur == '?')
1394         {
1395             new = __xmlInfoProcess(cur, restlen);
1396             if (!new)
1397             {
1398                 *rlen = 0;
1399                 *name = cur;
1400                 *len = XML_INVALID_INFO_BLOCK;
1401                 return 0;
1402             }
1403
1404             restlen -= new-cur;
1405             cur = new;
1406             continue;
1407         }
1408
1409         element = *name;
1410         elementlen = *rlen;
1411         new = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
1412         if (new)
1413         {
1414             retlen = elementlen;
1415             if (found == num)
1416             {
1417                 ret = new+1;
1418                 start_tag = element;
1419                 *rlen = elementlen;
1420             }
1421             else start_tag = 0;
1422         }
1423         else
1424         {
1425             new = cur+elementlen;
1426             if (new >= ne)
1427             {
1428                 *rlen = 0;
1429                 *name = cur;
1430                 *len = XML_UNEXPECTED_EOF;
1431                 return 0;
1432             }
1433             element = *name;
1434         }
1435
1436         if (*(new-1) == '/')                            /* e.g. <test/> */
1437         {
1438             if (found == num)
1439             {
1440                *len = 0;
1441                *name = start_tag;
1442             }
1443             found++;
1444
1445             if ((restlen < 1) || (*new != '>'))
1446             {
1447                 *rlen = 0;
1448                 *name = cur;
1449                 *len = XML_ELEMENT_NO_CLOSING_TAG;
1450                 return 0;
1451             }
1452
1453             restlen -= new+1-cur;
1454             cur = new+1;
1455             continue;
1456         }
1457
1458         /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
1459         cur = new;
1460         new = memchr(cur, '<', restlen);
1461         if (!new)
1462         {
1463             *rlen = 0;
1464             *name = cur;
1465             *len = XML_ELEMENT_NO_CLOSING_TAG;
1466             return 0;
1467         }       
1468
1469         restlen -= new-cur;
1470         cur = new;
1471         if (*(cur+1) != '/')                            /* new node found */
1472         {
1473             char *node = "*";
1474             size_t slen = restlen;
1475             size_t nlen = 1;
1476             size_t pos = -1;
1477
1478             new = __xmlNodeGet(cur, &slen, &node, &nlen, &pos);
1479             if (!new)
1480             {
1481                 if (slen == restlen)
1482                 {
1483                     *rlen = 0;
1484                     *name = cur;
1485                     *len = XML_UNEXPECTED_EOF;
1486                     return 0;
1487                 }
1488                 else new = cur + slen;
1489             }
1490
1491             restlen -= slen;
1492             cur = new;
1493
1494             new = memchr(cur, '<', restlen);
1495             if (!new)
1496             {
1497                 *rlen = 0;
1498                 *name = cur;
1499                 *len = XML_ELEMENT_NO_CLOSING_TAG;
1500                 return 0;
1501             }
1502
1503             restlen -= new-cur;
1504             cur = new;
1505         }
1506
1507         if (*(cur+1) == '/')                            /* closing tag found */
1508         {
1509             if (!strncasecmp(new+2, element, elementlen))
1510             {
1511                 if (found == num)
1512                 {
1513                    if (start_tag)
1514                    {
1515                        *len = new-ret;
1516                        *name = start_tag;
1517                    }
1518                    else /* report error */
1519                    {
1520                        *rlen = 0;
1521                        *name = new;
1522                        *len = XML_ELEMENT_NO_OPENING_TAG;
1523                        return 0;
1524                    }
1525                 }
1526                 found++;
1527             }
1528
1529             new = memchr(cur, '>', restlen);
1530             if (!new)
1531             {
1532                 *rlen = 0;
1533                 *name = cur;
1534                 *len = XML_ELEMENT_NO_CLOSING_TAG;
1535                 return 0;
1536             }
1537
1538             restlen -= new-cur;
1539             cur = new;
1540         }
1541         else
1542         {
1543             *rlen = 0;
1544             *name = cur;
1545             return 0;
1546         }
1547     }
1548
1549     if ((ret == 0) && (start_tag == 0) && (*rlen > 1))
1550     {
1551         ret = 0;
1552         *rlen = 0;
1553         *name = start_tag;
1554         *len = XML_ELEMENT_NOT_FOUND;
1555     }
1556     else
1557     {
1558         *rlen = retlen;
1559         *nodenum = found;
1560     }
1561
1562     return ret;
1563 }
1564
1565 char *
1566 __xmlCommentSkip(const char *start, size_t len)
1567 {
1568     char *cur, *new;
1569
1570     cur = (char *)start;
1571     new = 0;
1572
1573     if (memcmp(cur, "!--", 3) == 0)
1574     {
1575         if (len < 6) return 0;                          /* <!-- --> */
1576
1577         cur += 3;
1578         len -= 3;
1579         do
1580         {
1581             new = memchr(cur, '-', len);
1582             if (new)
1583             {
1584                 len -= new - cur;
1585                 if ((len > 3) && (memcmp(new, "-->", 3) == 0))
1586                 {
1587                     new += 3;
1588                     len -= 3;
1589                     break;
1590                 }
1591                 cur = new+1;
1592             }
1593             else break;
1594         }
1595         while (new && (len > 2));
1596     }
1597
1598     return new;
1599 }
1600
1601 char *
1602 __xmlInfoProcess(const char *start, size_t len)
1603 {
1604     char *cur, *new;
1605
1606     cur = (char *)start;
1607     new = 0;
1608
1609     if (*cur == '?')
1610     {
1611         if (len < 3) return 0;                          /* <? ?> */
1612
1613         cur++;
1614         len--;
1615         new = memchr(cur, '?', len);
1616         if (!new || *(new+1) != '>') return 0;
1617
1618         new += 2;
1619     }
1620
1621     return new;
1622 }
1623
1624
1625 #define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
1626 void *
1627 __xml_memncasecmp(const char *haystack, size_t *haystacklen,
1628                   char **needle, size_t *needlelen)
1629 {
1630     void *rptr = 0;
1631
1632     if (haystack && needle && needlelen && (*needlelen > 0)
1633         && (*haystacklen >= *needlelen))
1634     {
1635         char *hs = (char *)haystack;
1636         char *ns;
1637         size_t i;
1638
1639         ns = *needle;
1640
1641         /* search for everything */
1642         if ((*ns == '*') && (*needlelen == 1))
1643         {
1644            char *he = hs + *haystacklen;
1645
1646            while ((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1647            *needle = (char *)haystack;
1648            *needlelen = hs - haystack;
1649            while ((hs < he) && (*hs != '>')) hs++;
1650            rptr = hs;
1651         }
1652         else
1653         {
1654             size_t nlen = *needlelen;
1655             char *he = hs + *haystacklen;
1656
1657             for (i=0; i<nlen; i++)
1658             {
1659                 if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
1660                 if (isspace(*hs) || (*hs == '>')) break;
1661                 hs++;
1662                 ns++;
1663             }
1664
1665             if (i != nlen)
1666             {
1667                 while((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1668                 *needle = (char *)haystack;
1669                 *needlelen = hs - haystack;
1670             }
1671             else
1672             {
1673                 int found = (isspace(*hs) || (*hs == '>'));
1674
1675                 *needle = (char *)haystack;
1676                 *needlelen = hs - haystack;
1677
1678                 while ((hs < he) && (*hs != '>')) hs++;
1679
1680                 if (!found) *needlelen = hs - haystack;
1681                 else rptr = hs;
1682             }
1683         }
1684
1685         *haystacklen -= hs - haystack;
1686     }
1687
1688     return rptr;
1689 }
1690
1691 #ifndef XML_NONVALIDATING
1692 void
1693 __xmlErrorSet(const void *id, const char *pos, unsigned int err_no)
1694 {
1695    struct _xml_id *xid = (struct _xml_id *)id;
1696    struct _root_id *rid;
1697
1698    assert(xid != 0);
1699
1700    if (xid->name) rid = xid->root;
1701    else rid = (struct _root_id *)xid;
1702
1703    assert(rid != 0);
1704    if (rid->info == 0)
1705    {
1706       rid->info = malloc(sizeof(struct _xml_error));
1707    }
1708
1709    if (rid->info)
1710    {
1711       struct _xml_error *err = rid->info;
1712
1713       err->pos = (char *)pos;
1714       err->err_no = err_no;
1715    }
1716 }
1717 #endif
1718
1719 #ifdef WIN32
1720 /* Source:
1721  * https://mollyrocket.com/forums/viewtopic.php?p=2529
1722  */
1723
1724 void *
1725 simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
1726 {
1727     HANDLE f;
1728     HANDLE m;
1729     void *p;
1730
1731     f = (HANDLE)_get_osfhandle(fd);
1732     if (!f) return NULL;
1733
1734     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
1735     if (!m) return NULL;
1736
1737     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
1738     if (!p)
1739     {
1740         CloseHandle(m);
1741         return NULL;
1742     }
1743
1744     if (un)
1745     {
1746         un->m = m;
1747         un->p = p;
1748     }
1749
1750     return p;
1751 }
1752
1753 void
1754 simple_unmmap(SIMPLE_UNMMAP *un)
1755 {
1756     UnmapViewOfFile(un->p);
1757     CloseHandle(un->m);
1758 }
1759 #endif