Tasmota/lib/default/jsmn-shadinger-1.0/src/JsonGenerator.cpp

192 lines
4.9 KiB
C++

/*
JsonGenerator.cpp - lightweight JSON parser
Copyright (C) 2021 Stephan Hadinger
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "JsonGenerator.h"
/*********************************************************************************************\
* JSON Generator for Arrays
\*********************************************************************************************/
void JsonGeneratorArray::pre(void) {
// remove trailing ']'
val.remove(val.length()-1);
if (val.length() > 1) { // if not empty, prefix with comma
val += ',';
}
}
// void JsonGeneratorArray::post(void) {
// val += ']';
// }
// Add signed int (32 bits)
void JsonGeneratorArray::add(int32_t uval32) {
pre();
val += uval32;
post();
}
// Add unsigned int (32 bits)
void JsonGeneratorArray::add(uint32_t uval32) {
pre();
val += uval32;
post();
}
// Add a raw string, that will not be escaped.
// Can be used to add a sub-array, sub-object or 'null', 'true', 'false' values
void JsonGeneratorArray::addStrRaw(const char * sval) {
pre();
val += sval;
post();
}
// Add a JSON String (will be escaped)
void JsonGeneratorArray::addStr(const char * sval) {
pre();
val += '"';
val += EscapeJSONString(sval).c_str();
val += '"';
post();
}
/*********************************************************************************************\
* JSON Generator for Objects
\*********************************************************************************************/
void JsonGeneratorObject::pre(const char * key) {
// remove trailing '}'
val.remove(val.length()-1);
if (val.length() > 1) { // if not empty, prefix with comma
val += ',';
}
val += '"';
val += EscapeJSONString(key);
val += '"';
val += ':';
}
// void JsonGeneratorObject::post(void) {
// val += '}';
// }
// Add signed int (32 bits)
void JsonGeneratorObject::add(const char* key, int32_t uval32) {
pre(key);
val += uval32;
post();
}
// Add unsigned int (32 bits)
void JsonGeneratorObject::add(const char* key, uint32_t uval32) {
pre(key);
val += uval32;
post();
}
void JsonGeneratorObject::add(const char* key, const String & str) {
pre(key);
val += '"';
val += EscapeJSONString(str.c_str()).c_str();
val += '"';
post();
}
// Add up to 32 bits hex value
void JsonGeneratorObject::addHex32(const char* key, uint32_t uval32) {
char hex[16];
snprintf_P(hex, sizeof(hex), PSTR("\"0x%8X\""), uval32);
addStrRaw(key, hex);
}
// Add a raw string, that will not be escaped.
// Can be used to add a sub-array, sub-object or 'null', 'true', 'false' values
void JsonGeneratorObject::addStrRaw(const char* key, const char * sval) {
pre(key);
val += sval;
post();
}
// Add a JSON String (will be escaped)
void JsonGeneratorObject::addStr(const char* key, const char * sval) {
pre(key);
val += '"';
val += EscapeJSONString(sval).c_str();
val += '"';
post();
}
/*********************************************************************************************\
* JSON Generator for Arrays
\*********************************************************************************************/
// does the character needs to be escaped, and if so with which character
static char EscapeJSONChar(char c) {
if ((c == '\"') || (c == '\\')) {
return c;
}
if (c == '\n') { return 'n'; }
if (c == '\t') { return 't'; }
if (c == '\r') { return 'r'; }
if (c == '\f') { return 'f'; }
if (c == '\b') { return 'b'; }
return 0;
}
String EscapeJSONString(const char *str) {
// As this function is used in ResponseCmndChar() and ResponseCmndIdxChar()
// it needs to be PROGMEM safe!
String r("");
if (nullptr == str) { return r; }
bool needs_escape = false;
size_t len_out = 1;
const char* c = str;
char ch = '.';
while (ch != '\0') {
ch = pgm_read_byte(c++);
if (EscapeJSONChar(ch)) {
len_out++;
needs_escape = true;
}
len_out++;
}
if (needs_escape) {
// we need to escape some chars
// allocate target buffer
r.reserve(len_out);
c = str;
char *d = r.begin();
char ch = '.';
while (ch != '\0') {
ch = pgm_read_byte(c++);
char c2 = EscapeJSONChar(ch);
if (c2) {
*d++ = '\\';
*d++ = c2;
} else {
*d++ = ch;
}
}
*d = 0; // add NULL terminator
r = (char*) r.begin(); // assign the buffer to the string
} else {
r = FPSTR(str);
}
return r;
}