00001 00002 // 00003 // XML storage C++ classes version 1.5 00004 // 00005 // Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Martin Fuchs <martin-fuchs@gmx.net> 00006 // 00007 00008 /// \file xs-native.cpp 00009 /// native internal XMLStorage parser 00010 00011 00012 /* 00013 00014 All rights reserved. 00015 00016 Redistribution and use in source and binary forms, with or without 00017 modification, are permitted provided that the following conditions are met: 00018 00019 * Redistributions of source code must retain the above copyright 00020 notice, this list of conditions and the following disclaimer. 00021 * Redistributions in binary form must reproduce the above copyright 00022 notice, this list of conditions and the following disclaimer in 00023 the documentation and/or other materials provided with the 00024 distribution. 00025 00026 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00027 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00028 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00029 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00030 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00031 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00032 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00033 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00034 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00035 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00036 POSSIBILITY OF SUCH DAMAGE. 00037 00038 */ 00039 00040 #ifndef XS_NO_COMMENT 00041 #define XS_NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files to enable static linking 00042 #endif 00043 00044 #include "xmlstorage.h" 00045 00046 00047 #if !defined(XS_USE_EXPAT) && !defined(XS_USE_XERCES) 00048 00049 namespace XMLStorage { 00050 00051 00052 XMLReaderBase::~XMLReaderBase() 00053 { 00054 } 00055 00056 /// read XML stream into XML tree below _pos 00057 void XMLReaderBase::read() 00058 { 00059 if (!parse()) { 00060 XMLError error("XML parsing error"); 00061 //error._line = ; 00062 //error._column = ; 00063 00064 _errors.push_back(error); 00065 } 00066 00067 finish_read(); 00068 } 00069 00070 00071 /// line buffer for XS-native parser 00072 00073 ReadBuffer::ReadBuffer(XMLErrorList& errors, XMLLocation& location) 00074 : _errors(errors), 00075 _location(location) 00076 { 00077 _buffer = (char*) malloc(BUFFER_LEN); 00078 _len = BUFFER_LEN; 00079 00080 reset(); 00081 } 00082 00083 ReadBuffer::~ReadBuffer() 00084 { 00085 free(_buffer); 00086 } 00087 00088 void ReadBuffer::reset() 00089 { 00090 _wptr = _buffer; 00091 _buffer_str.erase(); 00092 } 00093 00094 void ReadBuffer::append(int c) 00095 { 00096 size_t wpos = _wptr-_buffer; 00097 00098 if (wpos >= _len) { 00099 _len <<= 1; 00100 _buffer = (char*) realloc(_buffer, _len); 00101 _wptr = _buffer + wpos; 00102 } 00103 00104 *_wptr++ = static_cast<char>(c); 00105 } 00106 00107 const std::string& ReadBuffer::str(bool utf8) // returns UTF-8 encoded buffer content 00108 { 00109 #if defined(_WIN32) && !defined(XS_STRING_UTF8) 00110 if (utf8) 00111 #endif 00112 _buffer_str.assign(_buffer, _wptr-_buffer); 00113 #if defined(_WIN32) && !defined(XS_STRING_UTF8) 00114 else 00115 _buffer_str = get_utf8(_buffer, _wptr-_buffer); 00116 #endif 00117 00118 return _buffer_str; 00119 } 00120 00121 size_t ReadBuffer::len() const 00122 { 00123 return _wptr - _buffer; 00124 } 00125 00126 bool ReadBuffer::has_CDEnd() const 00127 { 00128 //if (_wptr-_buffer < 3) 00129 // return false; 00130 00131 return !strncmp(_wptr-3, CDATA_END, 3); 00132 } 00133 00134 XS_String ReadBuffer::get_tag() const 00135 { 00136 const char* p = _buffer_str.c_str(); 00137 00138 if (*p == '<') 00139 ++p; 00140 00141 if (*p == '/') 00142 ++p; 00143 00144 const char* q = p; 00145 00146 if (*q == '?') 00147 ++q; 00148 00149 q = get_xmlsym_end_utf8(q); 00150 00151 #ifdef XS_STRING_UTF8 00152 return XS_String(p, q-p); 00153 #else 00154 return from_utf8(p, q-p); 00155 #endif 00156 } 00157 00158 /// read attributes and values 00159 void ReadBuffer::get_attributes(XMLNode::AttributeMap& attributes) const 00160 { 00161 const char* p = _buffer_str.c_str(); 00162 00163 // find end of tag name 00164 if (*p == '<') 00165 ++p; 00166 00167 if (*p == '/') 00168 ++p; 00169 else if (*p == '?') 00170 ++p; 00171 00172 p = get_xmlsym_end_utf8(p); 00173 00174 // read attributes from buffer 00175 while(*p && *p!='>' && *p!='/') { 00176 while(isspace((unsigned char)*p)) 00177 ++p; 00178 00179 if (*p=='?' || *p=='/') 00180 break; 00181 00182 const char* attr_name = p; 00183 00184 p = get_xmlsym_end_utf8(p); 00185 00186 if (*p != '=') { 00187 _errors.push_back(XMLError(_location, "missing attribute assignment")); 00188 break; 00189 } 00190 00191 size_t attr_len = p - attr_name; 00192 00193 if (*++p!='"' && *p!='\'') { 00194 _errors.push_back(XMLError(_location, "missing attribute value quote")); 00195 break; 00196 } 00197 00198 char delim = *p; 00199 const char* value = ++p; 00200 00201 while(*p && *p!=delim) 00202 ++p; 00203 00204 size_t value_len = p - value; 00205 00206 if (*p) 00207 ++p; // '"' oder '\'' 00208 else 00209 _errors.push_back(XMLError(_location, "unterminated attribute quote")); 00210 00211 #ifdef XS_STRING_UTF8 00212 XS_String name_str(attr_name, attr_len); 00213 #else 00214 XS_String name_str; 00215 assign_utf8(name_str, attr_name, attr_len); 00216 #endif 00217 00218 attributes[name_str] = DecodeXMLString(std::string(value, value_len)); 00219 } 00220 } 00221 00222 00223 ParseContext::ParseContext(XMLReaderBase& reader) 00224 : _reader(reader), 00225 _buffer(reader._errors, reader._location), 00226 _utf8(false) 00227 { 00228 _next = reader.get(); 00229 _in_comment = false; 00230 00231 // check for UTF-8 signature 00232 read_bom(); 00233 } 00234 00235 void ParseContext::read_bom() 00236 { 00237 if (_next == 0xEF) { 00238 _next = _reader.get(); 00239 00240 if (_next == 0xBB) { 00241 _next = _reader.get(); 00242 00243 if (_next == 0xBF) { 00244 _utf8 = true; 00245 _reader._format._utf8_bom = true; 00246 00247 _next = _reader.get(); 00248 } 00249 } 00250 } 00251 } 00252 00253 bool ParseContext::proceed() 00254 { 00255 if (_next != EOF) 00256 _next = process_next(_next); 00257 00258 return _next != EOF; 00259 } 00260 00261 int ParseContext::process_next(int c) 00262 { 00263 if (_in_comment || c=='<') { 00264 if (!_buffer.empty()) 00265 _buffer.reset(); 00266 00267 _buffer.append(c); 00268 00269 // read start or end tag 00270 for(;;) { 00271 c = _reader.get(); 00272 00273 if (c == EOF) 00274 break; 00275 00276 _buffer.append(c); 00277 00278 if (c == '>') 00279 break; 00280 } 00281 00282 const std::string& b = _buffer.str(_utf8); 00283 const char* str = b.c_str(); 00284 00285 if (_in_comment || !strncmp(str+1, "!--", 3)) { 00286 // XML comment 00287 _reader.DefaultHandler(b); 00288 00289 if (strcmp(str+b.length()-3, "-->")) 00290 _in_comment = true; 00291 else 00292 _in_comment = false; 00293 00294 c = _reader.get(); 00295 } else if (str[1] == '/') { 00296 // end tag 00297 00298 /*@TODO error handling 00299 const XS_String& tag = buffer.get_tag(); 00300 00301 if (tag != last_opened_tag) { 00302 ERROR 00303 } 00304 */ 00305 00306 _reader.EndElementHandler(); 00307 00308 c = _reader.get(); 00309 } else if (str[1] == '?') { 00310 // XML declaration 00311 const XS_String& tag = _buffer.get_tag(); 00312 00313 if (tag == "?xml") { 00314 XMLNode::AttributeMap attributes; 00315 _buffer.get_attributes(attributes); 00316 00317 const std::string& version = attributes.get("version"); 00318 const std::string& encoding = attributes.get("encoding"); 00319 00320 int standalone; 00321 XMLNode::AttributeMap::const_iterator found = // const_cast for ISO C++ compatibility error of GCC 00322 const_cast<const XMLNode::AttributeMap&>(attributes).find("standalone"); 00323 if (found != attributes.end()) 00324 standalone = !XS_icmp(found->second.c_str(), XS_TEXT("yes")); 00325 else 00326 standalone = -1; 00327 00328 _reader.XmlDeclHandler(version.empty()?NULL:version.c_str(), encoding.empty()?NULL:encoding.c_str(), standalone); 00329 00330 if (!encoding.empty()) { 00331 if (!_stricmp(encoding.c_str(), "utf-8")) 00332 _utf8 = true; 00333 else 00334 assert(!_reader._format._utf8_bom); // mismatch between BOM and xml header 00335 } 00336 00337 c = _reader.eat_endl(); 00338 } else if (tag == "?xml-stylesheet") { 00339 XMLNode::AttributeMap attributes; 00340 _buffer.get_attributes(attributes); 00341 00342 StyleSheet stylesheet(attributes.get("href"), attributes.get("type"), !XS_icmp(attributes.get("alternate"), XS_TEXT("yes"))); 00343 stylesheet._title = attributes.get("title"); 00344 stylesheet._media = attributes.get("media"); 00345 stylesheet._charset = attributes.get("charset"); 00346 00347 _reader._format._stylesheets.push_back(stylesheet); 00348 00349 c = _reader.eat_endl(); 00350 } else { 00351 _reader.DefaultHandler(b); 00352 c = _reader.get(); 00353 } 00354 } else if (str[1] == '!') { 00355 if (!strncmp(str+2, "DOCTYPE ", 8)) { 00356 _reader._format._doctype.parse(str+10); 00357 00358 c = _reader.eat_endl(); 00359 } else if (!strncmp(str+2, "[CDATA[", 7)) { // see CDATA_START 00360 // parse <![CDATA[ ... ]]> strings 00361 while(!_buffer.has_CDEnd()) { 00362 c = _reader.get(); 00363 00364 if (c == EOF) 00365 break; 00366 00367 _buffer.append(c); 00368 } 00369 00370 _reader.DefaultHandler(_buffer.str(_utf8)); 00371 00372 c = _reader.get(); 00373 } 00374 } else { 00375 // start tag 00376 const XS_String& tag = _buffer.get_tag(); 00377 00378 if (!tag.empty()) { 00379 XMLNode::AttributeMap attributes; 00380 _buffer.get_attributes(attributes); 00381 00382 _reader.StartElementHandler(tag, attributes); 00383 00384 if (str[b.length()-2] == '/') 00385 _reader.EndElementHandler(); 00386 } 00387 00388 c = _reader.get(); 00389 } 00390 } else { // in_comment || c=='<' 00391 _buffer.append(c); 00392 00393 // read white space 00394 for(;;) { 00395 // check for the encoding of the first line end 00396 if (!_reader._endl_defined) { 00397 if (c == '\n') { 00398 _reader._format._endl = "\n"; 00399 _reader._endl_defined = true; 00400 } else if (c == '\r') { 00401 _reader._format._endl = "\r\n"; 00402 _reader._endl_defined = true; 00403 } 00404 } 00405 00406 c = _reader.get(); 00407 00408 if (c == EOF) 00409 break; 00410 00411 if (c == '<') 00412 break; 00413 00414 _buffer.append(c); 00415 } 00416 00417 _reader.DefaultHandler(_buffer.str(_utf8)); 00418 } 00419 00420 _buffer.reset(); 00421 00422 return c; 00423 } 00424 00425 00426 bool XMLReaderBase::parse() 00427 { 00428 ParseContext ctx(*this); 00429 00430 while(ctx.proceed()) { 00431 } 00432 00433 return true; //TODO return false on invalid XML 00434 } 00435 00436 int XMLReaderBase::eat_endl() 00437 { 00438 int c = get(); 00439 00440 if (c == '\r') 00441 c = get(); 00442 00443 if (c == '\n') 00444 c = get(); 00445 00446 return c; 00447 } 00448 00449 00450 /// store content, white space and comments 00451 void XMLReaderBase::DefaultHandler(const std::string& s) 00452 { 00453 _content.append(s); 00454 } 00455 00456 00457 } // namespace XMLStorage 00458 00459 #endif // !defined(XS_USE_EXPAT) && !defined(XS_USE_XERCES)
ROS Explorer Source Code Documentation
generated on 02.01.2013 by ![]() |