/* 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 . */ #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; }