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 }