xs-native.cpp

Go to the documentation of this file.
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 doxygen

ROS Explorer Homepage