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