]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xml.c
whoops, my bad
[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 <unistd.h>
57 #include <ctype.h>
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62
63 struct _xml_id
64 {
65     char *start;
66     size_t len;
67     int fd;
68 };
69
70 static char *__xmlCopyNode(char *, size_t, const char *);
71 static char *__xmlGetNode(char *, size_t, const char *, size_t *);
72 static char *__xmlFindNextElement(char *, size_t, const char *);
73 static void *memncasemem(const void *, size_t, const void *, size_t);
74
75 void *
76 xmlOpen(char *fn)
77 {
78     struct _xml_id *id = 0;
79
80     if (fn)
81     {
82         int fd = open(fn, O_RDONLY);
83         if (fd > 0)
84         {
85             id = malloc(sizeof(struct _xml_id));
86             if (id)
87             {
88                 struct stat statbuf;
89
90                 fstat(fd, &statbuf);
91
92                 id->fd = fd;
93                 id->len = statbuf.st_size;
94                 id->start = mmap(0, id->len, PROT_READ, MAP_PRIVATE, fd, 0L);
95             }
96         }
97     }
98
99     return (void*)id;
100 }
101
102 void
103 xmlClose(void *id)
104 {
105     if (id)
106     {
107         struct _xml_id *xid = (struct _xml_id *)id;
108         munmap(xid->start, xid->len);
109         close(xid->fd);
110         free(id);
111         id = 0;
112     }
113 }
114
115 void *
116 xmlCopyNode(void *id, char *path)
117 {
118     struct _xml_id *xsid = 0;
119
120     if (id && path)
121     {
122         struct _xml_id *xid = (struct _xml_id *)id;
123         char *ptr, *p;
124         size_t rlen;
125
126         rlen = strlen(path);
127         ptr = __xmlGetNode(xid->start, xid->len, path, &rlen);
128         if (ptr)
129         {
130             xsid = malloc(sizeof(struct _xml_id) + rlen);
131             if (xsid)
132             {
133                 p = (char *)xsid + sizeof(struct _xml_id);
134
135                 xsid->len = rlen;
136                 xsid->start = p;
137                 xsid->fd = 0;
138
139                 memcpy(xsid->start, ptr, rlen);
140            }
141        }
142    }
143
144    return (void *)xsid;
145 }
146
147 void *
148 xmlGetNode(void *id, 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 rlen;
156       char *ptr;
157
158       rlen = strlen(path);
159       ptr = __xmlGetNode(xid->start, xid->len, path, &rlen);
160       if (ptr)
161       {
162          xsid = malloc(sizeof(struct _xml_id));
163          xsid->len = rlen;
164          xsid->start = ptr;
165          xsid->fd = 0;
166       }
167    }
168
169    return (void *)xsid;
170 }
171
172 void *
173 xmlGetNextElement(const void *pid, void *id, char *path)
174 {
175     struct _xml_id *xpid = (struct _xml_id *)pid;
176     struct _xml_id *xsid = 0;
177
178     if (id && path)
179     {
180         struct _xml_id *xid = (struct _xml_id *)id;
181         size_t rlen, nlen;
182         char *ptr;
183
184         if (xid->len < xpid->len) xid->start += xid->len;
185         nlen = xpid->len - (xid->start - xpid->start);
186
187         rlen = strlen(path);
188         ptr = __xmlGetNode(xid->start, nlen, path, &rlen);
189         if (ptr)
190         {
191              xid->len = rlen;
192              xid->start = ptr;
193              xsid = xid;
194         }
195     }
196
197     return (void *)xsid;
198 }
199
200 int
201 xmlCompareString(const void *id, const char *s)
202 {
203     struct _xml_id *xid = (struct _xml_id *)id;
204     int ret = -1;
205
206     if (xid && xid->len && s && (strlen(s) > 0))
207     {
208         ret = strncasecmp(xid->start, s, xid->len);
209     }
210
211     return ret;
212 }
213
214 int
215 xmlCompareNodeString(const void *id, const char *path, const char *s)
216 {
217     struct _xml_id *xid = (struct _xml_id *)id;
218     int ret = -1;
219
220     if (xid && xid->len && path && s && (strlen(s) > 0))
221     {
222         size_t rlen;
223         char *str;
224
225         rlen = strlen(path);
226         str = __xmlGetNode(xid->start, xid->len, path, &rlen);
227         if (str) ret = strncasecmp(str, s, rlen);
228     }
229
230     return ret;
231 }
232
233 char *
234 xmlGetNodeString(void *id, const char *path)
235 {
236     struct _xml_id *xid = (struct _xml_id *)id;
237     char *str = 0;
238
239     if (xid && xid->len && path)
240     {
241         str = __xmlCopyNode(xid->start, xid->len, path);
242         if (str)
243         {
244             char *ps, *pe, *pem;
245             int slen;
246
247             slen = strlen(str);
248             ps = str;
249             pe = pem = ps+slen;
250
251             while ((ps<pe) && isspace(*ps)) ps++;
252             while ((pe>ps) && isspace(*pe)) pe--;
253
254             if (pe<pem) *++pe = 0;
255             slen = (pe-ps);
256             if ((ps>str) && slen) memmove(str, ps, slen+1);
257             else if (!slen) *str = 0;
258         }
259     }
260
261     return str;
262 }
263
264 char *
265 xmlGetString(void *id)
266 {
267     struct _xml_id *xid = (struct _xml_id *)id;
268     char *str = 0;
269
270     if (xid && xid->len)
271     {
272         str = malloc(xid->len+1);
273         if (str)
274         {
275             char *ps, *pe, *pem;
276             int slen;
277
278             slen = xid->len;
279             memcpy(str, xid->start, slen);
280             *(str+slen) = 0;
281
282             ps = str;
283             pe = pem = ps+slen;
284
285             while ((ps<pe) && isspace(*ps)) ps++;
286             while ((pe>ps) && isspace(*pe)) pe--;
287
288             if (pe<pem) *++pe = 0;
289             slen = (pe-ps);
290             if ((ps>str) && slen) memmove(str, ps, slen+1);
291             else if (!slen) *str = 0;
292         }
293     }
294
295     return str;
296 }
297
298 unsigned int
299 xmlCopyString(void *id, const char *path, char *buffer, unsigned int buflen)
300 {
301     struct _xml_id *xid = (struct _xml_id *)id;
302     unsigned int rlen = 0;
303
304     if (xid && xid->len && path && buffer && buflen)
305     {
306         char *str;
307
308         *buffer = 0;
309         rlen = strlen(path);
310         str = __xmlGetNode(xid->start, xid->len, path, &rlen);
311         if (str)
312         {
313             char *ps, *pe;
314
315             ps = str;
316             pe = ps+rlen-1;
317
318             while ((ps<pe) && isspace(*ps)) ps++;
319             while ((pe>ps) && isspace(*pe)) pe--;
320
321             rlen = (pe-ps)+1;
322             if (rlen >= buflen) rlen = buflen-1;
323
324             memcpy(buffer, ps, rlen);
325             str = buffer + rlen;
326             *str = 0;
327         }
328     }
329
330     return rlen;
331 }
332
333 long int
334 xmlGetNodeInt(void *id, const char *path)
335 {
336     struct _xml_id *xid = (struct _xml_id *)id;
337     long int li = 0;
338
339     if (path && xid && xid->len)
340     {
341         unsigned int rlen;
342         char *str;
343
344         rlen = strlen(path);
345         str = __xmlGetNode(xid->start, xid->len, path, &rlen);
346         if (str) li = strtol(str, (char **)NULL, 10);
347     }
348
349     return li;
350 }
351
352 long int
353 xmlGetInt(void *id)
354 {
355     struct _xml_id *xid = (struct _xml_id *)id;
356     long int li = 0;
357
358     if (xid && xid->len)
359         li = strtol(xid->start, (char **)NULL, 10);
360
361     return li;
362 }
363
364 double
365 xmlGetNodeDouble(void *id, const char *path)
366 {
367    struct _xml_id *xid = (struct _xml_id *)id;
368    double d = 0.0;
369
370     if (path && xid && xid->len)
371     {
372         unsigned int rlen;
373         char *str;
374
375         rlen = strlen(path);
376         str = __xmlGetNode(xid->start, xid->len, path, &rlen);
377
378         if (str) d = strtod(str, (char **)NULL);
379     }
380
381     return d;
382 }
383
384 double
385 xmlGetDouble(void *id)
386 {
387    struct _xml_id *xid = (struct _xml_id *)id;
388    double d = 0.0;
389
390     if (xid && xid->len)
391         d = strtod(xid->start, (char **)NULL);
392
393     return d;
394 }
395
396
397 unsigned int
398 xmlGetNumElements(void *id, const char *path)
399 {
400     struct _xml_id *xid = (struct _xml_id *)id;
401     unsigned ret = 0;
402
403     if (xid && xid->len && path)
404     {
405         unsigned int clen;
406         char *p, *pathname;
407         char *pname, *nname;
408
409         pathname = (char *)path;
410         if (*path == '/') pathname++;
411
412         nname = strrchr(pathname, '/');
413         if (nname)
414         {
415            clen = nname-pathname;
416            p = __xmlGetNode(xid->start, xid->len, path, &clen);
417         }
418         else
419         {
420             nname = (char *)pathname;
421             p = (char *)xid->start;
422             clen = xid->len;
423         }
424            
425         while ((p = __xmlFindNextElement(p, clen, nname)) != 0)
426             ret++;
427     }
428
429     return ret;
430 }
431
432 void *
433 xmlMarkId(void *id)
434 {
435    struct _xml_id *xmid = 0;
436
437    if (id)
438    {
439       xmid = malloc(sizeof(struct _xml_id));
440       if (xmid)
441       {
442           memcpy(xmid, id, sizeof(struct _xml_id));
443           xmid->fd = 0;
444       }
445    }
446
447    return (void *)xmid;
448 }
449
450 /* -------------------------------------------------------------------------- */
451
452 char *
453 __xmlCopyNode(char *start, size_t len, const char *path)
454 {
455    char *p, *ret = 0;
456    size_t rlen;
457
458    rlen = strlen(path);
459    p = __xmlGetNode(start, len, path, &rlen);
460    if (p && rlen)
461    {
462       ret = calloc(1, rlen+1);
463       memcpy(ret, p, rlen);
464    }
465
466    return ret;
467 }
468
469 char *
470 __xmlGetNode(char *start, size_t len, const char *path, size_t *rlen)
471 {
472     char *ret = 0;
473
474     if (len)
475     {
476         char last_node = 0;
477         char *ptr, *name;
478         int plen;
479
480         name = (char *)path;
481         if (*name == '/') name++;       /* skip the leading '/' character */
482
483         ptr = strchr(name, '/');
484         if (!ptr)
485         {
486            last_node = 1;
487            ptr = name + *rlen;
488         }
489         plen = ptr - name;
490          
491         if (plen)
492         {
493             char *p, *cur;
494
495             cur = start;
496             do
497             {
498                 if ((p = memncasemem(cur, len, name, plen)) != 0)
499                 {
500                     len -= (p + plen) - cur;
501                     cur = p + plen;
502                 }
503             }
504             while (p && (*(p-1) != '<'));
505
506             if (p)
507             {
508                 p = cur;
509                 while ((*cur++ != '>') && (cur<(p+len)));
510                 len -= cur - p;
511
512                 if (last_node)
513                 {
514                     char *rptr = cur;
515                     do
516                     {
517                         if ((p = memncasemem(cur, len, name, plen)) != 0) 
518                         {
519                             len -= (p + plen) - cur;
520                             cur = p + plen;
521                             if (*(p-2) == '<' && *(p-1) == '/'
522                                 && *(p+plen) == '>') break;
523                         }
524                     }
525                     while (p);
526
527                     if (p)
528                     {
529                         *rlen = p-rptr-2;
530                         ret = rptr;
531                     }
532                 }
533                 else
534                 {
535                     ret = __xmlGetNode(cur, len, ptr+1, rlen);
536                 }
537             }
538         }
539     }
540
541     return ret;
542 }
543
544 char *
545 __xmlFindNextElement(char *start, size_t len, const char *name)
546 {
547     char *ret = 0;
548
549     if (start && len && name)
550     {
551         unsigned int plen;
552
553         plen = strlen(name);
554         if (plen)
555         {
556             char *p, *cur;
557
558             cur = start;
559             do
560             {
561                 if ((p = memncasemem(cur, len, name, plen)) != 0)
562                 {
563                     len -= (p + plen) - cur;
564                     cur = p + plen;
565                 }
566             }
567             while (p && (*(p-1) != '<'));
568
569             if (p)
570             {
571                 char *rptr = cur;
572
573                 p = cur;
574                 while ((*cur++ != '>') && (cur<(p+len)));
575                 len -= cur - p;
576
577                 do
578                 {
579                     if ((p = memncasemem(cur, len, name, plen)) != 0)
580                     {
581                         len -= (p + plen) - cur;
582                         cur = p + plen;
583                         if (*(p-2) == '<' && *(p-1) == '/' && *(p+plen) == '>')
584                             break;
585                     }
586                 }
587                 while (p);
588
589                 ret = rptr;
590           }
591       }
592    }
593
594    return ret;
595 }
596
597
598 #define CASECMP(a,b)    ( ((a) & 0xdf) == ((b) & 0xdf) )
599 #define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
600
601 void *
602 memncasemem(const void *haystack, size_t haystacklen,
603                          const void *needle, size_t needlelen)
604 {
605     void *rptr = 0;
606
607     if (haystack && needle && (needlelen > 0) && (haystacklen >= needlelen))
608     {
609         const char *ne = (const char *)needle + needlelen;
610         const char *he = (const char *)haystack + haystacklen;
611         const char *hne = he - needlelen;
612         char *ns, *hs = (char *)haystack;
613
614         do
615         {
616             rptr = 0;
617             ns = (char *)needle;
618             while((hs <= hne) && NOCASECMP(*hs,*ns))
619                hs++;
620
621             if (hs < hne)
622             {
623                 rptr = hs;
624                 while((hs < he) && (ns < ne) && !NOCASECMP(*hs,*ns))
625                 {
626                     hs++;
627                     ns++;
628                 }
629             }
630             else break;
631         }
632         while (ns < ne);
633     }
634
635     return rptr;
636 }
637
638 #if 0
639 const unsigned char *
640 boyermoore_horspool_memmem(const unsigned char* haystack, size_t hlen,
641                            const unsigned char* needle,   size_t nlen)
642 {
643     size_t scan = 0;
644     size_t bad_char_skip[UCHAR_MAX + 1]; /* Officially called:
645                                           * bad character shift */
646  
647     /* Sanity checks on the parameters */
648     if (nlen <= 0 || !haystack || !needle)
649         return NULL;
650  
651     /* ---- Preprocess ---- */
652     /* Initialize the table to default value */
653     /* When a character is encountered that does not occur
654      * in the needle, we can safely skip ahead for the whole
655      * length of the needle.
656      */
657     for (scan = 0; scan <= UCHAR_MAX; scan = scan + 1)
658         bad_char_skip[scan] = nlen;
659  
660     /* C arrays have the first byte at [0], therefore:
661      * [nlen - 1] is the last byte of the array. */
662     size_t last = nlen - 1;
663  
664     /* Then populate it with the analysis of the needle */
665     for (scan = 0; scan < last; scan = scan + 1)
666         bad_char_skip[needle[scan]] = last - scan;
667  
668     /* ---- Do the matching ---- */
669  
670     /* Search the haystack, while the needle can still be within it. */
671     while (hlen >= nlen)
672     {
673         /* scan from the end of the needle */
674         for (scan = last; haystack[scan] == needle[scan]; scan = scan - 1)
675             if (scan == 0) /* If the first byte matches, we've found it. */
676                 return haystack;
677  
678         /* otherwise, we need to skip some bytes and start again. 
679            Note that here we are getting the skip value based on the last byte
680            of needle, no matter where we didn't match. So if needle is: "abcd"
681            then we are skipping based on 'd' and that value will be 4, and
682            for "abcdd" we again skip on 'd' but the value will be only 1.
683            The alternative of pretending that the mismatched character was 
684            the last character is slower in the normal case (Eg. finding 
685            "abcd" in "...azcd..." gives 4 by using 'd' but only 
686            4-2==2 using 'z'. */
687         hlen     -= bad_char_skip[haystack[last]];
688         haystack += bad_char_skip[haystack[last]];
689     }
690  
691     return NULL;
692 }
693 #endif
694
695 #ifdef WIN32
696 /* Source:
697  * https://mollyrocket.com/forums/viewtopic.php?p=2529
698  */
699
700 void *
701 simple_mmap(int fd, unsigned int length, SIMPLE_UNMMAP *un)
702 {
703     HANDLE f;
704     HANDLE m;
705     void *p;
706
707     f = (HANDLE)_get_osfhandle(fd);
708     if (!f) return NULL;
709
710     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
711     if (!m) return NULL;
712
713     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
714     if (!p)
715     {
716         CloseHandle(m);
717         return NULL;
718     }
719
720     if (n) *n = GetFileSize(f, NULL);
721
722     if (un)
723     {
724         un->m = m;
725         un->p = p;
726     }
727
728     return p;
729 }
730
731 void
732 simple_unmmap(SIMPLE_UNMMAP *un)
733 {
734    UnmapViewOfFile(un->p);
735    CloseHandle(un->m);
736 }
737 #endif