gpx2yaml

GPX to YAML converter
git clone git://git.sikmir.ru/gpx2yaml
Log | Files | Refs | README | LICENSE

xml.c (6026B)


      1 #include <ctype.h>
      2 #include <errno.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 
      7 #include "xml.h"
      8 
      9 static void
     10 xml_parseattrs(XMLParser *x)
     11 {
     12 	size_t namelen = 0, valuelen;
     13 	int c, endsep, endname = 0, valuestart = 0;
     14 
     15 	while ((c = GETNEXT()) != EOF) {
     16 		if (isspace(c)) {
     17 			if (namelen)
     18 				endname = 1;
     19 			continue;
     20 		} else if (c == '?')
     21 			; /* ignore */
     22 		else if (c == '=') {
     23 			x->name[namelen] = '\0';
     24 			valuestart = 1;
     25 			endname = 1;
     26 		} else if (namelen && ((endname && !valuestart && isalpha(c)) || (c == '>' || c == '/'))) {
     27 			/* attribute without value */
     28 			x->name[namelen] = '\0';
     29 			if (x->xmlattrstart)
     30 				x->xmlattrstart(x, x->tag, x->taglen, x->name, namelen);
     31 			if (x->xmlattr)
     32 				x->xmlattr(x, x->tag, x->taglen, x->name, namelen, "", 0);
     33 			if (x->xmlattrend)
     34 				x->xmlattrend(x, x->tag, x->taglen, x->name, namelen);
     35 			endname = 0;
     36 			x->name[0] = c;
     37 			namelen = 1;
     38 		} else if (namelen && valuestart) {
     39 			/* attribute with value */
     40 			if (x->xmlattrstart)
     41 				x->xmlattrstart(x, x->tag, x->taglen, x->name, namelen);
     42 
     43 			valuelen = 0;
     44 			if (c == '\'' || c == '"') {
     45 				endsep = c;
     46 			} else {
     47 				endsep = ' '; /* isspace() */
     48 				goto startvalue;
     49 			}
     50 
     51 			while ((c = GETNEXT()) != EOF) {
     52 startvalue:
     53 				if (c == '&') { /* entities */
     54 					x->data[valuelen] = '\0';
     55 					/* call data function with data before entity if there is data */
     56 					if (valuelen && x->xmlattr)
     57 						x->xmlattr(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
     58 					x->data[0] = c;
     59 					valuelen = 1;
     60 					while ((c = GETNEXT()) != EOF) {
     61 						if (c == endsep || (endsep == ' ' && (c == '>' || isspace(c))))
     62 							break;
     63 						if (valuelen < sizeof(x->data) - 1)
     64 							x->data[valuelen++] = c;
     65 						else {
     66 							/* entity too long for buffer, handle as normal data */
     67 							x->data[valuelen] = '\0';
     68 							if (x->xmlattr)
     69 								x->xmlattr(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
     70 							x->data[0] = c;
     71 							valuelen = 1;
     72 							break;
     73 						}
     74 						if (c == ';') {
     75 							x->data[valuelen] = '\0';
     76 							if (x->xmlattrentity)
     77 								x->xmlattrentity(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
     78 							valuelen = 0;
     79 							break;
     80 						}
     81 					}
     82 				} else if (c != endsep && !(endsep == ' ' && (c == '>' || isspace(c)))) {
     83 					if (valuelen < sizeof(x->data) - 1) {
     84 						x->data[valuelen++] = c;
     85 					} else {
     86 						x->data[valuelen] = '\0';
     87 						if (x->xmlattr)
     88 							x->xmlattr(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
     89 						x->data[0] = c;
     90 						valuelen = 1;
     91 					}
     92 				}
     93 				if (c == endsep || (endsep == ' ' && (c == '>' || isspace(c)))) {
     94 					x->data[valuelen] = '\0';
     95 					if (x->xmlattr)
     96 						x->xmlattr(x, x->tag, x->taglen, x->name, namelen, x->data, valuelen);
     97 					if (x->xmlattrend)
     98 						x->xmlattrend(x, x->tag, x->taglen, x->name, namelen);
     99 					break;
    100 				}
    101 			}
    102 			namelen = endname = valuestart = 0;
    103 		} else if (namelen < sizeof(x->name) - 1) {
    104 			x->name[namelen++] = c;
    105 		}
    106 		if (c == '>') {
    107 			break;
    108 		} else if (c == '/') {
    109 			x->isshorttag = 1;
    110 			x->name[0] = '\0';
    111 			namelen = 0;
    112 		}
    113 	}
    114 }
    115 
    116 void
    117 xml_parse(XMLParser *x)
    118 {
    119 	size_t datalen, tagdatalen;
    120 	int c, isend;
    121 
    122 	while ((c = GETNEXT()) != EOF && c != '<')
    123 		; /* skip until < */
    124 
    125 	while (c != EOF) {
    126 		if (c == '<') { /* parse tag */
    127 			if ((c = GETNEXT()) == EOF)
    128 				return;
    129 
    130 			/* normal tag (open, short open, close), processing instruction. */
    131 			x->tag[0] = c;
    132 			x->taglen = 1;
    133 			x->isshorttag = isend = 0;
    134 
    135 			/* treat processing instruction as shorttag, don't strip "?" prefix. */
    136 			if (c == '?') {
    137 				x->isshorttag = 1;
    138 			} else if (c == '/') {
    139 				if ((c = GETNEXT()) == EOF)
    140 					return;
    141 				x->tag[0] = c;
    142 				isend = 1;
    143 			}
    144 
    145 			while ((c = GETNEXT()) != EOF) {
    146 				if (c == '/')
    147 					x->isshorttag = 1; /* short tag */
    148 				else if (c == '>' || isspace(c)) {
    149 					x->tag[x->taglen] = '\0';
    150 					if (isend) { /* end tag, starts with </ */
    151 						if (x->xmltagend)
    152 							x->xmltagend(x, x->tag, x->taglen, x->isshorttag);
    153 						x->tag[0] = '\0';
    154 						x->taglen = 0;
    155 					} else {
    156 						/* start tag */
    157 						if (x->xmltagstart)
    158 							x->xmltagstart(x, x->tag, x->taglen);
    159 						if (isspace(c))
    160 							xml_parseattrs(x);
    161 						if (x->xmltagstartparsed)
    162 							x->xmltagstartparsed(x, x->tag, x->taglen, x->isshorttag);
    163 					}
    164 					/* call tagend for shortform or processing instruction */
    165 					if (x->isshorttag) {
    166 						if (x->xmltagend)
    167 							x->xmltagend(x, x->tag, x->taglen, x->isshorttag);
    168 						x->tag[0] = '\0';
    169 						x->taglen = 0;
    170 					}
    171 					break;
    172 				} else if (x->taglen < sizeof(x->tag) - 1)
    173 					x->tag[x->taglen++] = c; /* NOTE: tag name truncation */
    174 			}
    175 		} else {
    176 			/* parse tag data */
    177 			datalen = 0;
    178 			if (x->xmldatastart)
    179 				x->xmldatastart(x);
    180 			while ((c = GETNEXT()) != EOF) {
    181 				if (c == '&') {
    182 					if (datalen) {
    183 						x->data[datalen] = '\0';
    184 						if (x->xmldata)
    185 							x->xmldata(x, x->data, datalen);
    186 					}
    187 					x->data[0] = c;
    188 					datalen = 1;
    189 					while ((c = GETNEXT()) != EOF) {
    190 						if (c == '<')
    191 							break;
    192 						if (datalen < sizeof(x->data) - 1)
    193 							x->data[datalen++] = c;
    194 						else {
    195 							/* entity too long for buffer, handle as normal data */
    196 							x->data[datalen] = '\0';
    197 							if (x->xmldata)
    198 								x->xmldata(x, x->data, datalen);
    199 							x->data[0] = c;
    200 							datalen = 1;
    201 							break;
    202 						}
    203 						if (c == ';') {
    204 							x->data[datalen] = '\0';
    205 							if (x->xmldataentity)
    206 								x->xmldataentity(x, x->data, datalen);
    207 							datalen = 0;
    208 							break;
    209 						}
    210 					}
    211 				} else if (c != '<') {
    212 					if (datalen < sizeof(x->data) - 1) {
    213 						x->data[datalen++] = c;
    214 					} else {
    215 						x->data[datalen] = '\0';
    216 						if (x->xmldata)
    217 							x->xmldata(x, x->data, datalen);
    218 						x->data[0] = c;
    219 						datalen = 1;
    220 					}
    221 				}
    222 				if (c == '<') {
    223 					x->data[datalen] = '\0';
    224 					if (x->xmldata && datalen)
    225 						x->xmldata(x, x->data, datalen);
    226 					if (x->xmldataend)
    227 						x->xmldataend(x);
    228 					break;
    229 				}
    230 			}
    231 		}
    232 	}
    233 }