]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xml.c
34d2bde6aa069c3d387bb332478bca50d5521be9
[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 void *simple_mmap(int, unsigned int, SIMPLE_UNMMAP *);
44 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 #else   /* !WIN32 */
50 # include <sys/mman.h>
51 # include <fcntl.h>
52 #endif
53
54 #include <sys/stat.h>
55 #include <sys/types.h>
56 #include <assert.h>
57 #include <unistd.h>
58 #include <ctype.h>
59
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63
64 struct _xml_id
65 {
66     char *name;
67     char *start;
68     size_t len;
69     size_t nlen;
70 };
71
72 static char *__xmlCopyNode(char *, size_t, const char *);
73 static char *__xmlGetNode(const char *, size_t *, char **, size_t *, int *);
74 static char *__xmlGetNodePath(const char *, size_t *, char **, size_t *);
75 static char *__xmlSkipComment(const char *, size_t);
76 static char *__xmlSkipInfo(const char *, size_t);
77
78 static void *__xml_memmem(const void *, size_t, const void *, size_t);
79 static void *__xml_memncasecmp(void *, size_t *, void **, size_t *);
80 static void *__xml_memchr(const void *, int, size_t);
81
82 #define PRINT(a, b, c) { \
83    if (a) { \
84       size_t q, len = c; \
85       if (b < c) len = b; \
86       if (len < 50000) { \
87          printf("(%i) '", len); \
88          for (q=0; q<len; q++) printf("%c", ((char *)(a))[q]); \
89          printf("'\n"); \
90       } else printf("Length (%u) seems too large at line %i\n",len, __LINE__); \
91    } else printf("NULL pointer at line %i\n", __LINE__); \
92 }
93
94 void *
95 xmlOpen(char *fn)
96 {
97     struct _xml_id *id = 0;
98
99     if (fn)
100     {
101         int fd = open(fn, O_RDONLY);
102         if (fd > 0)
103         {
104             id = malloc(sizeof(struct _xml_id));
105             if (id)
106             {
107                 struct stat statbuf;
108
109                 fstat(fd, &statbuf);
110
111                 id->nlen = (size_t)fd;
112                 id->len = statbuf.st_size;
113                 id->start = mmap(0, id->len, PROT_READ, MAP_PRIVATE, fd, 0L);
114                 id->name = 0;
115             }
116         }
117     }
118
119     return (void*)id;
120 }
121
122 void
123 xmlClose(void *id)
124 {
125     if (id)
126     {
127         struct _xml_id *xid = (struct _xml_id *)id;
128         assert(xid->name == 0);
129
130         munmap(xid->start, xid->len);
131         close((int)xid->nlen);
132         free(id);
133         id = 0;
134     }
135 }
136
137 void *
138 xmlCopyNode(void *id, char *path)
139 {
140     struct _xml_id *xsid = 0;
141
142     if (id && path)
143     {
144         struct _xml_id *xid = (struct _xml_id *)id;
145         char *ptr, *node, *p;
146         size_t slen, len;
147
148         node = path;
149         len = xid->len;
150         slen = strlen(path);
151         ptr = __xmlGetNodePath(xid->start, &len, &node, &slen);
152         if (ptr)
153         {
154             xsid = malloc(sizeof(struct _xml_id) + len);
155             if (xsid)
156             {
157                 p = (char *)xsid + sizeof(struct _xml_id);
158
159                 xsid->len = len;
160                 xsid->start = p;
161                 xsid->nlen = slen;
162                 xsid->name = node;
163
164                 memcpy(xsid->start, ptr, len);
165            }
166        }
167    }
168
169    return (void *)xsid;
170 }
171
172 void *
173 xmlGetNode(void *id, char *path)
174 {
175    struct _xml_id *xsid = 0;
176
177    if (id && path)
178    {
179       struct _xml_id *xid = (struct _xml_id *)id;
180       size_t len, slen;
181       char *ptr, *node;
182
183       node = path;
184       len = xid->len;
185       slen = strlen(path);
186       ptr = __xmlGetNodePath(xid->start, &len, &node, &slen);
187       if (ptr)
188       {
189          xsid = malloc(sizeof(struct _xml_id));
190          if (xsid)
191          {
192              xsid->len = len;
193              xsid->start = ptr;
194              xsid->nlen = slen;
195              xsid->name = node;
196          }
197       }
198    }
199
200    return (void *)xsid;
201 }
202
203 char *
204 xmlGetNodeName(void *id)
205 {
206     struct _xml_id *xid = (struct _xml_id *)id;
207     char *ret;
208
209     ret = malloc(xid->nlen+1);
210     if (ret)
211     {
212         memcpy(ret, xid->name, xid->nlen);
213         *(ret + xid->nlen) = 0;
214     }
215
216     return ret;
217 }
218
219 size_t
220 xmlCopyNodeName(void *id, const char *buf, size_t len)
221 {
222     struct _xml_id *xid = (struct _xml_id *)id;
223     size_t slen = 0;
224  
225     if (buf)
226     {
227         slen = len-1;
228         if (slen > xid->nlen) slen = xid->nlen;
229         memcpy((char *)buf, xid->name, slen);
230     }
231 }
232
233 void *
234 xmlGetNodeNum(const void *rid, void *id, char *element, int num)
235 {
236     struct _xml_id *xrid = (struct _xml_id *)rid;
237     void *ret = 0;
238
239     if (id && element)
240     {
241         struct _xml_id *xid = (struct _xml_id *)id;
242         size_t len, slen;
243         char *ptr, *node;
244
245         len = xrid->len;
246         slen = strlen(element);
247         node = element;
248         ptr = __xmlGetNode(xrid->start, &len, &node, &slen, &num);
249         if (ptr)
250         {
251              xid->len = len;
252              xid->start = ptr;
253              xid->name = node;
254              xid->nlen = slen;
255              ret = xid;
256         }
257     }
258
259     return ret;
260 }
261
262 int
263 xmlCompareString(const void *id, const char *s)
264 {
265     struct _xml_id *xid = (struct _xml_id *)id;
266     int ret = -1;
267
268     if (xid && xid->len && s && (strlen(s) > 0))
269     {
270         char *ps, *pe;
271
272         ps = xid->start;
273         pe = ps + xid->len;
274         pe--;
275
276         while ((ps<pe) && isspace(*ps)) ps++;
277         while ((pe>ps) && isspace(*pe)) pe--;
278         pe++;
279
280         ret = strncasecmp(ps, s, pe-ps);
281     }
282
283     return ret;
284 }
285
286 int
287 xmlCompareNodeString(const void *id, const char *path, const char *s)
288 {
289     struct _xml_id *xid = (struct _xml_id *)id;
290     int ret = -1;
291
292     if (xid && xid->len && path && s && (strlen(s) > 0))
293     {
294         char *node, *str, *ps, *pe;
295         size_t len, slen;
296
297         len = xid->len;
298         slen = strlen(path);
299         node = (char *)path;
300         str = __xmlGetNodePath(xid->start, &len, &node, &slen);
301         if (str)
302         {
303             ps = str;
304             pe = ps + len;
305             pe--;
306
307             while ((ps<pe) && isspace(*ps)) ps++;
308             while ((pe>ps) && isspace(*pe)) pe--;
309             pe++;
310
311             ret = strncasecmp(pe, s, pe-ps);
312         }
313     }
314
315     return ret;
316 }
317
318 char *
319 xmlGetNodeString(void *id, const char *path)
320 {
321     struct _xml_id *xid = (struct _xml_id *)id;
322     char *str = 0;
323
324     if (xid && xid->len && path)
325     {
326         str = __xmlCopyNode(xid->start, xid->len, path);
327         if (str)
328         {
329             char *ps, *pe, *pend;
330             int slen;
331
332             ps = str;
333             slen = strlen(str);
334             pend = ps+slen;
335             pe = pend-1;
336
337             while ((ps<pe) && isspace(*ps)) ps++;
338             while ((pe>ps) && isspace(*pe)) pe--;
339
340             *++pe = 0;
341             slen = (pe-ps);
342             if (slen && (ps>str)) memmove(str, ps, slen);
343             else if (!slen) *str = 0;
344         }
345     }
346
347     return str;
348 }
349
350 char *
351 xmlGetString(void *id)
352 {
353     struct _xml_id *xid = (struct _xml_id *)id;
354     char *str = 0;
355
356     if (xid && xid->len)
357     {
358         char *ps, *pe, *pend;
359         int nlen;
360
361         ps = xid->start;
362         nlen = xid->len;
363         pend = ps+nlen;
364         pe = pend;
365
366         while ((ps<pe) && isspace(*ps)) ps++;
367         while ((pe>ps) && isspace(*pe)) pe--;
368         nlen = (pe-ps);
369         if (nlen)
370         {
371             str = malloc(nlen+1);
372             if (str)
373             {
374                 memcpy(str, ps, nlen);
375                 *(str+nlen) = 0;
376             }
377         }
378     }
379
380     return str;
381 }
382
383 size_t
384 xmlCopyString(void *id, char *buf, size_t len)
385 {
386     struct _xml_id *xid = (struct _xml_id *)id;
387     size_t nlen = 0;
388
389     if (xid && xid->len && buf && len)
390     {
391         char *ps, *pe, *pend;
392         int slen;
393
394         nlen = len-1;
395         ps = xid->start;
396         slen = xid->len;
397         pend = ps+slen;
398         pe = pend;
399
400         while ((ps<pe) && isspace(*ps)) ps++;
401         while ((pe>ps) && isspace(*pe)) pe--;
402         nlen = (pe-ps);
403         if (nlen > slen) nlen = slen;
404
405         if (nlen)
406         {
407             memcpy(buf, ps, nlen);
408             *(buf+nlen) = 0;
409         }
410     }
411
412     return nlen;
413 }
414
415 size_t
416 xmlCopyNodeString(void *id, const char *path, char *buffer, size_t buflen)
417 {
418     struct _xml_id *xid = (struct _xml_id *)id;
419     size_t len = 0;
420
421     if (xid && xid->len && path && buffer && buflen)
422     {
423         char *str, *node;
424         size_t slen;
425
426         *buffer = 0;
427         len = xid->len;
428         slen = strlen(path);
429         node = (char *)path;
430         str = __xmlGetNodePath(xid->start, &len, &node, &slen);
431         if (str)
432         {
433             char *ps, *pe;
434
435             ps = str;
436             pe = ps+len-1;
437
438             while ((ps<pe) && isspace(*ps)) ps++;
439             while ((pe>ps) && isspace(*pe)) pe--;
440
441             len = (pe-ps)+1;
442             if (len >= buflen) len = buflen-1;
443
444             memcpy(buffer, ps, len);
445             str = buffer + len;
446             *str = 0;
447         }
448     }
449
450     return len;
451 }
452
453 long int
454 xmlGetNodeInt(void *id, const char *path)
455 {
456     struct _xml_id *xid = (struct _xml_id *)id;
457     long int li = 0;
458
459     if (path && xid && xid->len)
460     {
461         size_t len, slen;
462         char *str, *node;
463
464         len = xid->len;
465         slen = strlen(path);
466         node = (char *)path;
467         str = __xmlGetNodePath(xid->start, &len, &node, &slen);
468         if (str)
469         {
470             char *end = str+len;
471             li = strtol(str, &end, 10);
472         }
473     }
474
475     return li;
476 }
477
478 long int
479 xmlGetInt(void *id)
480 {
481     struct _xml_id *xid = (struct _xml_id *)id;
482     long int li = 0;
483
484     if (xid && xid->len)
485     {
486         char *end = xid->start + xid->len;
487         li = strtol(xid->start, &end, 10);
488     }
489
490     return li;
491 }
492
493 double
494 xmlGetNodeDouble(void *id, const char *path)
495 {
496    struct _xml_id *xid = (struct _xml_id *)id;
497    double d = 0.0;
498
499     if (path && xid && xid->len)
500     {
501         size_t len, slen;
502         char *str, *node;
503
504         len = xid->len;
505         slen = strlen(path);
506         node = (char *)path;
507         str = __xmlGetNodePath(xid->start, &len, &node, &slen);
508         if (str)
509         {
510             char *end = str+len;
511             d = strtod(str, &end);
512         }
513     }
514
515     return d;
516 }
517
518 double
519 xmlGetDouble(void *id)
520 {
521    struct _xml_id *xid = (struct _xml_id *)id;
522    double d = 0.0;
523
524     if (xid && xid->len)
525     {
526         char *end = xid->start + xid->len;
527         d = strtod(xid->start, &end);
528     }
529
530     return d;
531 }
532
533
534 unsigned int
535 xmlGetNumNodes(void *id, const char *path)
536 {
537     struct _xml_id *xid = (struct _xml_id *)id;
538     unsigned num = 0;
539
540     if (xid && xid->len && path)
541     {
542         char *nodename, *pathname;
543         size_t len, slen;
544         char *p;
545
546         nodename = (char *)path;
547         if (*path == '/') nodename++;
548         slen = strlen(nodename);
549
550         pathname = strchr(nodename, '/');
551         if (pathname)
552         {
553            char *node;
554
555            len = xid->len;
556            pathname++;
557            slen -= pathname-nodename;
558            node = pathname;
559            p = __xmlGetNodePath(xid->start, &len, &node, &slen);
560         }
561         else
562         {
563             p = (char *)xid->start;
564             len = xid->len;
565         }
566            
567         if (p)
568         {
569             char *node = nodename;
570             __xmlGetNode(p, &len, &node, &slen, &num);
571         }
572     }
573
574     return num;
575 }
576
577 void *
578 xmlMarkId(void *id)
579 {
580    struct _xml_id *xmid = 0;
581
582    if (id)
583    {
584       xmid = malloc(sizeof(struct _xml_id));
585       if (xmid)
586       {
587           memcpy(xmid, id, sizeof(struct _xml_id));
588           xmid->nlen = 0;
589       }
590    }
591
592    return (void *)xmid;
593 }
594
595 /* -------------------------------------------------------------------------- */
596
597 static char *
598 __xmlCopyNode(char *start, size_t len, const char *path)
599 {
600    char *node, *p, *ret = 0;
601    size_t rlen, slen;
602
603    rlen = len;
604    slen = strlen(path);
605    node = (char *)path;
606    p = __xmlGetNodePath(start, &rlen, &node, &slen);
607    if (p && rlen)
608    {
609       ret = calloc(1, rlen+1);
610       memcpy(ret, p, rlen);
611    }
612
613    return ret;
614 }
615
616 char *
617 __xmlGetNodePath(const char *start, size_t *len, char **name, size_t *plen)
618 {
619     char *node;
620     char *ret = 0;
621
622     assert (start != 0);
623     assert (len != 0);
624     assert (name != 0);
625     assert (*name != 0);
626     assert (plen != 0);
627
628     if ((*len == 0) || (*plen == 0) || (*plen > *len))
629         return 0;
630
631     node = (char *)*name;
632     if (*node == '/') node++;
633     if (*node != 0)
634     {
635         size_t plen, slen;
636         char *path;
637         int num;
638
639         slen = strlen(node);
640         path = strchr(node, '/');
641
642         if (!path) plen = slen;
643         else plen = path++ - node;
644
645         num = 0;
646         ret = __xmlGetNode(start, len, &node, &plen, &num);
647         if (ret && path)
648         {
649            plen = slen - (path - *name);
650            ret = __xmlGetNodePath(ret, len, &path, &plen);
651         }
652
653         *name = path;
654     }
655
656     return ret;
657 }
658
659 char *
660 __xmlGetNode(const char *start, size_t *len, char **name, size_t *rlen, int *nodenum)
661 {
662     char *new, *cur, *ne, *ret = 0;
663     size_t restlen, elementlen;
664     int found, num;
665     void *element;
666
667     assert (start != 0);
668     assert (len != 0);
669     assert (name != 0);
670     assert (*name != 0);
671     assert (rlen != 0);
672     assert (nodenum != 0);
673
674     if ((*len == 0) || (*rlen == 0) || (*rlen > *len))
675         return 0;
676
677     found = 0;
678     num = *nodenum;
679     restlen = *len;
680     cur = (char *)start;
681     ne = cur + restlen;
682
683     while ((new = memchr(cur, '<', restlen)) != 0)
684     {
685         if (*(new+1) == '/')            /* cascading closing tag found */
686         {
687             *len -= restlen;
688              break;
689         }
690
691         new++;
692         restlen -= new-cur;
693         cur = new;
694
695         if (*cur == '!')
696         {
697             new = __xmlSkipComment(cur, restlen);
698             if (!new) return 0;
699             restlen -= new-cur;
700             cur = new;
701             continue;
702         }
703         else if (*cur == '?')
704         {
705             new = __xmlSkipInfo(cur, restlen);
706             if (!new) return 0;
707
708             restlen -= new-cur;
709             cur = new;
710             continue;
711         }
712
713         element = (char *)*name;
714         elementlen = *rlen;
715         new = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
716         if (new)
717         {
718             if (found == num ) ret = new+1;
719         }
720         else
721         {
722             new = cur+elementlen;
723             if (new >= ne) return 0;
724             element = (char *)*name;
725             elementlen = *rlen;
726         }
727
728         /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
729         cur = new;
730         new = memchr(cur, '<', restlen);
731         if (!new) return 0;
732
733         restlen -= new-cur;
734         cur = new;
735         if (*(cur+1) != '/')                            /* new node found */
736         {
737             char *node = "*";
738             size_t slen = restlen;
739             size_t nlen = 1;
740             int pos = -1;
741
742             new = __xmlGetNode(cur, &slen, &node, &nlen, &pos);
743             if (!new)
744             {
745                 if (slen == restlen) return 0;
746                 else new = cur + slen;
747             }
748
749             restlen -= slen;
750             cur = new;
751
752             new = memchr(cur, '<', restlen);
753             if (!new) return 0;
754
755             restlen -= new-cur;
756             cur = new;
757         }
758
759         if (*(cur+1) == '/')                            /* closing tag found */
760         {
761             if (!strncasecmp(new+2, element, elementlen))
762             {
763                 if (found == num) *len = new-ret;
764                 *name = element;
765                 found++;
766             }
767
768             new = memchr(cur, '>', restlen);
769             if (!new) return 0;
770
771             restlen -= new-cur;
772             cur = new;
773         }
774         else return 0;
775     }
776
777     *rlen = elementlen;
778     *nodenum = found;
779
780     return ret;
781 }
782
783 char *
784 __xmlSkipComment(const char *start, size_t len)
785 {
786     char *cur, *new;
787
788     cur = (char *)start;
789     new = 0;
790
791     if (memcmp(cur, "!--", 3) == 0)
792     {
793         if (len < 6) return 0;
794
795         cur += 3;
796         len -= 3;
797
798         do
799         {
800             new = memchr(cur, '-', len);
801             if (new)
802             {
803                 len -= new - cur;
804                 if ((len > 3) && (memcmp(new, "-->", 3) == 0))
805                 {
806                     new += 3;
807                     len -= 3;
808                     break;
809                 }
810                 cur = new+1;
811             }
812             else break;
813         }
814         while (new && (len > 2));
815     }
816
817     return new;
818 }
819
820 char *
821 __xmlSkipInfo(const char *start, size_t len)
822 {
823     char *cur, *new;
824
825     cur = (char *)start;
826     new = 0;
827
828     if (*cur == '?')
829     {
830         if (len < 3) return 0;
831
832         cur++;
833         len--;
834         new = memchr(cur, '?', len);
835         if (!new || *(new+1) != '>') return 0;
836
837         new += 2;
838     }
839
840     return new;
841 }
842
843
844 void *
845 __xml_memmem(const void *haystack, size_t haystacklen,
846                          const void *needle, size_t needlelen)
847 {
848     void *rptr = 0;
849
850     if (haystack && needle && (needlelen > 0) && (haystacklen >= needlelen))
851     {
852         char *ns, *hs, *ptr;
853
854         hs = (char *)haystack;
855         ns = (char *)needle;
856
857         do
858         {
859             ptr = memchr(hs, *ns, haystacklen);
860             if (ptr)
861             {
862                 haystacklen -= (ptr - hs);
863
864                 if (haystacklen < needlelen) break;
865                 if (memcmp(ptr, needle, needlelen) == 0)
866                 {
867                    rptr = ptr;
868                    break;
869                 }
870
871                 hs = ptr+1;
872             }
873             else break;
874         }
875         while (haystacklen > needlelen);
876     }
877
878     return rptr;
879 }
880
881
882 #define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
883 void *
884 __xml_memncasecmp(void *haystack, size_t *haystacklen,
885                   void **needle, size_t *needlelen)
886 {
887     void *rptr = 0;
888     char *hs = (char *)haystack;
889
890     if (haystack && needle && needlelen && (*needlelen > 0)
891         && (*haystacklen >= *needlelen))
892     {
893         char *ns;
894         size_t i;
895
896         ns = (char *)*needle;
897
898         /* search for everything */
899         if ((*ns == '*') && (*needlelen == 1))
900         {
901            char *he = hs + *haystacklen;
902
903            while ((hs < he) && (*hs != ' ') && (*hs != '>')) hs++;
904            *needle = (void *)haystack;
905            *needlelen = hs - (char *)haystack;
906
907            while ((hs < he) && (*hs != '>')) hs++;
908            rptr = hs;
909         }
910         else
911         {
912             size_t nlen = *needlelen;
913             char *he = hs + *haystacklen;
914
915             for (i=0; i<nlen; i++)
916             {
917                 if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
918                 if ((*hs == ' ') || (*hs == '>')) break;
919                 hs++;
920                 ns++;
921             }
922
923             if (i != nlen)
924             {
925                 while((hs < he) && (*hs != ' ') && (*hs != '>')) hs++;
926                 *needle = (void *)haystack;
927                 *needlelen = hs - (char *)haystack;
928             }
929             else
930             {
931                 *needle = (void *)haystack;
932                 *needlelen = hs - (char *)haystack;
933                 while ((hs < he) && (*hs != '>')) hs++;
934                 rptr = hs;
935             }
936         }
937
938         *haystacklen -= hs - (char *)haystack;
939     }
940
941     return rptr;
942 }
943
944 #ifdef WIN32
945 /* Source:
946  * https://mollyrocket.com/forums/viewtopic.php?p=2529
947  */
948
949 void *
950 simple_mmap(int fd, unsigned int length, SIMPLE_UNMMAP *un)
951 {
952     HANDLE f;
953     HANDLE m;
954     void *p;
955
956     f = (HANDLE)_get_osfhandle(fd);
957     if (!f) return NULL;
958
959     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
960     if (!m) return NULL;
961
962     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
963     if (!p)
964     {
965         CloseHandle(m);
966         return NULL;
967     }
968
969     if (n) *n = GetFileSize(f, NULL);
970
971     if (un)
972     {
973         un->m = m;
974         un->p = p;
975     }
976
977     return p;
978 }
979
980 void
981 simple_unmmap(SIMPLE_UNMMAP *un)
982 {
983    UnmapViewOfFile(un->p);
984    CloseHandle(un->m);
985 }
986 #endif