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