]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xml.c
Fix bug 150 (airports not found in GPS search)
[flightgear.git] / utils / xmlgrep / xml.c
1 /* Copyright (c) 2007-2009 by Adalin B.V.
2  * Copyright (c) 2007-2009 by Erik Hofman
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *      * Redistributions of source code must retain the above copyright
8  *         notice, this list of conditions and the following disclaimer.
9  *      * Redistributions in binary form must reproduce the above copyright
10  *         notice, this list of conditions and the following disclaimer in the
11  *         documentation and/or other materials provided with the distribution.
12  *      * Neither the name of (any of) the copyrightholder(s) nor the
13  *         names of its contributors may be used to endorse or promote products
14  *         derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #ifdef WIN32
29 # include <io.h>
30
31 #else   /* !WIN32 */
32 # include <sys/mman.h>
33 # include <unistd.h>
34 #endif
35
36 #ifndef NDEBUG
37 # include <stdio.h>
38 #endif
39 #include <stdlib.h>     /* free, malloc */
40 #include <malloc.h>
41 #include <string.h>     /* memcmp */
42 #ifndef _MSC_VER
43 #include <strings.h>    /* strncasecmp */
44 #else
45 # define strncasecmp strnicmp
46 #endif
47 #include <fcntl.h>
48 #include <sys/stat.h>
49 #include <sys/types.h>
50 #include <assert.h>
51 #include <ctype.h>
52
53 #include "xml.h"
54
55 #ifndef XML_NONVALIDATING
56 static const char *__xml_error_str[XML_MAX_ERROR];
57
58 static void __xmlErrorSet(const void *, const char *, unsigned int);
59 # define xmlErrorSet(a, b, c)   __xmlErrorSet(a, b, c)
60
61 # ifndef NDEBUG
62 # define PRINT_INFO(a) \
63         assert((a) < XML_MAX_ERROR); \
64         printf("at line %i: %s\n", __LINE__, __xml_error_str[(a)])
65 # else
66 # define PRINT_INFO(a)
67 # endif
68
69 # define SET_ERROR_AND_RETURN(a, b) \
70        { *rlen = 0; *name = (a); *len = (b); PRINT_INFO(b); return 0; }
71
72 #else /* !XML_NONVALIDATING */
73 # define xmlErrorSet(a, b, c)
74 # define SET_ERROR_AND_RETURN(a, b)     return 0;
75 #endif
76
77 static char *__xmlNodeGetPath(void **, const char *, size_t *, char **, size_t *);
78 static char *__xmlNodeGet(void *, const char *, size_t *, char **, size_t *, size_t *);
79 static char *__xmlProcessCDATA(char **, size_t *);
80 static char *__xmlCommentSkip(const char *, size_t);
81 static char *__xmlInfoProcess(const char *, size_t);
82
83 static void *__xml_memncasecmp(const char *, size_t *, char **, size_t *);
84 static void __xmlPrepareData(char **, size_t *);
85
86 #ifdef WIN32
87 /*
88  * map 'filename' and return a pointer to it.
89  */
90 static void *simple_mmap(int, size_t, SIMPLE_UNMMAP *);
91 static void simple_unmmap(SIMPLE_UNMMAP *);
92
93 # define mmap(a,b,c,d,e,f)       simple_mmap((e), (b), &rid->un)
94 # define munmap(a,b)             simple_unmmap(&rid->un)
95 #endif
96
97 #ifndef NDEBUG
98 # define PRINT(a, b, c) { \
99    size_t l1 = (b), l2 = (c); \
100    char *s = (a); \
101    if (s) { \
102       size_t q, len = l2; \
103       if (l1 < l2) len = l1; \
104       if (len < 50000) { \
105          printf("(%i) '", len); \
106          for (q=0; q<len; q++) printf("%c", s[q]); \
107          printf("'\n"); \
108       } else printf("Length (%u) seems too large at line %i\n",len, __LINE__); \
109    } else printf("NULL pointer at line %i\n", __LINE__); \
110 }
111 #endif
112
113 void *
114 xmlOpen(const char *filename)
115 {
116     struct _root_id *rid = 0;
117
118     if (filename)
119     {
120         int fd = open(filename, O_RDONLY);
121         if (fd >= 0)
122         {
123             struct stat statbuf;
124             void *mm;
125
126             fstat(fd, &statbuf);
127             mm = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0L);
128             if (mm != (void *)-1)
129             {
130                 rid = calloc(1, sizeof(struct _root_id));
131                 if (rid)
132                 {
133                     size_t blen = statbuf.st_size;
134 #ifdef XML_USE_NODECACHE
135                     size_t num = 0, nlen = 1;
136                     char *n = "*";
137
138                     rid->node = cacheInit();
139                     __xmlNodeGet(rid->node, mm, &blen, &n, &nlen, &num);
140 #endif
141                     rid->fd = fd;
142                     rid->start = mm;
143                     rid->len = blen;
144                 }
145             }
146         }
147     }
148
149     return (void *)rid;
150 }
151
152 void *
153 xmlInitBuffer(const char *buffer, size_t size)
154 {
155     struct _root_id *rid = 0;
156
157     if (buffer && (size > 0))
158     {
159         rid = calloc(1, sizeof(struct _root_id));
160         if (rid)
161         {
162 #ifdef XML_USE_NODECACHE
163             size_t num = 0, nlen = 1;
164             size_t blen = size;
165             char *n = "*";
166
167             rid->node = cacheInit();
168             __xmlNodeGet(rid->node, buffer, &blen, &n, &nlen, &num);
169 #endif
170            rid->fd = -1;
171             rid->start = (char *)buffer;
172             rid->len = size;
173         }
174     }
175
176     return (void *)rid;
177 }
178
179 void
180 xmlClose(void *id)
181 {
182      struct _root_id *rid = (struct _root_id *)id;
183
184      assert(rid != 0);
185      assert(rid->name == 0);
186
187      if (rid->fd != -1)
188      {
189          munmap(rid->start, rid->len);
190          close(rid->fd);
191      }
192
193 #ifdef XML_USE_NODECACHE
194      if (rid->node) cacheFree(rid->node);
195 #endif
196 #ifndef XML_NONVALIDATING
197      if (rid->info) free(rid->info);
198 #endif
199      free(rid);
200      id = 0;
201 }
202
203 void *
204 xmlNodeGet(const void *id, const char *path)
205 {
206     struct _xml_id *xid = (struct _xml_id *)id;
207     struct _xml_id *xsid = 0;
208     size_t len, slen;
209     char *ptr, *node;
210     void *nc, *nnc;
211
212     assert(id != 0);
213     assert(path != 0);
214
215     node = (char *)path;
216     len = xid->len;
217     slen = strlen(path);
218
219     nnc = nc = cacheNodeGet(xid);
220     ptr = __xmlNodeGetPath(&nnc, xid->start, &len, &node, &slen);
221     if (ptr)
222     {
223         xsid = malloc(sizeof(struct _xml_id));
224         if (xsid)
225         {
226              xsid->name = node;
227              xsid->name_len = slen;
228              xsid->start = ptr;
229              xsid->len = len;
230 #ifdef XML_USE_NODECACHE
231              xsid->node = nnc;
232 #endif
233 #ifndef XML_NONVALIDATING
234              if (xid->name)
235                 xsid->root = xid->root;
236              else
237                 xsid->root = (struct _root_id *)xid;
238 #endif
239         }
240         else
241         {
242             xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
243         }
244     }
245     else if (slen == 0)
246     {
247         xmlErrorSet(xid, node, len);
248     }
249
250     return (void *)xsid;
251 }
252
253 void *
254 xmlNodeCopy(const void *id, const char *path)
255 {
256     struct _xml_id *xid = (struct _xml_id *)id;
257     struct _xml_id *xsid = 0;
258     char *ptr, *node, *p;
259     size_t slen, len;
260     void *nc, *nnc;
261
262     node = (char *)path;
263     len = xid->len;
264     slen = strlen(path);
265
266     nnc = nc = cacheNodeGet(xid);
267     ptr = __xmlNodeGetPath(&nnc, xid->start, &len, &node, &slen);
268     if (ptr)
269     {
270         xsid = malloc(sizeof(struct _xml_id) + len);
271         if (xsid)
272         {
273             p = (char *)xsid + sizeof(struct _xml_id);
274
275             xsid->len = len;
276             xsid->start = p;
277             xsid->name_len = slen;
278             xsid->name = node;
279 #ifdef XML_USE_NODECACHE
280                  xsid->node = nc;
281 #endif
282 #ifndef XML_NONVALIDATING
283             if (xid->name)
284                 xsid->root = xid->root;
285             else
286                 xsid->root = (struct _root_id *)xid;
287 #endif
288
289             memcpy(xsid->start, ptr, len);
290         }
291         else
292         {
293             xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
294         }
295     }
296     else if (slen == 0)
297     {
298         xmlErrorSet(xid, node, len);
299     }
300
301    return (void *)xsid;
302 }
303
304 char *
305 xmlNodeGetName(const void *id)
306 {
307     struct _xml_id *xid = (struct _xml_id *)id;
308     size_t len;
309     char *ret;
310
311     assert(xid != 0);
312
313     len = xid->name_len;
314     ret = malloc(len+1);
315     if (ret)
316     {
317         memcpy(ret, xid->name, len);
318         *(ret + len) = 0;
319     }
320     else
321     {
322         xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
323     }
324
325     return ret;
326 }
327
328 size_t
329 xmlNodeCopyName(const void *id, char *buf, size_t buflen)
330 {
331     struct _xml_id *xid = (struct _xml_id *)id;
332     size_t slen = 0;
333  
334     assert(buf != 0);
335     assert(buflen > 0);
336
337     slen = xid->name_len;
338     if (slen >= buflen)
339     {
340         slen = buflen-1;
341         xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
342     }
343     memcpy(buf, xid->name, slen);
344     *(buf + slen) = 0;
345
346     return slen;
347 }
348
349 unsigned int
350 xmlNodeGetNum(const void *id, const char *path)
351 {
352     struct _xml_id *xid = (struct _xml_id *)id;
353     size_t num = 0;
354
355     assert(xid != 0);
356     assert(path != 0);
357
358     if (xid->len)
359     {
360         char *nodename, *pathname;
361         size_t len, slen;
362         void *nc;
363         char *p;
364
365         nodename = (char *)path;
366         if (*path == '/') nodename++;
367         slen = strlen(nodename);
368
369         nc = cacheNodeGet(xid);
370         pathname = strchr(nodename, '/');
371         if (pathname)
372         {
373            char *node;
374
375            len = xid->len;
376            pathname++;
377            slen -= pathname-nodename;
378            node = pathname;
379            p = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
380            if (p == 0 && slen == 0)
381            {
382                xmlErrorSet(xid, node, len);
383            }
384         }
385         else
386         {
387             p = xid->start;
388             len = xid->len;
389         }
390
391         if (p)
392         {
393             char *ret, *node = nodename;
394 #ifndef XML_USE_NODECACHE
395             ret = __xmlNodeGet(nc, p, &len, &node, &slen, &num);
396 #else
397             ret = __xmlNodeGetFromCache(&nc, p, &len, &node, &slen, &num);
398 #endif
399             if (ret == 0 && slen == 0)
400             {
401                 xmlErrorSet(xid, node, len);
402                 num = 0;
403             }
404         }
405     }
406
407     return num;
408 }
409
410 void *
411 xmlNodeGetPos(const void *pid, void *id, const char *element, size_t num)
412 {
413     struct _xml_id *xpid = (struct _xml_id *)pid;
414     struct _xml_id *xid = (struct _xml_id *)id;
415     size_t len, slen;
416     char *ptr, *node;
417     void *ret = 0;
418     void *nc;
419
420     assert(xpid != 0);
421     assert(xid != 0);
422     assert(element != 0);
423
424     len = xpid->len;
425     slen = strlen(element);
426     node = (char *)element;
427     nc = cacheNodeGet(xpid);
428 #ifndef XML_USE_NODECACHE
429     ptr = __xmlNodeGet(nc, xpid->start, &len, &node, &slen, &num);
430 #else
431     ptr = __xmlNodeGetFromCache(&nc, xpid->start, &len, &node, &slen, &num);
432 #endif
433     if (ptr)
434     {
435          xid->len = len;
436          xid->start = ptr;
437          xid->name = node;
438          xid->name_len = slen;
439 #ifdef XML_USE_NODECACHE
440          /* unused for the cache but tested at the start of this function */
441          if (len == 0) xid->len = 1;
442          xid->node = nc;
443 #endif
444          ret = xid;
445     }
446     else if (slen == 0)
447     {
448         xmlErrorSet(xpid, node, len);
449     }
450
451     return ret;
452 }
453
454 char *
455 xmlGetString(const void *id)
456 {
457     struct _xml_id *xid = (struct _xml_id *)id;
458     char *str = 0;
459
460     assert(xid != 0);
461
462     if (xid->len)
463     {
464         size_t len;
465         char *ps;
466
467         ps = xid->start;
468         len = xid->len-1;
469         __xmlPrepareData(&ps, &len);
470         if (len)
471         {
472             len++;
473             str = malloc(len+1);
474             if (str)
475             {
476                 memcpy(str, ps, len);
477                 *(str+len) = 0;
478             }
479             else
480             {
481                 xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
482             }
483         }
484     }
485
486     return str;
487 }
488
489 size_t
490 xmlCopyString(const void *id, char *buffer, size_t buflen)
491 {
492     struct _xml_id *xid = (struct _xml_id *)id;
493     size_t ret = 0;
494  
495     assert(xid != 0);
496     assert(buffer != 0);
497     assert(buflen > 0);
498
499     *buffer = '\0';
500     if (xid->len)
501     {
502         size_t len;
503         char *ps;
504
505         ps = xid->start;
506         len = xid->len;
507         __xmlPrepareData(&ps, &len);
508         if (len)
509         {
510             if (len >= buflen)
511             {
512                 len = buflen-1;
513                 xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
514             }
515             memcpy(buffer, ps, len);
516             *(buffer+len) = 0;
517         }
518         ret = len;
519     }
520
521     return ret;
522 }
523
524 int
525 xmlCompareString(const void *id, const char *s)
526 {
527     struct _xml_id *xid = (struct _xml_id *)id;
528     int ret = -1;
529
530     assert(xid != 0);
531     assert(s != 0);
532
533     if (xid->len && (strlen(s) > 0))
534     {
535         size_t len;
536         char *ps;
537
538         ps = xid->start;
539         len = xid->len;
540         __xmlPrepareData(&ps, &len);
541         ret = strncasecmp(ps, s, len);
542     }
543
544     return ret;
545 }
546
547 char *
548 xmlNodeGetString(const void *id, const char *path)
549 {
550     struct _xml_id *xid = (struct _xml_id *)id;
551     char *str = 0;
552
553     assert(xid != 0);
554     assert(path != 0);
555
556     if (xid->len)
557     {
558         char *ptr, *node = (char *)path;
559         size_t slen = strlen(node);
560         size_t len = xid->len;
561         void *nc;
562
563         nc = cacheNodeGet(xid);
564         ptr = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
565         if (ptr && len)
566         {
567             __xmlPrepareData(&ptr, &len);
568             str = malloc(len+1);
569             if (str)
570             {
571                memcpy(str, ptr, len);
572                *(str+len) = '\0';
573             }
574             else
575             {
576                 xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
577             }
578         }
579         else
580         {
581             xmlErrorSet(xid, node, len);
582         }
583     }
584
585     return str;
586 }
587
588 size_t
589 xmlNodeCopyString(const void *id, const char *path, char *buffer, size_t buflen)
590 {
591     struct _xml_id *xid = (struct _xml_id *)id;
592     size_t ret = 0;
593
594     assert(xid != 0);
595     assert(path != 0);
596     assert(buffer != 0);
597     assert(buflen > 0);
598
599     *buffer = '\0';
600     if (xid->len)
601     {
602         char *p, *node = (char *)path;
603         size_t slen = strlen(node);
604         size_t len = xid->len;
605         void *nc;
606
607         nc = cacheNodeGet(xid);
608         p = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
609         if (p)
610         {
611             __xmlPrepareData(&p, &len);
612             if (len)
613             {
614                 if (len >= buflen)
615                 {
616                     len = buflen-1;
617                     xmlErrorSet(xid, 0, XML_TRUNCATE_RESULT);
618                 }
619
620                 memcpy(buffer, p, len);
621                 *(buffer+len) = '\0';
622             }
623             ret = len;
624         }
625         else if (slen == 0)
626         {
627             xmlErrorSet(xid, node, len);
628         }
629     }
630
631     return ret;
632 }
633
634 int
635 xmlNodeCompareString(const void *id, const char *path, const char *s)
636 {
637     struct _xml_id *xid = (struct _xml_id *)id;
638     int ret = -1;
639
640     assert(xid != 0);
641     assert(path != 0);
642     assert(s != 0);
643
644     if (xid->len && (strlen(s) > 0))
645     {
646         char *node, *str, *ps, *pe;
647         size_t len, slen;
648         void *nc;
649
650         len = xid->len;
651         slen = strlen(path);
652         node = (char *)path;
653         nc = cacheNodeGet(xid);
654         str = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
655         if (str)
656         {
657             ps = str;
658             __xmlPrepareData(&ps, &len);
659             ret = strncasecmp(ps, s, len);
660         }
661         else if (slen == 0)
662         {
663             xmlErrorSet(xid, node, len);
664         }
665     }
666
667     return ret;
668 }
669
670 long int
671 xmlGetInt(const void *id)
672 {
673     struct _xml_id *xid = (struct _xml_id *)id;
674     long int li = 0;
675
676     assert(xid != 0);
677
678     if (xid->len)
679     {
680         char *end = xid->start + xid->len;
681         li = strtol(xid->start, &end, 10);
682     }
683
684     return li;
685 }
686
687 long int
688 xmlNodeGetInt(const void *id, const char *path)
689 {
690     struct _xml_id *xid = (struct _xml_id *)id;
691     long int li = 0;
692
693     assert(xid != 0);
694     assert(path != 0);
695
696     if (xid->len)
697     {
698         size_t len, slen;
699         char *str, *node;
700         void *nc;
701
702         len = xid->len;
703         slen = strlen(path);
704         node = (char *)path;
705         nc = cacheNodeGet(xid);
706         str = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
707         if (str)
708         {
709             char *end = str+len;
710             li = strtol(str, &end, 10);
711         }
712         else if (slen == 0)
713         {
714             xmlErrorSet(xid, node, len);
715         }
716     }
717
718     return li;
719 }
720
721 double
722 xmlGetDouble(const void *id)
723 {
724     struct _xml_id *xid = (struct _xml_id *)id;
725     double d = 0.0;
726
727     assert(xid != 0);
728
729     if (xid->len)
730     {
731         char *end = xid->start + xid->len;
732         d = strtod(xid->start, &end);
733     }
734
735     return d;
736 }
737
738 double
739 xmlNodeGetDouble(const void *id, const char *path)
740 {
741     struct _xml_id *xid = (struct _xml_id *)id;
742     double d = 0.0;
743
744     assert(xid != 0);
745     assert(path != 0);
746
747     if (xid->len)
748     {
749         size_t len, slen;
750         char *str, *node;
751         void *nc;
752
753         len = xid->len;
754         slen = strlen(path);
755         node = (char *)path;
756         nc = cacheNodeGet(xid);
757         str = __xmlNodeGetPath(&nc, xid->start, &len, &node, &slen);
758         if (str)
759         {
760             char *end = str+len;
761             d = strtod(str, &end);
762         }
763         else if (slen == 0)
764         {
765             xmlErrorSet(xid, node, len);
766         }
767     }
768
769     return d;
770 }
771
772 void *
773 xmlMarkId(const void *id)
774 {
775     struct _xml_id *xmid = 0;
776
777     assert(id != 0);
778
779     xmid = malloc(sizeof(struct _xml_id));
780     if (xmid)
781     {
782         struct _root_id *xrid = (struct _root_id *)id;
783         if (xrid->name == 0)
784         {
785             xmid->name = "";
786             xmid->name_len = 0;
787             xmid->start = xrid->start;
788             xmid->len = xrid->len;
789 #ifdef XML_USE_NODECACHE
790             xmid->node = xrid->node;
791 #endif
792 #ifndef XML_NONVALIDATING
793             xmid->root = xrid;
794 #endif
795         }
796         else
797         {
798             memcpy(xmid, id, sizeof(struct _xml_id));
799         }
800     }
801     else
802     {
803         xmlErrorSet(id, 0, XML_OUT_OF_MEMORY);
804     }
805
806     return (void *)xmid;
807 }
808
809 double
810 xmlAttributeGetDouble(const void *id, const char *name)
811 {
812     struct _xml_id *xid = (struct _xml_id *)id;
813     double ret = 0.0;
814
815     assert(xid != 0);
816     assert(name != 0);
817
818     if (xid->name_len)
819     {
820         size_t slen = strlen(name);
821         char *ps, *pe;
822
823         assert(xid->start > xid->name);
824
825         ps = xid->name + xid->name_len + 1;
826         pe = xid->start - 1;
827         while (ps<pe)
828         {
829             while ((ps<pe) && isspace(*ps)) ps++;
830             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
831             {
832                 ps += slen;
833                 if ((ps<pe) && (*ps == '='))
834                 {
835                     char *start;
836
837                     ps++;
838                     if (*ps == '"' || *ps == '\'') ps++;
839                     else
840                     {
841                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
842                         return 0;
843                     }
844
845                     start = ps;
846                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
847                     if (ps<pe)
848                     {
849                         ret = strtod(start, &ps);
850                     }
851                     else
852                     {
853                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
854                         return 0;
855                     }
856                 }
857                 else
858                 {
859                     while ((ps<pe) && !isspace(*ps)) ps++;
860                     continue;
861                 }
862
863                 break;
864             }
865
866             while ((ps<pe) && !isspace(*ps)) ps++;
867         }
868     }
869
870     return ret;
871 }
872
873 long int
874 xmlAttributeGetInt(const void *id, const char *name)
875 {
876     struct _xml_id *xid = (struct _xml_id *)id;
877     long int ret = 0;
878
879     assert(xid != 0);
880     assert(name != 0);
881
882     if (xid->name_len)
883     {
884         size_t slen = strlen(name);
885         char *ps, *pe;
886
887         assert(xid->start > xid->name);
888
889         ps = xid->name + xid->name_len + 1;
890         pe = xid->start - 1;
891         while (ps<pe)
892         {
893             while ((ps<pe) && isspace(*ps)) ps++;
894             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
895             {
896                 ps += slen;
897                 if ((ps<pe) && (*ps == '='))
898                 {
899                     char *start;
900
901                     ps++;
902                     if (*ps == '"' || *ps == '\'') ps++;
903                     else
904                     {
905                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
906                         return 0;
907                     }
908
909                     start = ps;
910                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
911                     if (ps<pe)
912                     {
913                         ret = strtol(start, &ps, 10);
914                     }
915                     else
916                     {
917                        xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
918                        return 0;
919                    }
920                }
921                else
922                {
923                    while ((ps<pe) && isspace(*ps)) ps++;
924                    continue;
925                }
926
927                break;
928            }
929
930            while ((ps<pe) && !isspace(*ps)) ps++;
931         }
932     }
933
934     return ret;
935 }
936
937 char *
938 xmlAttributeGetString(const void *id, const char *name)
939 {
940     struct _xml_id *xid = (struct _xml_id *)id;
941     char *ret = 0;
942
943     assert(xid != 0);
944     assert(name != 0);
945
946     if (xid->name_len)
947     {
948         size_t slen = strlen(name);
949         char *ps, *pe;
950
951         assert(xid->start > xid->name);
952
953         ps = xid->name + xid->name_len + 1;
954         pe = xid->start - 1;
955         while (ps<pe)
956         {
957              while ((ps<pe) && isspace(*ps)) ps++;
958              if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
959              {
960                  ps += slen;
961                  if ((ps<pe) && (*ps == '='))
962                  {
963                      char *start;
964
965                      ps++;
966                      if (*ps == '"' || *ps == '\'') ps++;
967                      else
968                      {
969                          xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
970                          return 0;
971                      }
972
973                      start = ps;
974                      while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
975                      if (ps<pe)
976                      {
977                          ret = malloc(ps-start);
978                          if (ret)
979                          {
980                              memcpy(ret, start, (ps-start));
981                              *(ret+(ps-start)) = '\0';
982                          }
983                          else
984                          {
985                              xmlErrorSet(xid, 0, XML_OUT_OF_MEMORY);
986                          }
987                      }
988                      else
989                      {
990                          xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
991                         return 0;
992                      }
993                  }
994                  else
995                  {
996                      while ((ps<pe) && !isspace(*ps)) ps++;
997                      continue;
998                  }
999
1000
1001                  break;
1002              }
1003
1004              while ((ps<pe) && !isspace(*ps)) ps++;
1005         }
1006     }
1007
1008     return ret;
1009 }
1010
1011 size_t
1012 xmlAttributeCopyString(const void *id, const char *name,
1013                                        char *buffer, size_t buflen)
1014 {
1015     struct _xml_id *xid = (struct _xml_id *)id;
1016     size_t ret = 0;
1017
1018     assert(xid != 0);
1019     assert(name != 0);
1020     assert(buffer != 0);
1021     assert(buflen > 0);
1022
1023     if (xid->name_len)
1024     {
1025         size_t slen = strlen(name);
1026         char *ps, *pe;
1027
1028         assert(xid->start > xid->name);
1029
1030         *buffer = '\0';
1031         ps = xid->name + xid->name_len + 1;
1032         pe = xid->start - 1;
1033         while (ps<pe)
1034         {
1035             while ((ps<pe) && isspace(*ps)) ps++;
1036             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
1037             {
1038                 ps += slen;
1039                 if ((ps<pe) && (*ps == '='))
1040                 {
1041                     char *start;
1042
1043                     ps++;
1044                     if (*ps == '"' || *ps == '\'') ps++;
1045                     else
1046                     {
1047                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
1048                         return 0;
1049                     }
1050
1051                     start = ps;
1052                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
1053                     if (ps<pe)
1054                     {
1055                         size_t restlen = ps-start;
1056                         if (restlen >= buflen)
1057                         {
1058                             restlen = buflen-1;
1059                             xmlErrorSet(xid, ps, XML_TRUNCATE_RESULT);
1060                         }
1061
1062                         memcpy(buffer, start, restlen);
1063                         *(buffer+restlen) = 0;
1064                         ret = restlen;
1065                     }
1066                     else
1067                     {
1068                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
1069                         return 0;
1070                     }
1071                 }
1072                 else
1073                 {
1074                     while ((ps<pe) && isspace(*ps)) ps++;
1075                     continue;
1076                 }
1077
1078                 break;
1079             }
1080
1081             while ((ps<pe) && !isspace(*ps)) ps++;
1082         }
1083     }
1084
1085     return ret;
1086 }
1087
1088 int
1089 xmlAttributeCompareString(const void *id, const char *name, const char *s)
1090 {
1091     struct _xml_id *xid = (struct _xml_id *)id;
1092     int ret = -1;
1093  
1094     assert(xid != 0);
1095     assert(name != 0);
1096     assert(s != 0);
1097
1098     if (xid->name_len && strlen(s))
1099     {
1100         size_t slen = strlen(name);
1101         char *ps, *pe;
1102
1103         assert(xid->start > xid->name);
1104
1105         ps = xid->name + xid->name_len + 1;
1106         pe = xid->start - 1;
1107         while (ps<pe)
1108         {
1109             while ((ps<pe) && isspace(*ps)) ps++;
1110             if (((size_t)(pe-ps) > slen) && (strncasecmp(ps, name, slen) == 0))
1111             {
1112                 ps += slen;
1113                 if ((ps<pe) && (*ps == '='))
1114                 {
1115                     char *start;
1116
1117                     ps++;
1118                     if (*ps == '"' || *ps == '\'') ps++;
1119                     else
1120                     {
1121                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_OPENING_QUOTE);
1122                         return 0;
1123                     }
1124
1125                     start = ps;
1126                     while ((ps<pe) && (*ps != '"') && (*ps != '\'')) ps++;
1127                     if (ps<pe)
1128                     {
1129                         ret = strncasecmp(start, s, ps-start);
1130                     }
1131                     else
1132                     {
1133                         xmlErrorSet(xid, ps, XML_ATTRIB_NO_CLOSING_QUOTE);
1134                         return 0;
1135                     }
1136                 }
1137                 else
1138                 {
1139                     while ((ps<pe) && !isspace(*ps)) ps++;
1140                     continue;
1141                 }
1142
1143                 break;
1144             }
1145
1146             while ((ps<pe) && !isspace(*ps)) ps++;
1147         }
1148     }
1149
1150     return ret;
1151 }
1152
1153
1154 #ifndef XML_NONVALIDATING
1155 int
1156 xmlErrorGetNo(const void *id, int clear)
1157 {
1158     int ret = 0;
1159
1160     if (id)
1161     {
1162         struct _xml_id *xid = (struct _xml_id *)id;
1163         struct _root_id *rid;
1164
1165         if (xid->name) rid = xid->root;
1166         else rid = (struct _root_id *)xid;
1167
1168         assert(rid != 0);
1169
1170         if (rid->info)
1171         {
1172             struct _xml_error *err = rid->info;
1173
1174             ret = err->err_no;
1175             if (clear) err->err_no = 0;
1176         }
1177     }
1178
1179     return ret;
1180 }
1181
1182 size_t
1183 xmlErrorGetLineNo(const void *id, int clear)
1184 {
1185     size_t ret = 0;
1186
1187     if (id)
1188     {
1189         struct _xml_id *xid = (struct _xml_id *)id;
1190         struct _root_id *rid;
1191
1192         if (xid->name) rid = xid->root;
1193         else rid = (struct _root_id *)xid;
1194
1195         assert(rid != 0);
1196
1197         if (rid->info)
1198         {
1199             struct _xml_error *err = rid->info;
1200             char *ps = rid->start;
1201             char *pe = err->pos;
1202             char *new;
1203
1204             ret++;
1205             while (ps<pe)
1206             {
1207                new = memchr(ps, '\n', pe-ps);
1208                if (new) ret++;
1209                else break;
1210                ps = new+1;
1211             }       
1212
1213             if (clear) err->err_no = 0;
1214         }
1215     }
1216
1217     return ret;
1218 }
1219
1220 size_t
1221 xmlErrorGetColumnNo(const void *id, int clear)
1222 {
1223     size_t ret = 0;
1224
1225     if (id)
1226     {
1227         struct _xml_id *xid = (struct _xml_id *)id;
1228         struct _root_id *rid;
1229
1230         if (xid->name) rid = xid->root;
1231         else rid = (struct _root_id *)xid;
1232
1233         assert(rid != 0);
1234
1235         if (rid->info)
1236         {
1237             struct _xml_error *err = rid->info;
1238             char *ps = rid->start;
1239             char *pe = err->pos;
1240             char *new;
1241
1242             while (ps<pe)
1243             {
1244                new = memchr(ps, '\n', pe-ps);
1245                new = memchr(ps, '\n', pe-ps);
1246                if (new) ret++;
1247                else break;
1248                ps = new+1;
1249             }
1250             ret = pe-ps;
1251
1252             if (clear) err->err_no = 0;
1253         }
1254     }
1255
1256     return ret;
1257 }
1258
1259 const char *
1260 xmlErrorGetString(const void *id, int clear)
1261 {
1262     char *ret = 0;
1263
1264     if (id)
1265     {
1266         struct _xml_id *xid = (struct _xml_id *)id;
1267         struct _root_id *rid;
1268
1269         if (xid->name) rid = xid->root;
1270         else rid = (struct _root_id *)xid;
1271
1272         assert(rid != 0);
1273
1274         if (rid->info)
1275         {
1276             struct _xml_error *err = rid->info;
1277             if (XML_NO_ERROR <= err->err_no && err->err_no < XML_MAX_ERROR)
1278             {
1279                ret = (char *)__xml_error_str[err->err_no];
1280             }
1281             else
1282             {
1283                ret = "incorrect error number.";
1284             }
1285
1286             if (clear) err->err_no = 0;
1287         }
1288     }
1289
1290     return ret;
1291 }
1292
1293 #else
1294
1295 int
1296 xmlErrorGetNo(const void *id, int clear)
1297 {
1298     return XML_NO_ERROR;
1299 }
1300
1301 size_t
1302 xmlErrorGetLineNo(const void *id, int clear)
1303 {
1304     return 0;
1305 }
1306
1307 size_t
1308 xmlErrorGetColumnNo(const void *id, int clear)
1309 {
1310     return 0;
1311 }
1312
1313 const char *
1314 xmlErrorGetString(const void *id, int clear)
1315 {
1316    return "error detection was not enabled at compile time: no error.";
1317 }
1318
1319 #endif
1320
1321 /* -------------------------------------------------------------------------- */
1322
1323 #ifndef XML_NONVALIDATING
1324 static const char *__xml_error_str[XML_MAX_ERROR] =
1325 {
1326     "no error.",
1327     "unable to allocate enough memory.",
1328     "unable to open file for reading.",
1329     "requested node name is invalid.",
1330     "unexpected end of section.",
1331     "buffer too small to hold all data, truncating.",
1332     "incorrect comment section.",
1333     "bad information block.",
1334     "incompatible opening tag for element.",
1335     "missing or invalid closing tag for element.",
1336     "missing or invalid opening quote for attribute.",
1337     "missing or invalid closing quote for attribute."
1338 };
1339 #endif
1340
1341 char *
1342 __xmlNodeGetPath(void **nc, const char *start, size_t *len, char **name, size_t *nlen)
1343 {
1344     char *path;
1345     char *ret = 0;
1346
1347     assert(start != 0);
1348     assert(len != 0);
1349     assert(name != 0);
1350     assert(*name != 0);
1351     assert(nlen != 0);
1352
1353     path = *name;
1354     if (*path == '/') path++;
1355     if (*path != '\0')
1356     {
1357         size_t num, blocklen, pathlen, nodelen;
1358         char *node;
1359
1360         node = path;
1361         pathlen = strlen(path);
1362         path = strchr(node, '/');
1363
1364         if (!path) nodelen = pathlen;
1365         else nodelen = path++ - node;
1366
1367         num = 0;
1368         blocklen = *len;
1369
1370 #ifndef XML_USE_NODECACHE
1371         ret = __xmlNodeGet(nc, start, &blocklen, &node, &nodelen, &num);
1372 #else
1373         ret = __xmlNodeGetFromCache(nc, start, &blocklen, &node, &nodelen, &num);
1374 #endif
1375         if (ret)
1376         {
1377             if (path)
1378             {
1379                 ret = __xmlNodeGetPath(nc, ret, &blocklen, &path, &pathlen);
1380                 *name = path;
1381                 *len = blocklen;
1382                 *nlen = pathlen;
1383             }
1384             else
1385             {
1386                *name = node;
1387                *nlen = nodelen;
1388                *len = blocklen;
1389             }
1390         }
1391         else
1392         {
1393             *len = 0;
1394             *nlen = 0;
1395         }
1396     }
1397
1398     return ret;
1399 }
1400
1401 char *
1402 __xmlNodeGet(void *nc, const char *start, size_t *len, char **name, size_t *rlen, size_t *nodenum)
1403 {
1404     char *cdata, *open_element = *name;
1405     char *element, *start_tag=0;
1406     char *new, *cur, *ne, *ret = 0;
1407     size_t restlen, elementlen;
1408     size_t open_len = *rlen;
1409     size_t return_len = 0;
1410     int found, num;
1411     void *nnc = 0;
1412
1413     assert(start != 0);
1414     assert(len != 0);
1415     assert(name != 0);
1416     assert(rlen != 0);
1417     assert(nodenum != 0);
1418
1419     if (open_len == 0 || *name == 0)
1420         SET_ERROR_AND_RETURN((char *)start, XML_INVALID_NODE_NAME);
1421
1422     cdata = (char *)start;
1423     if (*rlen > *len)
1424         SET_ERROR_AND_RETURN((char *)start, XML_UNEXPECTED_EOF);
1425
1426     found = 0;
1427     num = *nodenum;
1428     restlen = *len;
1429     cur = (char *)start;
1430     ne = cur + restlen;
1431
1432 #ifdef XML_USE_NODECACHE
1433     cacheInitLevel(nc);
1434 #endif
1435
1436     /* search for an opening tag */
1437     while ((new = memchr(cur, '<', restlen)) != 0)
1438     {
1439         size_t len_remaining;
1440         char *rptr;
1441
1442         if (*(new+1) == '/')            /* end of section */
1443         {
1444             *len -= restlen;
1445              break;
1446         }
1447
1448         new++;
1449         restlen -= new-cur;
1450         cur = new;
1451
1452         if (*cur == '!') /* comment */
1453         {
1454             char *start = cur;
1455             size_t blocklen = restlen;
1456             new = __xmlProcessCDATA(&start, &blocklen);
1457             if (!new && start && open_len)                       /* CDATA */
1458                 SET_ERROR_AND_RETURN(cur, XML_INVALID_COMMENT);
1459
1460             restlen -= new-cur;
1461             cur = new;
1462             continue;
1463         }
1464         else if (*cur == '?') /* info block */
1465         {
1466             new = __xmlInfoProcess(cur, restlen);
1467             if (!new)
1468                 SET_ERROR_AND_RETURN(cur, XML_INVALID_INFO_BLOCK);
1469
1470             restlen -= new-cur;
1471             cur = new;
1472             continue;
1473         }
1474
1475         /*
1476          * get element name and a pointer to after the opening tag
1477          */
1478         element = *name;
1479         elementlen = *rlen;
1480         len_remaining = restlen;
1481         rptr = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
1482         if (rptr)                       /* requested element was found */
1483         {
1484             new = rptr;
1485             return_len = elementlen;
1486             if (found == num)
1487             {
1488                 ret = new;
1489                 open_len = elementlen;
1490                 start_tag = element;
1491             }
1492             else start_tag = 0;
1493         }
1494         else                            /* different element name was foud */
1495         {
1496             new = cur + (len_remaining - restlen);
1497             if (new >= ne)
1498                 SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
1499
1500             element = *name;
1501         }
1502
1503 #ifdef XML_USE_NODECACHE
1504         nnc = cacheNodeNew(nc);
1505 #endif
1506
1507         if (*(new-2) == '/')                            /* e.g. <test/> */
1508         {
1509             cur = new;
1510             if (rptr)
1511             {
1512 #ifdef XML_USE_NODECACHE
1513                 cacheDataSet(nnc, element, elementlen, rptr, 0);
1514 #endif
1515                 if (found == num)
1516                 {
1517                     open_element = start_tag;
1518                     *len = 0;
1519                 }
1520                 found++;
1521             }
1522             continue;
1523         }
1524
1525         /*
1526          * get the next xml tag
1527          */
1528         /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
1529         cur = new;
1530         new = memchr(cur, '<', restlen);
1531         if (!new)
1532             SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1533
1534         new++;
1535         restlen -= new-cur;
1536         cur = new;
1537         if (*cur == '!')                                /* comment, CDATA */
1538         {
1539             char *start = cur;
1540             size_t blocklen = restlen;
1541             new = __xmlProcessCDATA(&start, &blocklen);
1542             if (new && start && open_len)                       /* CDATA */
1543             {
1544                 cdata = ret;
1545             }
1546             else if (!new)
1547                 SET_ERROR_AND_RETURN(cur, XML_INVALID_COMMENT);
1548
1549             restlen -= new-cur;
1550             cur = new;
1551
1552             /*
1553              * look for the closing tag of the cascading block
1554              */
1555             new = memchr(cur, '<', restlen);
1556             if (!new)
1557                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1558
1559             new++;
1560             restlen -= new-cur;
1561             cur = new;
1562         }
1563
1564         if (*cur == '/')                /* closing tag of leaf node found */
1565         {
1566             if (!strncasecmp(new+1, element, elementlen))
1567             {
1568 #ifdef XML_USE_NODECACHE
1569                 cacheDataSet(nnc, element, elementlen, rptr, new-rptr-1);
1570 #endif
1571                 if (*(new+elementlen+1) != '>')
1572                     SET_ERROR_AND_RETURN(new+1, XML_ELEMENT_NO_CLOSING_TAG);
1573
1574                 if (found == num)
1575                 {
1576                     if (start_tag)
1577                     {
1578                         *len = new-ret-1;
1579                         open_element = start_tag;
1580                         cdata = (char *)start;
1581                         start_tag = 0;
1582                     }
1583                     else /* report error */
1584                         SET_ERROR_AND_RETURN(new, XML_ELEMENT_NO_OPENING_TAG);
1585                 }
1586                 found++;
1587             }
1588
1589             new = memchr(cur, '>', restlen);
1590             if (!new)
1591                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1592
1593             restlen -= new-cur;
1594             cur = new;
1595             continue;
1596         }
1597
1598         /* no leaf node, continue */
1599         if (*cur != '/')                        /* cascading tag found */
1600         {
1601             char *node = "*";
1602             size_t slen = restlen+1; /* due to cur-1 below*/
1603             size_t nlen = 1;
1604             size_t pos = -1;
1605
1606             /*
1607              * recursively walk the xml tree from here
1608              */
1609             new = __xmlNodeGet(nnc, cur-1, &slen, &node, &nlen, &pos);
1610             if (!new)
1611             {
1612                 if (nlen == 0)          /* error upstream */
1613                 {
1614                     *rlen = nlen;
1615                     *name = node;
1616                     *len = slen;
1617                     return 0;
1618                 }
1619
1620                 if (slen == restlen)
1621                     SET_ERROR_AND_RETURN(cur, XML_UNEXPECTED_EOF);
1622
1623                 slen--;
1624                 new = cur + slen;
1625                 restlen -= slen;
1626             }
1627             else restlen -= slen;
1628
1629             /* 
1630              * look for the closing tag of the cascading block
1631              */
1632             cur = new;
1633             new = memchr(cur, '<', restlen);
1634             if (!new)
1635                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1636
1637             new++;
1638             restlen -= new-cur;
1639             cur = new;
1640         }
1641
1642         if (*cur == '/')                                /* closing tag found */
1643         {
1644             if (!strncasecmp(new+1, element, elementlen))
1645             {
1646                 if (*(new+elementlen+1) != '>')
1647                     SET_ERROR_AND_RETURN(new+1, XML_ELEMENT_NO_CLOSING_TAG);
1648
1649 #ifdef XML_USE_NODECACHE
1650                 cacheDataSet(nnc, element, elementlen, rptr, new-rptr-1);
1651 #endif
1652                 if (found == num)
1653                 {
1654                     if (start_tag)
1655                     {
1656                         *len = new-ret-1;
1657                         open_element = start_tag;
1658                         cdata = (char *)start;
1659                         start_tag = 0;
1660                     }
1661                     else /* report error */
1662                         SET_ERROR_AND_RETURN(new, XML_ELEMENT_NO_OPENING_TAG);
1663                 }
1664                 found++;
1665             }
1666
1667             new = memchr(cur, '>', restlen);
1668             if (!new)
1669                 SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1670
1671             restlen -= new-cur;
1672             cur = new;
1673         }
1674         else
1675             SET_ERROR_AND_RETURN(cur, XML_ELEMENT_NO_CLOSING_TAG);
1676
1677     } /* while */
1678
1679     if (found == 0)
1680     {
1681         ret = 0;
1682         *rlen = 0;
1683         *name = start_tag;
1684         *len = XML_NO_ERROR;    /* element not found, no real error */
1685     }
1686     else
1687     {
1688         *rlen = open_len;
1689         *name = open_element;
1690         *nodenum = found;
1691     }
1692
1693     return ret;
1694 }
1695
1696 char *
1697 __xmlProcessCDATA(char **start, size_t *len)
1698 {
1699     char *cur, *new;
1700     size_t restlen = *len;
1701
1702     cur = *start;
1703     if ((restlen > 6) && (*(cur+1) == '-'))             /* comment */
1704     {
1705         new = __xmlCommentSkip(cur, restlen);
1706         if (new)
1707         {
1708             *start = new;
1709             *len = 0;
1710         }
1711         return new;
1712     }
1713
1714     if (restlen < 12) return 0;                         /* ![CDATA[ ]]> */
1715
1716     cur = *start;
1717     new = 0;
1718
1719     if (memcmp(cur, "![CDATA[", 8) == 0)
1720     {
1721         *start = cur+8;
1722         cur += 8;
1723         restlen -= 8;
1724         do
1725         {
1726             new = memchr(cur, ']', restlen);
1727             if (new)
1728             {
1729                 if ((restlen > 3) && (memcmp(new, "]]>", 3) == 0))
1730                 {
1731                     *len = new-1 - *start;
1732                     restlen -= 3;
1733                     new += 3;
1734                     break;
1735                 }
1736                 cur = new+1;
1737             }
1738             else
1739             {
1740                 *len = 0;
1741                 break;
1742             }
1743         }
1744         while (new && (restlen > 2));
1745     }
1746
1747     return new;
1748 }
1749
1750 char *
1751 __xmlCommentSkip(const char *start, size_t len)
1752 {
1753     char *cur, *new;
1754
1755     if (len < 7) return 0;                               /* !-- --> */
1756
1757     cur = (char *)start;
1758     new = 0;
1759
1760     if (memcmp(cur, "!--", 3) == 0)
1761     {
1762         cur += 3;
1763         len -= 3;
1764         do
1765         {
1766             new = memchr(cur, '-', len);
1767             if (new)
1768             {
1769                 len -= new-cur;
1770                 if ((len >= 3) && (memcmp(new, "-->", 3) == 0))
1771                 {
1772                     new += 3;
1773                     /* len -= 3; */
1774                     break;
1775                 }
1776                 cur = new+1;
1777                 len -= cur-new;
1778             }
1779             else break;
1780         }
1781         while (new && (len > 2));
1782     }
1783
1784     return new;
1785 }
1786
1787 char *
1788 __xmlInfoProcess(const char *start, size_t len)
1789 {
1790     char *cur, *new;
1791
1792     cur = (char *)start;
1793     new = 0;
1794
1795     if (*cur == '?')
1796     {
1797         if (len < 3) return 0;                          /* <? ?> */
1798
1799         cur++;
1800         len--;
1801         new = memchr(cur, '?', len);
1802         if (!new || *(new+1) != '>') return 0;
1803
1804         new += 2;
1805     }
1806
1807     return new;
1808 }
1809
1810
1811 static void
1812 __xmlPrepareData(char **start, size_t *blocklen)
1813 {
1814     size_t len = *blocklen;
1815     char *pe, *ps = *start;
1816
1817     if (len > 1)
1818     {
1819         pe = ps + len-1;
1820         while ((ps<pe) && isspace(*ps)) ps++;
1821         while ((pe>ps) && isspace(*pe)) pe--;
1822         len = (pe-ps)+1;
1823     }
1824     else if (isspace(*(ps+1))) len--;
1825
1826     /* CDATA or comment */
1827     if ((len >= 2) && !strncmp(ps, "<!", 2))
1828     {
1829         char *start = ps+1;
1830         size_t blocklen = len-1;
1831         if (blocklen >= 6)                  /* !-- --> */
1832         {
1833             char *new = __xmlProcessCDATA(&start, &len);
1834             if (new)
1835             {
1836                 ps = start;
1837                 pe = ps + len;
1838
1839                 while ((ps<pe) && isspace(*ps)) ps++;
1840                 while ((pe>ps) && isspace(*pe)) pe--;
1841                 len = (pe-ps);
1842             }
1843         }
1844     }
1845
1846     *start = ps;
1847     *blocklen = len;
1848 }
1849
1850 #define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
1851 void *
1852 __xml_memncasecmp(const char *haystack, size_t *haystacklen,
1853                   char **needle, size_t *needlelen)
1854 {
1855     char *rptr = 0;
1856
1857     if (haystack && needle && needlelen && (*needlelen > 0)
1858         && (*haystacklen >= *needlelen))
1859     {
1860         char *hs = (char *)haystack;
1861         char *ns;
1862         size_t i;
1863
1864         ns = *needle;
1865
1866         /* search for everything */
1867         if ((*ns == '*') && (*needlelen == 1))
1868         {
1869            char *he = hs + *haystacklen;
1870
1871            while ((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1872            if (*(hs-1) == '/') hs--;
1873
1874            *needle = (char *)haystack;
1875            *needlelen = hs - haystack;
1876
1877            ns = memchr(hs, '>', he-hs);
1878            if (ns) hs = ns+1;
1879            else hs = he;
1880      
1881            rptr = hs;
1882         }
1883         else
1884         {
1885             size_t nlen = *needlelen;
1886             char *he = hs + *haystacklen;
1887
1888             for (i=0; i<nlen; i++)
1889             {
1890                 if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
1891                 if (isspace(*hs) || (*hs == '/') || (*hs == '>')) break;
1892                 hs++;
1893                 ns++;
1894             }
1895
1896             if (i == nlen)
1897             {
1898                 *needle = (char *)haystack;
1899                 *needlelen = hs - haystack;
1900
1901                 ns = memchr(hs, '>', he-hs);
1902                 if (ns) hs = ns+1;
1903                 else hs = he;
1904
1905                 rptr = hs;
1906             }
1907             else /* not found */
1908             {
1909                 while((hs < he) && !isspace(*hs) && (*hs != '>')) hs++;
1910                 if (*(hs-1) == '/') hs--;
1911
1912                 *needle = (char *)haystack;
1913                 *needlelen = hs - haystack;
1914
1915                 ns = memchr(hs, '>', he-hs);
1916                 if (ns) hs = ns+1;
1917                 else hs = he;
1918             }
1919         }
1920
1921         *haystacklen -= hs - haystack;
1922     }
1923
1924     return rptr;
1925 }
1926
1927 #ifndef XML_NONVALIDATING
1928 void
1929 __xmlErrorSet(const void *id, const char *pos, unsigned int err_no)
1930 {
1931    struct _xml_id *xid = (struct _xml_id *)id;
1932    struct _root_id *rid;
1933
1934    assert(xid != 0);
1935
1936    if (xid->name) rid = xid->root;
1937    else rid = (struct _root_id *)xid;
1938
1939    assert(rid != 0);
1940    if (rid->info == 0)
1941    {
1942       rid->info = malloc(sizeof(struct _xml_error));
1943    }
1944
1945    if (rid->info)
1946    {
1947       struct _xml_error *err = rid->info;
1948
1949       err->pos = (char *)pos;
1950       err->err_no = err_no;
1951    }
1952 }
1953 #endif
1954
1955 #ifdef WIN32
1956 /* Source:
1957  * https://mollyrocket.com/forums/viewtopic.php?p=2529
1958  */
1959
1960 void *
1961 simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
1962 {
1963     HANDLE f;
1964     HANDLE m;
1965     void *p;
1966
1967     f = (HANDLE)_get_osfhandle(fd);
1968     if (!f) return (void *)-1;
1969
1970     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
1971     if (!m) return (void *)-1;
1972
1973     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
1974     if (!p)
1975     {
1976         CloseHandle(m);
1977         return (void *)-1;
1978     }
1979
1980     if (un)
1981     {
1982         un->m = m;
1983         un->p = p;
1984     }
1985
1986     return p;
1987 }
1988
1989 void
1990 simple_unmmap(SIMPLE_UNMMAP *un)
1991 {
1992     UnmapViewOfFile(un->p);
1993     CloseHandle(un->m);
1994 }
1995 #endif