1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 29 окт. 2019 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <core/debug.h> 23 #include <core/files/xml/PushParser.h> 24 25 namespace lsp 26 { 27 namespace xml 28 { 29 PushParser()30 PushParser::PushParser() 31 { 32 } 33 ~PushParser()34 PushParser::~PushParser() 35 { 36 } 37 drop_list(cvector<LSPString> * list)38 void PushParser::drop_list(cvector<LSPString> *list) 39 { 40 for (size_t i=0, n=list->size(); i<n; ++i) 41 { 42 LSPString *item = list->at(i); 43 if (item != NULL) 44 delete item; 45 } 46 list->clear(); 47 } 48 parse_file(IXMLHandler * handler,const char * path,const char * charset)49 status_t PushParser::parse_file(IXMLHandler *handler, const char *path, const char *charset) 50 { 51 IXMLHandler stub; 52 status_t res = sParser.open(path, charset); 53 if (res == STATUS_OK) 54 res = parse_document((handler != NULL) ? handler : &stub); 55 if (res == STATUS_OK) 56 res = sParser.close(); 57 else 58 sParser.close(); 59 return res; 60 } 61 parse_file(IXMLHandler * handler,const LSPString * path,const char * charset)62 status_t PushParser::parse_file(IXMLHandler *handler, const LSPString *path, const char *charset) 63 { 64 IXMLHandler stub; 65 status_t res = sParser.open(path, charset); 66 if (res == STATUS_OK) 67 res = parse_document((handler != NULL) ? handler : &stub); 68 if (res == STATUS_OK) 69 res = sParser.close(); 70 else 71 sParser.close(); 72 return res; 73 } 74 parse_file(IXMLHandler * handler,const io::Path * path,const char * charset)75 status_t PushParser::parse_file(IXMLHandler *handler, const io::Path *path, const char *charset) 76 { 77 IXMLHandler stub; 78 status_t res = sParser.open(path, charset); 79 if (res == STATUS_OK) 80 res = parse_document((handler != NULL) ? handler : &stub); 81 if (res == STATUS_OK) 82 res = sParser.close(); 83 else 84 sParser.close(); 85 return res; 86 } 87 parse_data(IXMLHandler * handler,io::IInStream * is,size_t flags,const char * charset)88 status_t PushParser::parse_data(IXMLHandler *handler, io::IInStream *is, size_t flags, const char *charset) 89 { 90 IXMLHandler stub; 91 status_t res = sParser.wrap(is, flags, charset); 92 if (res == STATUS_OK) 93 res = parse_document((handler != NULL) ? handler : &stub); 94 if (res == STATUS_OK) 95 res = sParser.close(); 96 else 97 sParser.close(); 98 return res; 99 } 100 parse_data(IXMLHandler * handler,const char * str,const char * charset)101 status_t PushParser::parse_data(IXMLHandler *handler, const char *str, const char *charset) 102 { 103 IXMLHandler stub; 104 status_t res = sParser.wrap(str, charset); 105 if (res == STATUS_OK) 106 res = parse_document((handler != NULL) ? handler : &stub); 107 if (res == STATUS_OK) 108 res = sParser.close(); 109 else 110 sParser.close(); 111 return res; 112 } 113 parse_data(IXMLHandler * handler,const LSPString * str)114 status_t PushParser::parse_data(IXMLHandler *handler, const LSPString *str) 115 { 116 IXMLHandler stub; 117 status_t res = sParser.wrap(str); 118 if (res == STATUS_OK) 119 res = parse_document((handler != NULL) ? handler : &stub); 120 if (res == STATUS_OK) 121 res = sParser.close(); 122 else 123 sParser.close(); 124 return res; 125 } 126 parse_data(IXMLHandler * handler,io::IInSequence * seq,size_t flags)127 status_t PushParser::parse_data(IXMLHandler *handler, io::IInSequence *seq, size_t flags) 128 { 129 IXMLHandler stub; 130 status_t res = sParser.wrap(seq, flags); 131 if (res == STATUS_OK) 132 res = parse_document((handler != NULL) ? handler : &stub); 133 if (res == STATUS_OK) 134 res = sParser.close(); 135 else 136 sParser.close(); 137 return res; 138 } 139 parse_document(IXMLHandler * handler)140 status_t PushParser::parse_document(IXMLHandler *handler) 141 { 142 status_t token, res, last = -1; 143 LSPString tmp, *ptmp; 144 cvector<LSPString> ctag; 145 146 do 147 { 148 // Get next token 149 if ((token = sParser.read_next()) < 0) 150 { 151 res = -token; 152 break; 153 } 154 155 // Is there tag element pending? 156 if ((ctag.size() > 0) && ((token != XT_ATTRIBUTE) && (token != XT_ENTITY_RESOLVE))) 157 { 158 // Add NULL-terminating element 159 if (!ctag.add(NULL)) 160 return STATUS_NO_MEM; 161 162 // Analyze state 163 LSPString **atts = ctag.get_array(); 164 size_t n = ctag.size(); 165 if (n & 1) // Nubmber of elements should be even 166 { 167 res = STATUS_CORRUPTED; 168 break; 169 } 170 171 // Call handler 172 res = handler->start_element(atts[0], &atts[1]); 173 drop_list(&ctag); 174 if (res != STATUS_OK) 175 break; 176 } 177 178 // Dispatch event 179 last = token; 180 switch (token) 181 { 182 case XT_START_DOCUMENT: 183 res = handler->start_document( 184 sParser.xml_version(), 185 sParser.version(), 186 sParser.encoding(), 187 sParser.is_standalone() 188 ); 189 break; 190 191 case XT_END_DOCUMENT: 192 res = handler->end_document(); 193 break; 194 195 case XT_CDATA: 196 res = handler->cdata(sParser.value()); 197 break; 198 199 case XT_CHARACTERS: 200 res = handler->characters(sParser.value()); 201 break; 202 203 case XT_COMMENT: 204 res = handler->comment(sParser.value()); 205 break; 206 207 case XT_ENTITY_RESOLVE: 208 res = handler->resolve(&tmp, sParser.name()); 209 if (res == STATUS_OK) 210 res = sParser.set_value(&tmp); 211 tmp.clear(); 212 break; 213 214 case XT_START_ELEMENT: 215 // Create copy of tag name 216 if ((ptmp = sParser.name()->clone()) == NULL) 217 { 218 res = STATUS_NO_MEM; 219 break; 220 } 221 else if (!ctag.add(ptmp)) 222 { 223 delete ptmp; 224 res = STATUS_NO_MEM; 225 break; 226 } 227 break; 228 229 case XT_ATTRIBUTE: 230 // Create copy of attribute name 231 if ((ptmp = sParser.name()->clone()) == NULL) 232 { 233 res = STATUS_NO_MEM; 234 break; 235 } 236 else if (!ctag.add(ptmp)) 237 { 238 delete ptmp; 239 res = STATUS_NO_MEM; 240 break; 241 } 242 243 // Create copy of tag value 244 if ((ptmp = sParser.value()->clone()) == NULL) 245 { 246 res = STATUS_NO_MEM; 247 break; 248 } 249 else if (!ctag.add(ptmp)) 250 { 251 delete ptmp; 252 res = STATUS_NO_MEM; 253 break; 254 } 255 break; 256 257 case XT_END_ELEMENT: 258 res = handler->end_element(sParser.name()); 259 break; 260 261 case XT_PROCESSING_INSTRUCTION: 262 res = handler->processing(sParser.name(), sParser.value()); 263 break; 264 265 case XT_DTD: 266 res = handler->doctype(sParser.doctype(), sParser.pub_literal(), sParser.sys_literal()); 267 break; 268 269 default: 270 res = STATUS_CORRUPTED; 271 break; 272 } 273 } while (res == STATUS_OK); 274 275 // Drop list 276 drop_list(&ctag); 277 278 // Return result 279 return ((res == STATUS_EOF) && (last == XT_END_DOCUMENT)) ? STATUS_OK : res; 280 } 281 282 } /* namespace xml */ 283 } /* namespace lsp */ 284