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