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