]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xml.c
Compile xmlgrep with MSVC 7.1
[flightgear.git] / utils / xmlgrep / xml.c
1 /* Copyright (c) 2007, 2008 by Adalin B.V.
2  * Copyright (c) 2007, 2008 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
32 typedef struct
33 {
34    HANDLE m;
35    void *p;
36 } SIMPLE_UNMMAP;
37
38 static SIMPLE_UNMMAP un;
39
40 /*
41  * map 'filename' and return a pointer to it.
42  */
43 static void *simple_mmap(int, size_t, SIMPLE_UNMMAP *);
44 static void simple_unmmap(SIMPLE_UNMMAP *);
45
46 # define mmap(a,b,c,d,e,f)      simple_mmap((e), (b), &un)
47 # define munmap(a,b)            simple_unmmap(&un)
48
49 # include <io.h>
50 # include <stdlib.h>
51
52 #else   /* !WIN32 */
53 # include <sys/mman.h>
54 # include <unistd.h>
55 #endif
56
57 # include <fcntl.h>
58 #include <sys/stat.h>
59 #include <sys/types.h>
60 #include <assert.h>
61 #include <ctype.h>
62 #include <string.h>
63 #ifndef _MSC_VER
64 # include <strings.h>   /* strncasecmp */
65 #else
66 # define strncasecmp strnicmp
67 #endif
68 #ifndef NDEBUG
69 #include <stdio.h>
70 #endif
71
72
73 struct _xml_id
74 {
75     size_t len;
76     char *start;
77     char *name;
78     union {
79        size_t name_len;
80        int fd;
81     } node;
82 };
83
84 static char *__xmlNodeCopy(const char *, size_t, const char *);
85 static char *__xmlNodeGetPath(const char *, size_t *, char **, size_t *);
86 static char *__xmlNodeGet(const char *, size_t *, char **, size_t *, size_t *);
87 static char *__xmlCommentSkip(const char *, size_t);
88 static char *__xmlInfoSkip(const char *, size_t);
89
90 static void *__xml_memncasecmp(const char *, size_t *, char **, size_t *);
91
92 #define PRINT(a, b, c) { \
93    if (a) { \
94       size_t q, len = c; \
95       if (b < c) len = b; \
96       if (len < 50000) { \
97          printf("(%i) '", len); \
98          for (q=0; q<len; q++) printf("%c", ((char *)(a))[q]); \
99          printf("'\n"); \
100       } else printf("Length (%u) seems too large at line %i\n",len, __LINE__); \
101    } else printf("NULL pointer at line %i\n", __LINE__); \
102 }
103
104 void *
105 xmlOpen(const char *filename)
106 {
107     struct _xml_id *id = 0;
108
109     if (filename)
110     {
111         int fd = open(filename, O_RDONLY);
112         if (fd > 0)
113         {
114             id = malloc(sizeof(struct _xml_id));
115             if (id)
116             {
117                 struct stat statbuf;
118
119                 fstat(fd, &statbuf);
120
121                 id->node.fd = fd;
122                 id->len = statbuf.st_size;
123                 id->start = mmap(0, id->len, PROT_READ, MAP_PRIVATE, fd, 0L);
124                 id->name = 0;
125             }
126         }
127     }
128
129     return (void *)id;
130 }
131
132 void
133 xmlClose(void *id)
134 {
135     if (id)
136     {
137         struct _xml_id *xid = (struct _xml_id *)id;
138         assert(xid->name == 0);
139
140         munmap(xid->start, xid->len);
141         close(xid->node.fd);
142         free(id);
143         id = 0;
144     }
145 }
146
147 void *
148 xmlNodeGet(const void *id, const char *path)
149 {
150    struct _xml_id *xsid = 0;
151
152    if (id && path)
153    {
154       struct _xml_id *xid = (struct _xml_id *)id;
155       size_t len, slen;
156       char *ptr, *node;
157
158       node = (char *)path;
159       len = xid->len;
160       slen = strlen(path);
161       ptr = __xmlNodeGetPath(xid->start, &len, &node, &slen);
162       if (ptr)
163       {
164          xsid = malloc(sizeof(struct _xml_id));
165          if (xsid)
166          {
167              xsid->len = len;
168              xsid->start = ptr;
169              xsid->node.name_len = slen;
170              xsid->name = node;
171          }
172       }
173    }
174
175    return (void *)xsid;
176 }
177
178 void *
179 xmlNodeCopy(const void *id, const char *path)
180 {
181     struct _xml_id *xsid = 0;
182
183     if (id && path)
184     {
185         struct _xml_id *xid = (struct _xml_id *)id;
186         char *ptr, *node, *p;
187         size_t slen, len;
188
189         node = (char *)path;
190         len = xid->len;
191         slen = strlen(path);
192         ptr = __xmlNodeGetPath(xid->start, &len, &node, &slen);
193         if (ptr)
194         {
195             xsid = malloc(sizeof(struct _xml_id) + len);
196             if (xsid)
197             {
198                 p = (char *)xsid + sizeof(struct _xml_id);
199
200                 xsid->len = len;
201                 xsid->start = p;
202                 xsid->node.name_len = slen;
203                 xsid->name = node;
204
205                 memcpy(xsid->start, ptr, len);
206            }
207        }
208    }
209
210    return (void *)xsid;
211 }
212
213 char *
214 xmlNodeGetName(const void *id)
215 {
216     struct _xml_id *xid = (struct _xml_id *)id;
217     size_t len;
218     char *ret;
219
220     len = xid->node.name_len;
221     ret = malloc(len+1);
222     if (ret)
223     {
224         memcpy(ret, xid->name, len);
225         *(ret + len) = 0;
226     }
227
228     return ret;
229 }
230
231 size_t
232 xmlNodeCopyName(const void *id, char *buf, size_t len)
233 {
234     struct _xml_id *xid = (struct _xml_id *)id;
235     size_t slen = 0;
236  
237     if (buf)
238     {
239         slen = len-1;
240         if (slen > xid->node.name_len) slen = xid->node.name_len;
241         memcpy(buf, xid->name, slen);
242         *(buf + slen) = 0;
243     }
244
245     return slen;
246 }
247
248 unsigned int
249 xmlNodeGetNum(const void *id, const char *path)
250 {
251     struct _xml_id *xid = (struct _xml_id *)id;
252     size_t num = 0;
253
254     if (xid && xid->len && path)
255     {
256         char *nodename, *pathname;
257         size_t len, slen;
258         char *p;
259
260         nodename = (char *)path;
261         if (*path == '/') nodename++;
262         slen = strlen(nodename);
263
264         pathname = strchr(nodename, '/');
265         if (pathname)
266         {
267            char *node;
268
269            len = xid->len;
270            pathname++;
271            slen -= pathname-nodename;
272            node = pathname;
273            p = __xmlNodeGetPath(xid->start, &len, &node, &slen);
274         }
275         else
276         {
277             p = xid->start;
278             len = xid->len;
279         }
280
281         if (p)
282         {
283             char *node = nodename;
284             __xmlNodeGet(p, &len, &node, &slen, &num);
285         }
286     }
287
288     return num;
289 }
290
291 void *
292 xmlNodeGetPos(const void *pid, void *id, const char *element, size_t num)
293 {
294     void *ret = 0;
295
296     if (pid && element)
297     {
298         struct _xml_id *xpid = (struct _xml_id *)pid;
299         struct _xml_id *xid = (struct _xml_id *)id;
300         size_t len, slen;
301         char *ptr, *node;
302
303         len = xpid->len;
304         slen = strlen(element);
305         node = (char *)element;
306         ptr = __xmlNodeGet(xpid->start, &len, &node, &slen, &num);
307         if (ptr)
308         {
309              xid->len = len;
310              xid->start = ptr;
311              xid->name = node;
312              xid->node.name_len = slen;
313              ret = xid;
314         }
315     }
316
317     return ret;
318 }
319
320 char *
321 xmlGetString(const void *id)
322 {
323     struct _xml_id *xid = (struct _xml_id *)id;
324     char *str = 0;
325
326     if (xid && xid->len)
327     {
328         char *ps, *pe, *pend;
329         int nlen;
330
331         ps = xid->start;
332         nlen = xid->len;
333         pend = ps+nlen;
334         pe = pend;
335
336         while ((ps<pe) && isspace(*ps)) ps++;
337         while ((pe>ps) && isspace(*pe)) pe--;
338         nlen = (pe-ps);
339         if (nlen)
340         {
341             str = malloc(nlen+1);
342             if (str)
343             {
344                 memcpy(str, ps, nlen);
345                 *(str+nlen) = 0;
346             }
347         }
348     }
349
350     return str;
351 }
352
353 size_t
354 xmlCopyString(const void *id, char *buffer, size_t buflen)
355 {
356     struct _xml_id *xid = (struct _xml_id *)id;
357     size_t ret = 0;
358
359     if (xid && xid->len && buffer && buflen)
360     {
361         char *ps, *pe, *pend;
362         size_t slen, nlen;
363
364         *buffer = '\0';
365         nlen = buflen-1;
366         ps = xid->start;
367         slen = xid->len;
368         pend = ps+slen;
369         pe = pend;
370
371         while ((ps<pe) && isspace(*ps)) ps++;
372         while ((pe>ps) && isspace(*pe)) pe--;
373         nlen = (pe-ps);
374         if (nlen > slen) nlen = slen;
375
376         if (nlen)
377         {
378             if (nlen >= buflen) nlen = buflen-1;
379             memcpy(buffer, ps, nlen);
380             *(buffer+nlen) = 0;
381             ret = nlen;
382         }
383     }
384
385     return ret;
386 }
387
388 int
389 xmlCompareString(const void *id, const char *s)
390 {
391     struct _xml_id *xid = (struct _xml_id *)id;
392     int ret = -1;
393
394     if (xid && xid->len && s && (strlen(s) > 0))
395     {
396         char *ps, *pe;
397
398         ps = xid->start;
399         pe = ps + xid->len;
400         pe--;
401
402         while ((ps<pe) && isspace(*ps)) ps++;
403         while ((pe>ps) && isspace(*pe)) pe--;
404         pe++;
405
406         ret = strncasecmp(ps, s, pe-ps);
407     }
408
409     return ret;
410 }
411
412 char *
413 xmlNodeGetString(const void *id, const char *path)
414 {
415     struct _xml_id *xid = (struct _xml_id *)id;
416     char *str = 0;
417
418     if (xid && xid->len && path)
419     {
420         str = __xmlNodeCopy(xid->start, xid->len, path);
421         if (str)
422         {
423             char *ps, *pe, *pend;
424             int slen;
425
426             ps = str;
427             slen = strlen(str);
428             pend = ps+slen;
429             pe = pend-1;
430
431             while ((ps<pe) && isspace(*ps)) ps++;
432             while ((pe>ps) && isspace(*pe)) pe--;
433
434             *++pe = 0;
435             slen = (pe-ps);
436             if (slen && (ps>str)) memmove(str, ps, slen);
437             else if (!slen) *str = 0;
438         }
439     }
440
441     return str;
442 }
443
444 size_t
445 xmlNodeCopyString(const void *id, const char *path, char *buffer, size_t buflen)
446 {
447     struct _xml_id *xid = (struct _xml_id *)id;
448     size_t ret = 0;
449
450     if (xid && xid->len && path && buffer && buflen)
451     {
452         char *str, *node;
453         size_t slen, nlen;
454
455         *buffer = '\0';
456         nlen = xid->len;
457         slen = strlen(path);
458         node = (char *)path;
459         str = __xmlNodeGetPath(xid->start, &nlen, &node, &slen);
460         if (str)
461         {
462             char *ps, *pe;
463
464             ps = str;
465             pe = ps+nlen-1;
466
467             while ((ps<pe) && isspace(*ps)) ps++;
468             while ((pe>ps) && isspace(*pe)) pe--;
469
470             nlen = (pe-ps)+1;
471             if (nlen >= buflen) nlen = buflen-1;
472
473             memcpy(buffer, ps, nlen);
474             *(buffer + nlen) = '\0';
475             ret = nlen;
476         }
477     }
478
479     return ret;
480 }
481
482 int
483 xmlNodeCompareString(const void *id, const char *path, const char *s)
484 {
485     struct _xml_id *xid = (struct _xml_id *)id;
486     int ret = -1;
487
488     if (xid && xid->len && path && s && (strlen(s) > 0))
489     {
490         char *node, *str, *ps, *pe;
491         size_t len, slen;
492
493         len = xid->len;
494         slen = strlen(path);
495         node = (char *)path;
496         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
497         if (str)
498         {
499             ps = str;
500             pe = ps + len;
501             pe--;
502
503             while ((ps<pe) && isspace(*ps)) ps++;
504             while ((pe>ps) && isspace(*pe)) pe--;
505             pe++;
506
507             ret = strncasecmp(ps, s, pe-ps);
508         }
509     }
510
511     return ret;
512 }
513
514 long int
515 xmlGetInt(const void *id)
516 {
517     struct _xml_id *xid = (struct _xml_id *)id;
518     long int li = 0;
519
520     if (xid && xid->len)
521     {
522         char *end = xid->start + xid->len;
523         li = strtol(xid->start, &end, 10);
524     }
525
526     return li;
527 }
528
529 long int
530 xmlNodeGetInt(const void *id, const char *path)
531 {
532     struct _xml_id *xid = (struct _xml_id *)id;
533     long int li = 0;
534
535     if (path && xid && xid->len)
536     {
537         size_t len, slen;
538         char *str, *node;
539
540         len = xid->len;
541         slen = strlen(path);
542         node = (char *)path;
543         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
544         if (str)
545         {
546             char *end = str+len;
547             li = strtol(str, &end, 10);
548         }
549     }
550
551     return li;
552 }
553
554 double
555 xmlGetDouble(const void *id)
556 {
557     struct _xml_id *xid = (struct _xml_id *)id;
558     double d = 0.0;
559
560     if (xid && xid->len)
561     {
562         char *end = xid->start + xid->len;
563         d = strtod(xid->start, &end);
564     }
565
566     return d;
567 }
568
569 double
570 xmlNodeGetDouble(const void *id, const char *path)
571 {
572     struct _xml_id *xid = (struct _xml_id *)id;
573     double d = 0.0;
574
575     if (path && xid && xid->len)
576     {
577         size_t len, slen;
578         char *str, *node;
579
580         len = xid->len;
581         slen = strlen(path);
582         node = (char *)path;
583         str = __xmlNodeGetPath(xid->start, &len, &node, &slen);
584         if (str)
585         {
586             char *end = str+len;
587             d = strtod(str, &end);
588         }
589     }
590
591     return d;
592 }
593
594 void *
595 xmlMarkId(const void *id)
596 {
597    struct _xml_id *xmid = 0;
598
599    if (id)
600    {
601       xmid = malloc(sizeof(struct _xml_id));
602       if (xmid)
603       {
604           memcpy(xmid, id, sizeof(struct _xml_id));
605       }
606    }
607
608    return (void *)xmid;
609 }
610
611 double
612 xmlAttributeGetDouble(const void *id, const char *name)
613 {
614    struct _xml_id *xid = (struct _xml_id *)id;
615    double ret = 0.0;
616
617    if (xid && xid->start && xid->len && xid->node.name_len)
618    {
619        char *p, *end, *new = 0;
620
621        assert(xid->start > xid->name);
622
623        p = xid->name + xid->node.name_len;
624        end = xid->start-1;
625
626        while ((p<end) && isspace(*p)) p++;
627        while (p<end)
628        {
629           size_t elementlen = strlen(name);
630           size_t restlen = end-p;
631           char *element = (char *)name;
632
633           new = __xml_memncasecmp(p, &restlen, &element, &elementlen);
634           if (new)
635           {
636              restlen = end-p;
637              new = memchr(p, '=', restlen);
638              if (new)
639              {
640                 new++;
641                 if (*new == '"') new++;
642                 restlen -= (new-p);
643                 end = new+restlen;
644                 ret = strtod(new, &end);
645              }
646              break;
647           }
648
649           while ((p<end) && !isspace(*p)) p++;
650           if (p<end)
651              while ((p<end) && isspace(*p)) p++;
652        }
653    }
654
655    return ret;
656 }
657
658 long int
659 xmlAttributeGetInt(const void *id, const char *name)
660 {
661    struct _xml_id *xid = (struct _xml_id *)id;
662    long int ret = 0;
663
664    if (xid && xid->start && xid->len && xid->node.name_len)
665    {
666        char *p, *end, *new = 0;
667
668        assert(xid->start > xid->name);
669
670        p = xid->name + xid->node.name_len;
671        end = xid->start-1;
672
673        while ((p<end) && isspace(*p)) p++;
674        while (p<end)
675        {
676           size_t elementlen = strlen(name);
677           size_t restlen = end-p;
678           char *element = (char *)name;
679
680           new = __xml_memncasecmp(p, &restlen, &element, &elementlen);
681           if (new)
682           {
683              restlen = end-p;
684              new = memchr(p, '=', restlen);
685              if (new)
686              {
687                 new++;
688                 if (*new == '"') new++;
689                 restlen -= (new-p);
690                 end = new+restlen;
691                 ret = strtol(new, &end, 10);
692              }
693              break;
694           }
695
696           while ((p<end) && !isspace(*p)) p++;
697           if (p<end)
698              while ((p<end) && isspace(*p)) p++;
699        }
700    }
701
702    return ret;
703 }
704
705 char *
706 xmlAttributeGetString(const void *id, const char *name)
707 {
708    struct _xml_id *xid = (struct _xml_id *)id;
709    char *ret = 0;
710
711    if (xid && xid->start && xid->len && xid->node.name_len)
712    {
713        char *p, *end, *new = 0;
714
715        assert(xid->start > xid->name);
716
717        p = xid->name + xid->node.name_len;
718        end = xid->start-1;
719
720        while ((p<end) && isspace(*p)) p++;
721        while (p<end)
722        {
723           size_t elementlen = strlen(name);
724           size_t restlen = end-p;
725           char *element = (char *)name;
726
727           new = __xml_memncasecmp(p, &restlen, &element, &elementlen);
728           if (new)
729           {
730              restlen = end-p;
731              new = memchr(p, '=', restlen);
732              if (new)
733              {
734                 new++;
735                 if (*new == '"') new++;
736                 p = new;
737                 while ((p<end) && (*p != '"') && (*p != ' ')) p++;
738                 if (p<end)
739                 {
740                    ret = calloc(1, p-new);
741                    memcpy(ret, new, (p-new));
742                 }
743              }
744              break;
745           }
746
747           while ((p<end) && !isspace(*p)) p++;
748           if (p<end)
749              while ((p<end) && isspace(*p)) p++;
750        }
751    }
752
753    return ret;
754 }
755
756 size_t
757 xmlAttributeCopyString(const void *id, const char *name,
758                                        char *buffer, size_t buflen)
759 {
760    struct _xml_id *xid = (struct _xml_id *)id;
761    size_t ret = 0;
762
763    if (xid && xid->start && xid->len && xid->node.name_len
764        && buffer && buflen)
765    {
766        char *ps, *pe;
767
768        *buffer = '\0';
769        ps = xid->name + xid->node.name_len + 1;
770        pe = xid->start - 1;
771
772        assert((int)(pe-ps) > 0);
773
774        while ((ps<pe) && isspace(*ps)) ps++;
775        while (ps<pe)
776        {
777           size_t slen = strlen(name);
778           size_t restlen = pe-ps;
779
780           if ((restlen >= slen) && (strncasecmp(ps, name, slen) == 0))
781           {
782              char *new;
783
784              restlen = pe-ps;
785              new = memchr(ps, '=', restlen);
786              if (new)
787              {
788                 new++;
789                 if (*new == '"') new++;
790                 ps = new;
791                 while ((ps<pe) && (*ps != '"') && (*ps != ' ')) ps++;
792                 if (ps<pe)
793                 {
794                    restlen = ps-new;
795                    if (restlen >= buflen) restlen = buflen-1;
796                    memcpy(buffer, new, restlen);
797                    *(buffer+restlen) = 0;
798                    ret = restlen;
799                 }
800              }
801              break;
802           }
803
804           while ((ps<pe) && !isspace(*ps)) ps++;
805           if (ps<pe)
806              while ((ps<pe) && isspace(*ps)) ps++;
807        }
808    }
809
810    return ret;
811 }
812
813 int
814 xmlAttributeCompareString(const void *id, const char *name, const char *s)
815 {
816    struct _xml_id *xid = (struct _xml_id *)id;
817    int ret = -1;
818
819    if (xid && xid->start && xid->len && xid->node.name_len
820        && s && strlen(s))
821    {
822       char *ps, *pe;
823
824        ps = xid->name + xid->node.name_len + 1;
825        pe = xid->start - 1;
826
827        assert((int)(pe-ps) > 0);
828
829        while ((ps<pe) && isspace(*ps)) ps++;
830        while (ps<pe)
831        {
832           size_t slen = strlen(name);
833           size_t restlen = pe-ps;
834
835           if ((restlen >= slen) && (strncasecmp(ps, name, slen) == 0))
836           {
837              char *new;
838
839              restlen = pe-ps;
840              new = memchr(ps, '=', restlen);
841              if (new)
842              {
843                 new++;
844                 if (*new == '"') new++;
845                 ps = new;
846                 while ((ps<pe) && (*ps != '"') && (*ps != ' ')) ps++;
847                 if (ps<pe)
848                 {
849                    int alen = ps-new;
850                    ret = strncasecmp(new, s, alen);
851                 }
852              }
853              break;
854           }
855
856           while ((ps<pe) && !isspace(*ps)) ps++;
857           if (ps<pe)
858              while ((ps<pe) && isspace(*ps)) ps++;
859        }
860    }
861
862    return ret;
863 }
864
865
866 /* -------------------------------------------------------------------------- */
867
868 static char *
869 __xmlNodeCopy(const char *start, size_t len, const char *path)
870 {
871    char *node, *p, *ret = 0;
872    size_t rlen, slen;
873
874    rlen = len;
875    slen = strlen(path);
876    node = (char *)path;
877    p = __xmlNodeGetPath(start, &rlen, &node, &slen);
878    if (p && rlen)
879    {
880       ret = calloc(1, rlen+1);
881       memcpy(ret, p, rlen);
882    }
883
884    return ret;
885 }
886
887 char *
888 __xmlNodeGetPath(const char *start, size_t *len, char **name, size_t *plen)
889 {
890     char *node;
891     char *ret = 0;
892
893     assert (start != 0);
894     assert (len != 0);
895     assert (name != 0);
896     assert (*name != 0);
897     assert (plen != 0);
898
899     if ((*len == 0) || (*plen == 0) || (*plen > *len))
900         return 0;
901
902     node = *name;
903     if (*node == '/') node++;
904     if (*node != 0)
905     {
906         size_t plen, slen;
907         char *path;
908         size_t num;
909
910         slen = strlen(node);
911         path = strchr(node, '/');
912
913         if (!path) plen = slen;
914         else plen = path++ - node;
915
916         num = 0;
917         ret = __xmlNodeGet(start, len, &node, &plen, &num);
918         if (ret && path)
919         {
920            plen = slen - (path - *name);
921            ret = __xmlNodeGetPath(ret, len, &path, &plen);
922         }
923
924         *name = path;
925     }
926
927     return ret;
928 }
929
930 char *
931 __xmlNodeGet(const char *start, size_t *len, char **name, size_t *rlen, size_t *nodenum)
932 {
933     char *new, *cur, *ne, *ret = 0;
934     char *element, *start_tag=0;
935     size_t restlen, elementlen;
936     size_t retlen = 0;
937     int found, num;
938
939     assert (start != 0);
940     assert (len != 0);
941     assert (name != 0);
942     assert (*name != 0);
943     assert (rlen != 0);
944     assert (nodenum != 0);
945
946     if ((*len == 0) || (*rlen == 0) || (*rlen > *len))
947         return 0;
948
949     found = 0;
950     num = *nodenum;
951     restlen = *len;
952     cur = (char *)start;
953     ne = cur + restlen;
954
955     while ((new = memchr(cur, '<', restlen)) != 0)
956     {
957         if (*(new+1) == '/')            /* cascading closing tag found */
958         {
959             *len -= restlen;
960              break;
961         }
962
963         new++;
964         restlen -= new-cur;
965         cur = new;
966
967         if (*cur == '!')
968         {
969             new = __xmlCommentSkip(cur, restlen);
970             if (!new) return 0;
971             restlen -= new-cur;
972             cur = new;
973             continue;
974         }
975         else if (*cur == '?')
976         {
977             new = __xmlInfoSkip(cur, restlen);
978             if (!new) return 0;
979
980             restlen -= new-cur;
981             cur = new;
982             continue;
983         }
984
985         element = *name;
986         elementlen = *rlen;
987         new = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
988         if (new)
989         {
990             retlen = elementlen;
991             if (found == num )
992             {
993               ret = new+1;
994               start_tag = element;
995             }
996             else start_tag = 0;
997         }
998         else
999         {
1000             new = cur+elementlen;
1001             if (new >= ne) return 0;
1002             element = *name;
1003         }
1004
1005         /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
1006         cur = new;
1007         new = memchr(cur, '<', restlen);
1008         if (!new) return 0;
1009
1010         restlen -= new-cur;
1011         cur = new;
1012         if (*(cur+1) != '/')                            /* new node found */
1013         {
1014             char *node = "*";
1015             size_t slen = restlen;
1016             size_t nlen = 1;
1017             size_t pos = -1;
1018
1019             new = __xmlNodeGet(cur, &slen, &node, &nlen, &pos);
1020             if (!new)
1021             {
1022                 if (slen == restlen) return 0;
1023                 else new = cur + slen;
1024             }
1025
1026             restlen -= slen;
1027             cur = new;
1028
1029             new = memchr(cur, '<', restlen);
1030             if (!new) return 0;
1031
1032             restlen -= new-cur;
1033             cur = new;
1034         }
1035
1036         if (*(cur+1) == '/')                            /* closing tag found */
1037         {
1038             if (!strncasecmp(new+2, element, elementlen))
1039             {
1040                 if (found == num) 
1041                 {
1042                    assert(start_tag != 0);
1043                    *len = new-ret;
1044                    *name = start_tag;
1045                 }
1046                 found++;
1047             }
1048
1049             new = memchr(cur, '>', restlen);
1050             if (!new) return 0;
1051
1052             restlen -= new-cur;
1053             cur = new;
1054         }
1055         else return 0;
1056     }
1057
1058     *rlen = retlen;
1059     *nodenum = found;
1060
1061     return ret;
1062 }
1063
1064 char *
1065 __xmlCommentSkip(const char *start, size_t len)
1066 {
1067     char *cur, *new;
1068
1069     cur = (char *)start;
1070     new = 0;
1071
1072     if (memcmp(cur, "!--", 3) == 0)
1073     {
1074         if (len < 6) return 0;
1075
1076         cur += 3;
1077         len -= 3;
1078
1079         do
1080         {
1081             new = memchr(cur, '-', len);
1082             if (new)
1083             {
1084                 len -= new - cur;
1085                 if ((len > 3) && (memcmp(new, "-->", 3) == 0))
1086                 {
1087                     new += 3;
1088                     len -= 3;
1089                     break;
1090                 }
1091                 cur = new+1;
1092             }
1093             else break;
1094         }
1095         while (new && (len > 2));
1096     }
1097
1098     return new;
1099 }
1100
1101 char *
1102 __xmlInfoSkip(const char *start, size_t len)
1103 {
1104     char *cur, *new;
1105
1106     cur = (char *)start;
1107     new = 0;
1108
1109     if (*cur == '?')
1110     {
1111         if (len < 3) return 0;
1112
1113         cur++;
1114         len--;
1115         new = memchr(cur, '?', len);
1116         if (!new || *(new+1) != '>') return 0;
1117
1118         new += 2;
1119     }
1120
1121     return new;
1122 }
1123
1124
1125 #define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
1126 void *
1127 __xml_memncasecmp(const char *haystack, size_t *haystacklen,
1128                   char **needle, size_t *needlelen)
1129 {
1130     void *rptr = 0;
1131
1132     if (haystack && needle && needlelen && (*needlelen > 0)
1133         && (*haystacklen >= *needlelen))
1134     {
1135         char *hs = (char *)haystack;
1136         char *ns;
1137         size_t i;
1138
1139         ns = *needle;
1140
1141         /* search for everything */
1142         if ((*ns == '*') && (*needlelen == 1))
1143         {
1144            char *he = hs + *haystacklen;
1145
1146            while ((hs < he) && (*hs != ' ') && (*hs != '>')) hs++;
1147            *needle = (char *)haystack;
1148            *needlelen = hs - haystack;
1149            while ((hs < he) && (*hs != '>')) hs++;
1150            rptr = hs;
1151         }
1152         else
1153         {
1154             size_t nlen = *needlelen;
1155             char *he = hs + *haystacklen;
1156
1157             for (i=0; i<nlen; i++)
1158             {
1159                 if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
1160                 if ((*hs == ' ') || (*hs == '>')) break;
1161                 hs++;
1162                 ns++;
1163             }
1164
1165             if (i != nlen)
1166             {
1167                 while((hs < he) && (*hs != ' ') && (*hs != '>')) hs++;
1168                 *needle = (char *)haystack;
1169                 *needlelen = hs - haystack;
1170             }
1171             else
1172             {
1173                 *needle = (char *)haystack;
1174                 *needlelen = hs - haystack;
1175                 while ((hs < he) && (*hs != '>')) hs++;
1176                 rptr = hs;
1177             }
1178         }
1179
1180         *haystacklen -= hs - haystack;
1181     }
1182
1183     return rptr;
1184 }
1185
1186 #ifdef WIN32
1187 /* Source:
1188  * https://mollyrocket.com/forums/viewtopic.php?p=2529
1189  */
1190
1191 void *
1192 simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
1193 {
1194     HANDLE f;
1195     HANDLE m;
1196     void *p;
1197
1198     f = (HANDLE)_get_osfhandle(fd);
1199     if (!f) return NULL;
1200
1201     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
1202     if (!m) return NULL;
1203
1204     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
1205     if (!p)
1206     {
1207         CloseHandle(m);
1208         return NULL;
1209     }
1210
1211     if (un)
1212     {
1213         un->m = m;
1214         un->p = p;
1215     }
1216
1217     return p;
1218 }
1219
1220 void
1221 simple_unmmap(SIMPLE_UNMMAP *un)
1222 {
1223    UnmapViewOfFile(un->p);
1224    CloseHandle(un->m);
1225 }
1226 #endif