void XMLWriter::writeNode(const char* tag, const char* str) { tagOpen(tag, "", NONEWLINE); #ifdef XMLWRITER_ESCAPE_SUPPORT escape(str); #else _stream->print(str); #endif tagClose(NOINDENT); }
//-------------------------------------------------------------- // parse a char buffer. Characters are assumed UTF-8, but this // is passed through to content and attributes. All we care // about is xml characters (<, >, =", etc.) void mgXMLScanner::parse( int len, const char* buffer) { int posn = 0; while (true) { // read a char, possibly pushed back char c; if (m_lastChar != '\0') { c = m_lastChar; m_lastChar = '\0'; } else { // if buffer empty if (posn >= len) break; c = buffer[posn++]; // track line and col nums for error messages if (c == '\n') { m_lineNum++; m_colNum = 0; } else if (c != '\r') m_colNum++; } // process against state machine switch (m_state) { case START_STATE: if (c == '<') { if (m_token.length() > 0) { content(m_token, m_token.length()); m_token.empty(); } m_state = OPEN_STATE; } else if (c == '&') { if (m_token.length() > 0) { content(m_token, m_token.length()); m_token.empty(); } m_state = AMPER_STATE; } else { if (m_token.length() > CONTENT_CHUNK_MAX) { content(m_token, m_token.length()); m_token.empty(); } m_token += c; } break; case OPEN_STATE: // '<' seen if (c == '?') m_state = PROCESS_STATE; else if (c == '!') m_state = TAGEXP_STATE; else if (c == '/') m_state = TAGCLOSE_STATE; else { m_state = TAGOPEN_STATE; m_lastChar = c; } break; case PROCESS_STATE: // <? seen if (c == '?') m_state = PROCESS_END_STATE; else m_token += c; break; case PROCESS_END_STATE: // <? ... ? seen if (c == '>') { processingInstruction(m_token); m_token.empty(); m_state = START_STATE; } else { m_token += '?'; m_lastChar = c; m_state = PROCESS_STATE; } break; case TAGEXP_STATE: // <! seen if (c == '-') m_state = TAGEXP_DASH_STATE; else if (c == '[') m_state = CDATA_OPEN_STATE; else errorMsg("xmlBadString", "string", "<!%c", c); break; case TAGEXP_DASH_STATE: // <!- seen if (c == '-') m_state = COMMENT_STATE; else errorMsg("xmlBadString", "string", "<!-%c", c); break; case COMMENT_STATE: // <!-- seen if (c == '-') m_state = COMMENT_END_STATE; else m_token += c; break; case COMMENT_END_STATE: // <!-- ... - seen if (c == '-') m_state = COMMENT_END2_STATE; else { m_token += '-'; m_lastChar = c; m_state = COMMENT_STATE; } break; case COMMENT_END2_STATE: // <!-- ... -- seen if (c == '>') { comment(m_token); m_token.empty(); m_state = START_STATE; } else { m_token += "--"; m_lastChar = c; m_state = COMMENT_STATE; } break; case CDATA_OPEN_STATE: // <![ seen if (c == 'C') m_state = CDATA_OPEN2_STATE; else errorMsg("xmlBadString", "string", "<![%c", c); break; case CDATA_OPEN2_STATE: // <![C seen if (c == 'D') m_state = CDATA_OPEN3_STATE; else errorMsg("xmlBadString", "string", "<![C%c", c); break; case CDATA_OPEN3_STATE: // <![CD seen if (c == 'A') m_state = CDATA_OPEN4_STATE; else errorMsg("xmlBadString", "string", "<![CD%c", c); break; case CDATA_OPEN4_STATE: // <![CDA seen if (c == 'T') m_state = CDATA_OPEN5_STATE; else errorMsg("xmlBadString", "string", "<![CDA%c", c); break; case CDATA_OPEN5_STATE: // <![CDAT seen if (c == 'A') m_state = CDATA_OPEN6_STATE; else errorMsg("xmlBadString", "string", "<![CDAT%c", c); break; case CDATA_OPEN6_STATE: // <![CDATA seen if (c == '[') m_state = CDATA_STATE; else errorMsg("xmlBadString", "string", "<![CDATA%c", c); break; case CDATA_STATE: // <![CDATA[ ... seen if (c == ']') m_state = CDATA_END_STATE; else { // break this into chunks if (m_token.length() > CONTENT_CHUNK_MAX) { CDATAContent(m_token, m_token.length()); m_token.empty(); } m_token += c; } break; case CDATA_END_STATE: // <![CDATA[ ... ] seen if (c == ']') m_state = CDATA_END2_STATE; else { m_state = CDATA_STATE; m_token += ']'; m_lastChar = c; } break; case CDATA_END2_STATE: // <![CDATA[ ... ]] seen if (c == '>') { CDATAContent(m_token, m_token.length()); m_token.empty(); m_state = START_STATE; } else { m_state = CDATA_STATE; m_token += "]]"; m_lastChar = c; } break; case TAGOPEN_STATE: // <x... seen if (c == '>') { tagOpen(m_token); endAttrs(); m_token.empty(); m_state = START_STATE; } else if (c == '/') { tagOpen(m_token); m_token.empty(); endAttrs(); tagNoContent(); m_state = TAGCLOSE_BLANK_STATE; } else if (isspace(c)) { tagOpen(m_token); m_token.empty(); m_state = ATTR_START_STATE; } else m_token += c; break; case TAGCLOSE_STATE: // </ seen if (c == '>') { tagClose(m_token); m_token.empty(); m_state = START_STATE; } else if (isspace(c)) { tagClose(m_token); m_token.empty(); m_state = TAGCLOSE_BLANK_STATE; } else m_token += c; break; case TAGCLOSE_BLANK_STATE: // </tag ' ' seen if (c == '>') m_state = START_STATE; else if (!isspace(c)) errorMsg("xmlBadClose", "", ""); break; case ATTR_START_STATE: // <tag ' ' seen, or attr=value seen if (c == '>') { if (m_token.length() > 0) { tagOpen(m_token); m_token.empty(); } endAttrs(); m_state = START_STATE; } else if (c == '/') { if (m_token.length() > 0) { tagOpen(m_token); m_token.empty(); } endAttrs(); tagNoContent(); m_state = TAGCLOSE_BLANK_STATE; } else if (!isspace(c)) { m_state = ATTR_NAME_STATE; m_lastChar = c; } break; case ATTR_NAME_STATE: // <tag ... 'letter' a seen if (iswalnum(c) || c == '_' || c == '.' || c == '-') m_token += c; else if (c == '=') { attrName(m_token); m_token.empty(); m_state = VALUE_START_STATE; } else if (isspace(c)) { attrName(m_token); m_token.empty(); m_state = EQUAL_START_STATE; } else errorMsg("xmlMissingEquals", "", ""); break; case EQUAL_START_STATE: if (c == '=') m_state = VALUE_START_STATE; else if (!isspace(c)) errorMsg("xmlMissingEquals", "", ""); break; case VALUE_START_STATE: if (c == '"') { m_state = VALUE_STATE; m_valueDelim = '"'; } else if (c == '\'') { m_state = VALUE_STATE; m_valueDelim = '\''; } else if (!isspace(c)) errorMsg("xmlMissingQuote", "", ""); break; case VALUE_STATE: if (c == m_valueDelim) { attrValue(m_token); m_token.empty(); m_state = ATTR_START_STATE; } else if (c == '&') m_state = VALUE_AMPER_STATE; else m_token += c; break; case VALUE_AMPER_STATE: // & seen in attribute value if (c == ';') { mgString value; entityRef(m_entityRef, value); m_token += value; m_entityRef.empty(); m_state = VALUE_STATE; } else if (isspace(c)) errorMsg("xmlMissingSemi", "", ""); else m_entityRef += c; break; case AMPER_STATE: // & seen in content if (c == ';') { mgString value; entityRef(m_entityRef, value); m_token += value; m_entityRef.empty(); m_state = START_STATE; } else if (isspace(c)) errorMsg("xmlMissingSemi", "", ""); else m_entityRef += c; break; } } }
void XMLWriter::tagOpen(const char* tag, const bool newline) { tagOpen(tag, "", newline); }
void XMLWriter::writeNode(const char* tag, const double value, const uint8_t decimals) { tagOpen(tag, "", NONEWLINE); _stream->print(value, decimals); tagClose(NOINDENT); }
void XMLWriter::writeNode(const char* tag, const bool value) { tagOpen(tag, "", NONEWLINE); _stream->print(value?F("true"):F("false")); tagClose(NOINDENT); }
void XMLWriter::writeNode(const char* tag, const int32_t value, const uint8_t base) { tagOpen(tag, "", NONEWLINE); _stream->print(value, base); // todo: leading zero's tagClose(NOINDENT); }
void XMLWriter::tagOpen(char* tag, bool newline) { tagOpen(tag, "", newline); }