GY-63_MS5611/libraries/XMLWriter/XMLWriter.cpp

399 lines
8.4 KiB
C++
Raw Normal View History

//
// FILE: XMLWriter.cpp
// AUTHOR: Rob Tillaart
2021-01-29 06:31:58 -05:00
// VERSION: 0.3.0
// DATE: 2013-11-06
2020-05-25 03:58:04 -04:00
// PURPOSE: Arduino library for creating XML
//
2021-01-29 06:31:58 -05:00
// HISTORY:
// 0.1.00 2013-11-06 initial version
// 0.1.01 2013-11-07 rework interfaces
// 0.1.02 2013-11-07 +setIndentSize(), corrected history, +escape support
// 0.1.03 2015-03-07 refactored - footprint + interface
// 0.1.04 2015-05-21 refactored - reduce RAM -> used F() macro etc.
// 0.1.05 2015-05-23 added XMLWRITER_MAXTAGSIZE 15 (to support KML coordinates tag)
// 0.1.6 2016-03-16 added incrIndent(), decrIndent(), indent(), raw();
// 0.1.7 2017-07-26 added const where possible
// 0.1.8 2017-12-09 fix casting issue #83 (long -> int32_t);
// 0.1.9 2017-12-09 add PROGMEM support for escape() strings
// 0.2.0 2020-04-24 refactor, added examples, #pragma, print as base class
// 0.2.1 2020-04-26 performance optimized, setconfig() + newLine() added
// 0.2.2 2020-04-29 dynamic buffer size in constructor
// 0.2.3 2020-06-19 fix library.json
// 0.2.4 2020-07-07 fix #6 Print interface made public
// 0.3.0 2021-01-09 arduino-ci + unit tests
// add getIndentSize(); version(); debug();
#include "XMLWriter.h"
2020-05-25 03:58:04 -04:00
XMLWriter::XMLWriter(Print* stream, uint8_t bufsize)
{
2020-05-25 03:58:04 -04:00
_bufsize = constrain(bufsize, 2, 250);
_buffer = (char *) malloc(_bufsize);
_stream = stream;
reset();
}
2021-01-29 06:31:58 -05:00
2020-05-25 03:58:04 -04:00
XMLWriter::~XMLWriter()
{
if (_buffer != NULL) free(_buffer);
}
2021-01-29 06:31:58 -05:00
void XMLWriter::reset()
{
2021-01-29 06:31:58 -05:00
_indent = 0;
_indentStep = 2;
2021-01-29 06:31:58 -05:00
_tidx = 0;
_bidx = 0;
_config = XMLWRITER_COMMENT | XMLWRITER_INDENT | XMLWRITER_NEWLINE;
_bytesOut = 0;
}
2021-01-29 06:31:58 -05:00
void XMLWriter::header()
{
2020-05-25 03:58:04 -04:00
print(F("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"));
}
2021-01-29 06:31:58 -05:00
void XMLWriter::version()
{
print(F("<!-- "));
print(F(" XMLWRITER_VERSION: "));
print(XMLWRITER_VERSION);
print(F(" -->\n"));
}
void XMLWriter::debug()
{
print(F("<!-- "));
print('\n');
print(F(" VERSION: "));
println(XMLWRITER_VERSION);
print(F("MAXLEVEL: "));
println(XMLWRITER_MAXLEVEL);
print(F(" TAGSIZE: "));
println(XMLWRITER_MAXTAGSIZE);
print(F(" CONFIG: "));
println(_config, HEX);
print(F(" INDENT: "));
println(_indent);
print(F(" BUFSIZE: "));
println(_bufsize);
print(F(" -->\n"));
}
2020-11-27 05:33:55 -05:00
void XMLWriter::comment(const char* text, const bool multiLine)
{
2020-05-25 03:58:04 -04:00
if (_config & XMLWRITER_COMMENT)
{
print('\n');
if (!multiLine) indent();
print(F("<!-- "));
if (multiLine) print('\n');
print(text);
if (multiLine) print('\n');
print(F(" -->\n"));
}
}
2021-01-29 06:31:58 -05:00
2020-05-25 03:58:04 -04:00
void XMLWriter::newLine(uint8_t n)
{
if (_config & XMLWRITER_NEWLINE)
{
while(n--) print('\n');
}
}
2021-01-29 06:31:58 -05:00
void XMLWriter::tagOpen(const char* tag, const bool newline)
{
tagOpen(tag, "", newline);
}
void XMLWriter::tagOpen(const char* tag, const char* name, const bool newline)
{
2020-05-25 03:58:04 -04:00
if (_tidx > XMLWRITER_MAXLEVEL)
{
2020-11-27 05:33:55 -05:00
comment("MAXLEVEL exceeded.");
2020-05-25 03:58:04 -04:00
comment(tag);
comment(name);
2020-11-27 05:33:55 -05:00
flush();
2020-05-25 03:58:04 -04:00
return;
}
2020-11-27 05:33:55 -05:00
if (strlen(tag) > XMLWRITER_MAXTAGSIZE)
{
comment("MAXTAGSIZE exceeded.");
comment(tag);
flush();
return;
}
strcpy(_tagStack[_tidx++], tag);
tagStart(tag);
if (name[0] != 0) tagField("name", name);
tagEnd(newline, NOSLASH);
_indent += _indentStep;
}
void XMLWriter::tagClose(const bool ind)
{
_indent -= _indentStep;
if (ind) indent();
2020-05-25 03:58:04 -04:00
print("</");
print(_tagStack[--_tidx]);
print(">\n");
}
void XMLWriter::tagStart(const char *tag)
{
indent();
2020-05-25 03:58:04 -04:00
print('<');
print(tag);
}
void XMLWriter::tagField(const char *field, const char* str)
{
2020-05-25 03:58:04 -04:00
print(' ');
print(field);
print("=\"");
#ifdef XMLWRITER_ESCAPE_SUPPORT
escape(str);
#else
2020-05-25 03:58:04 -04:00
print(str);
#endif
2020-05-25 03:58:04 -04:00
print('"');
}
void XMLWriter::tagEnd(const bool newline, const bool addSlash)
{
2020-05-25 03:58:04 -04:00
if (addSlash) print("/>");
else print('>');
if (newline) print('\n');
}
void XMLWriter::writeNode(const char* tag, const char* str)
{
tagOpen(tag, "", NONEWLINE);
#ifdef XMLWRITER_ESCAPE_SUPPORT
escape(str);
#else
2020-05-25 03:58:04 -04:00
print(str);
#endif
tagClose(NOINDENT);
}
2021-01-29 06:31:58 -05:00
///////////////////////////////////////////////////////////////
//
// TAGFIELD
//
void XMLWriter::tagField(const char *field, const uint8_t value, const uint8_t base)
{
tagField(field, (uint32_t) value, base);
}
void XMLWriter::tagField(const char *field, const uint16_t value, const uint8_t base)
{
tagField(field, (uint32_t) value, base);
}
void XMLWriter::tagField(const char *field, const uint32_t value, const uint8_t base)
{
2020-05-25 03:58:04 -04:00
print(' ');
print(field);
print("=\"");
print(value, base);
print('"');
}
void XMLWriter::tagField(const char *field, const int8_t value, const uint8_t base)
{
tagField(field, (int32_t) value, base);
}
void XMLWriter::tagField(const char *field, const int16_t value, const uint8_t base)
{
tagField(field, (int32_t) value, base);
}
2021-01-29 06:31:58 -05:00
void XMLWriter::tagField(const char *field, const int value, const int base)
{
tagField(field, (int32_t) value, (uint8_t) base);
}
void XMLWriter::tagField(const char *field, const int32_t value, const uint8_t base)
{
2020-05-25 03:58:04 -04:00
print(' ');
print(field);
print("=\"");
print(value, base);
print('"');
}
void XMLWriter::tagField(const char *field, const bool value)
{
2020-05-25 03:58:04 -04:00
print(' ');
print(field);
// F() is slower & uses less RAM but 15 bytes saved
print(value ? F("=\"true\"") : F("=\"false\""));
}
void XMLWriter::tagField(const char *field, const double value, const uint8_t decimals)
{
2020-05-25 03:58:04 -04:00
print(' ');
print(field);
print(F("=\""));
print(value, decimals);
print('"');
}
2021-01-29 06:31:58 -05:00
///////////////////////////////////////////////////////////////
//
// WRITENODE
//
void XMLWriter::writeNode(const char* tag, const uint8_t value, const uint8_t base)
{
writeNode(tag, (uint32_t) value, base);
}
void XMLWriter::writeNode(const char* tag, const uint16_t value, const uint8_t base)
{
writeNode(tag, (uint32_t) value, base);
}
void XMLWriter::writeNode(const char* tag, const uint32_t value, const uint8_t base)
{
tagOpen(tag, "", NONEWLINE);
2020-05-25 03:58:04 -04:00
print(value, base);
tagClose(NOINDENT);
}
void XMLWriter::writeNode(const char* tag, const int8_t value, const uint8_t base)
{
writeNode(tag, (int32_t) value, base);
}
void XMLWriter::writeNode(const char* tag, const int16_t value, const uint8_t base)
{
writeNode(tag, (int32_t) value, base);
}
2021-01-29 06:31:58 -05:00
void XMLWriter::writeNode(const char* tag, const int value, const int base)
{
writeNode(tag, (int32_t) value, (uint8_t) base);
}
void XMLWriter::writeNode(const char* tag, const int32_t value, const uint8_t base)
{
tagOpen(tag, "", NONEWLINE);
2020-05-25 03:58:04 -04:00
print(value, base);
tagClose(NOINDENT);
}
void XMLWriter::writeNode(const char* tag, const bool value)
{
tagOpen(tag, "", NONEWLINE);
2020-05-25 03:58:04 -04:00
// F() is slower & uses less RAM but saves 9 bytes
print(value ? F("true") : F("false"));
tagClose(NOINDENT);
}
void XMLWriter::writeNode(const char* tag, const double value, const uint8_t decimals)
{
tagOpen(tag, "", NONEWLINE);
2020-05-25 03:58:04 -04:00
print(value, decimals);
tagClose(NOINDENT);
}
void XMLWriter::indent()
{
2020-05-25 03:58:04 -04:00
if (_config & XMLWRITER_INDENT)
{
// as indentation is a multiple of 2
2021-01-29 06:31:58 -05:00
// this is nice balance between speed and RAM.
2020-05-25 03:58:04 -04:00
for (uint8_t i = _indent; i > 0; i-= 2) print(" ");
}
}
2020-05-25 03:58:04 -04:00
size_t XMLWriter::write(uint8_t c)
{
_buffer[_bidx++] = c;
if (_bidx == (_bufsize - 1)) flush();
return 1;
};
void XMLWriter::flush()
{
_bytesOut += _bidx;
if (_bidx > 0)
{
_buffer[_bidx] = 0;
_stream->print(_buffer);
_bidx = 0;
}
};
////////////////////////////////////////////////////////////////////
2020-05-25 03:58:04 -04:00
//
// ESCAPE
//
#ifdef XMLWRITER_ESCAPE_SUPPORT
2020-05-25 03:58:04 -04:00
static char c[6] = "\"\'<>&";
#ifdef __PROGMEM__
PROGMEM const char quote[] = "&quot;";
PROGMEM const char apostrophe[] = "&apos;";
PROGMEM const char lessthen[] = "&lt;";
PROGMEM const char greaterthen[] = "&gt;";
PROGMEM const char ampersand[] = "&amp;";
PROGMEM const char* const expanded[] =
{
quote, apostrophe, lessthen, greaterthen, ampersand
};
#else
// NOTE: & and ; are handled in code. // 25 bytes RAM
static char expanded[][5] = { "quot", "apos","lt","gt","amp"};
#endif
void XMLWriter::escape(const char* str)
{
char* p = (char *)str;
2020-05-25 03:58:04 -04:00
while (*p != 0)
{
char* q = strchr(c, *p);
2020-05-25 03:58:04 -04:00
if (q == NULL) print(*p);
#ifdef __PROGMEM__
else
{
char buf[8];
strcpy_P(buf, (char*)pgm_read_word(&(expanded[q - c])));
print(buf);
}
#else
else
{
print('&');
print(expanded[q - c]); // uint8_t idx = q-c;
print(';');
}
#endif
p++;
}
}
#endif
2020-05-25 03:58:04 -04:00
// -- END OF FILE --