• Main Page
  • Namespaces
  • Classes
  • Files
  • Directories
  • File List
  • File Members

xs-native.cpp

Go to the documentation of this file.
00001 
00002  //
00003  // XML storage C++ classes version 1.6
00004  //
00005  // Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014 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(bool force_utf8)
00058 {
00059     if (!parse(force_utf8)) {
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 bool ReadBuffer::append(int c)
00095 {
00096     size_t wpos = _wptr-_buffer;
00097 
00098     if (wpos >= _len) {
00099         size_t new_len = _len << 1;
00100 
00101         void* new_ptr = realloc(_buffer, new_len);
00102 
00103         if (new_ptr) {
00104             _buffer = (char*)new_ptr;
00105             _wptr = _buffer + wpos;
00106             _len = new_len;
00107         } else
00108             return false; // memory allocation failure
00109     }
00110 
00111     *_wptr++ = static_cast<char>(c);
00112 
00113     return true;
00114 }
00115 
00116 const std::string& ReadBuffer::str(bool utf8)   // returns UTF-8 encoded buffer content
00117 {
00118 #if defined(_WIN32) && !defined(XS_STRING_UTF8)
00119     if (utf8)
00120 #endif
00121         _buffer_str.assign(_buffer, _wptr-_buffer);
00122 #if defined(_WIN32) && !defined(XS_STRING_UTF8)
00123     else
00124         _buffer_str = get_utf8(_buffer, _wptr-_buffer);
00125 #endif
00126 
00127     return _buffer_str;
00128 }
00129 
00130 size_t ReadBuffer::len() const
00131 {
00132     return _wptr - _buffer;
00133 }
00134 
00135 bool ReadBuffer::has_CDEnd() const
00136 {
00137     //if (_wptr-_buffer < 3)
00138     //  return false;
00139 
00140     return !strncmp(_wptr-3, CDATA_END, 3);
00141 }
00142 
00143 XS_String ReadBuffer::get_tag() const
00144 {
00145     const char* p = _buffer_str.c_str();
00146 
00147     if (*p == '<')
00148         ++p;
00149 
00150     if (*p == '/')
00151         ++p;
00152 
00153     const char* q = p;
00154 
00155     if (*q == '?')
00156         ++q;
00157 
00158     q = get_xmlsym_end_utf8(q);
00159 
00160 #ifdef XS_STRING_UTF8
00161     return XS_String(p, q-p);
00162 #else
00163     return from_utf8(p, q-p);
00164 #endif
00165 }
00166 
00167  /// read attributes and values
00168 void ReadBuffer::get_attributes(XMLNode::AttributeMap& attributes) const
00169 {
00170     const char* p = _buffer_str.c_str();
00171 
00172      // find end of tag name
00173     if (*p == '<')
00174         ++p;
00175 
00176     if (*p == '/')
00177         ++p;
00178     else if (*p == '?')
00179         ++p;
00180 
00181     p = get_xmlsym_end_utf8(p);
00182 
00183      // read attributes from buffer
00184     while(*p && *p!='>' && *p!='/') {
00185         while(isspace((unsigned char)*p))
00186             ++p;
00187 
00188         if (*p=='?' || *p=='>' || *p=='/')
00189             break;
00190 
00191         const char* attr_name = p;
00192 
00193         p = get_xmlsym_end_utf8(p);
00194 
00195         if (*p != '=') {
00196             _errors.push_back(XMLError(_location, "missing attribute assignment"));
00197             break;
00198         }
00199 
00200         size_t attr_len = p - attr_name;
00201 
00202         if (*++p!='"' && *p!='\'') {
00203             _errors.push_back(XMLError(_location, "missing attribute value quote"));
00204             break;
00205         }
00206 
00207         char delim = *p;
00208         const char* value = ++p;
00209 
00210         while(*p && *p!=delim)
00211             ++p;
00212 
00213         size_t value_len = p - value;
00214 
00215         if (*p)
00216             ++p;    // '"' oder '\''
00217         else
00218             _errors.push_back(XMLError(_location, "unterminated attribute quote"));
00219 
00220 #ifdef XS_STRING_UTF8
00221         XS_String name_str(attr_name, attr_len);
00222 #else
00223         XS_String name_str;
00224         assign_utf8(name_str, attr_name, attr_len);
00225 #endif
00226 
00227         attributes[name_str] = DecodeXMLString(std::string(value, value_len));
00228     }
00229 }
00230 
00231 
00232 ParseContext::ParseContext(XMLReaderBase& reader, bool force_utf8)
00233  :  _reader(reader),
00234     _buffer(reader._errors, reader._location),
00235     _utf8(force_utf8)
00236 {
00237     _next = reader.get();
00238     _in_comment = false;
00239 
00240      // check for UTF-8 signature
00241     read_bom();
00242 }
00243 
00244 void ParseContext::read_bom()
00245 {
00246     if (_next == 0xEF) {
00247         _next = _reader.get();
00248 
00249         if (_next == 0xBB) {
00250             _next = _reader.get();
00251 
00252             if (_next == 0xBF) {
00253                 _utf8 = true;
00254                 _reader._format._utf8_bom = true;
00255 
00256                 _next = _reader.get();
00257             }
00258         }
00259     }
00260 }
00261 
00262 bool ParseContext::proceed()
00263 {
00264     if (_next != EOF)
00265         _next = process_next(_next);
00266 
00267     return _next != EOF;
00268 }
00269 
00270 int ParseContext::process_next(int c)
00271 {
00272     if (_in_comment || c=='<') {
00273         if (!_buffer.empty())
00274             _buffer.reset();
00275 
00276         _buffer.append(c);
00277 
00278          // read start or end tag
00279         for(;;) {
00280             c = _reader.get();
00281 
00282             if (c == EOF)
00283                 break;
00284 
00285             _buffer.append(c);
00286 
00287             if (c == '>')
00288                 break;
00289         }
00290 
00291         const std::string& b = _buffer.str(_utf8);
00292         const char* str = b.c_str();
00293 
00294         if (_in_comment || !strncmp(str+1, "!--", 3)) {
00295              // XML comment
00296             _reader.DefaultHandler(b);
00297 
00298             if (strcmp(str+b.length()-3, "-->"))
00299                 _in_comment = true;
00300             else
00301                 _in_comment = false;
00302 
00303             c = _reader.get();
00304         } else if (str[1] == '/') {
00305              // end tag
00306 
00307             /*@TODO error handling
00308             const XS_String& tag = buffer.get_tag();
00309 
00310                 if (tag != last_opened_tag) {
00311                     ERROR
00312                 }
00313             */
00314 
00315             _reader.EndElementHandler();
00316 
00317             c = _reader.get();
00318         } else if (str[1] == '?') {
00319              // XML declaration
00320             const XS_String& tag = _buffer.get_tag();
00321 
00322             if (tag == "?xml") {
00323                 XMLNode::AttributeMap attributes;
00324                 _buffer.get_attributes(attributes);
00325 
00326                 const std::string& version = attributes.get("version");
00327                 const std::string& encoding = attributes.get("encoding");
00328 
00329                 int standalone;
00330                 XMLNode::AttributeMap::const_iterator found = // const_cast for ISO C++ compatibility error of GCC
00331                         const_cast<const XMLNode::AttributeMap&>(attributes).find("standalone");
00332                 if (found != attributes.end())
00333                     standalone = !XS_icmp(found->second.c_str(), XS_TEXT("yes"));
00334                 else
00335                     standalone = -1;
00336 
00337                 _reader.XmlDeclHandler(version.empty()?NULL:version.c_str(), encoding.empty()?NULL:encoding.c_str(), standalone);
00338 
00339                 if (!encoding.empty()) {
00340                     if (!_stricmp(encoding.c_str(), "utf-8"))
00341                         _utf8 = true;
00342                     else
00343                         assert(!_reader._format._utf8_bom); // mismatch between BOM and xml header
00344                 }
00345 
00346                 c = _reader.eat_endl();
00347             } else if (tag == "?xml-stylesheet") {
00348                 XMLNode::AttributeMap attributes;
00349                 _buffer.get_attributes(attributes);
00350 
00351                 StyleSheet stylesheet(attributes.get("href"), attributes.get("type"), !XS_icmp(attributes.get("alternate"), XS_TEXT("yes")));
00352                 stylesheet._title = attributes.get("title");
00353                 stylesheet._media = attributes.get("media");
00354                 stylesheet._charset = attributes.get("charset");
00355 
00356                 _reader._format._stylesheets.push_back(stylesheet);
00357 
00358                 c = _reader.eat_endl();
00359             } else {
00360                 _reader.DefaultHandler(b);
00361                 c = _reader.get();
00362             }
00363         } else if (str[1] == '!') {
00364             if (!strncmp(str+2, "DOCTYPE ", 8)) {
00365                 _reader._format._doctype.parse(str+10);
00366 
00367                 c = _reader.eat_endl();
00368             } else if (!strncmp(str+2, "[CDATA[", 7)) { // see CDATA_START
00369                  // parse <![CDATA[ ... ]]> strings
00370                 while(!_buffer.has_CDEnd()) {
00371                     c = _reader.get();
00372 
00373                     if (c == EOF)
00374                         break;
00375 
00376                     _buffer.append(c);
00377                 }
00378 
00379                 _reader.DefaultHandler(_buffer.str(_utf8));
00380 
00381                 c = _reader.get();
00382             }
00383         } else {
00384              // start tag
00385             const XS_String& tag = _buffer.get_tag();
00386 
00387             if (!tag.empty()) {
00388                 XMLNode::AttributeMap attributes;
00389                 _buffer.get_attributes(attributes);
00390 
00391                 _reader.StartElementHandler(tag, attributes);
00392 
00393                 if (str[b.length()-2] == '/')
00394                     _reader.EndElementHandler();
00395             }
00396 
00397             c = _reader.get();
00398         }
00399     } else { // in_comment || c=='<'
00400         _buffer.append(c);
00401 
00402          // read white space
00403         for(;;) {
00404              // check for the encoding of the first line end
00405             if (!_reader._endl_defined) {
00406                 if (c == '\n') {
00407                     _reader._format._endl = "\n";
00408                     _reader._endl_defined = true;
00409                 } else if (c == '\r') {
00410                     _reader._format._endl = "\r\n";
00411                     _reader._endl_defined = true;
00412                 }
00413             }
00414 
00415             c = _reader.get();
00416 
00417             if (c == EOF)
00418                 break;
00419 
00420             if (c == '<')
00421                 break;
00422 
00423             _buffer.append(c);
00424         }
00425 
00426         _reader.DefaultHandler(_buffer.str(_utf8));
00427     }
00428 
00429     _buffer.reset();
00430 
00431     return c;
00432 }
00433 
00434 
00435 bool XMLReaderBase::parse(bool force_utf8)
00436 {
00437     ParseContext ctx(*this, force_utf8);
00438 
00439     while(ctx.proceed()) {
00440     }
00441 
00442     return true; //TODO return false on invalid XML
00443 }
00444 
00445 int XMLReaderBase::eat_endl()
00446 {
00447     int c = get();
00448 
00449     if (c == '\r')
00450         c = get();
00451 
00452     if (c == '\n')
00453         c = get();
00454 
00455     return c;
00456 }
00457 
00458 
00459  /// store content, white space and comments
00460 void XMLReaderBase::DefaultHandler(const std::string& s)
00461 {
00462     _content.append(s);
00463 }
00464 
00465 
00466 } // namespace XMLStorage
00467 
00468 #endif // !defined(XS_USE_EXPAT) && !defined(XS_USE_XERCES)

Generated on Fri Nov 14 2014 00:05:04 for XMLStorage/C++ by  doxygen 1.7.2