From cb85962bd99ff605bf0387b59566865d3c0be40d Mon Sep 17 00:00:00 2001 From: suwatchai Date: Mon, 18 Apr 2022 14:45:55 +0700 Subject: [PATCH] Update Signer class. --- LICENSE | 2 +- README.md | 10 +- library.json | 2 +- library.properties | 2 +- src/ESP_Google_Sheet_Client.cpp | 83 +- src/ESP_Google_Sheet_Client.h | 53 +- src/lib/ESPSigner/ESPSigner.cpp | 275 ++- src/lib/ESPSigner/ESPSigner.h | 13 +- .../{SignerCommon.h => SignerConst.h} | 92 +- src/lib/ESPSigner/SignerUtils.h | 109 +- src/lib/ESPSigner/json/FirebaseJson.cpp | 580 ++--- src/lib/ESPSigner/json/FirebaseJson.h | 1914 ++++++----------- src/lib/ESPSigner/json/MB_JSON/MB_JSON.c | 4 +- src/lib/ESPSigner/json/MB_JSON/MB_JSON.h | 4 +- src/lib/ESPSigner/json/MB_List.h | 224 ++ src/lib/ESPSigner/json/MB_String.h | 1140 +++++++++- .../json/extras/print/fb_json_print.c | 1049 +++++++++ .../json/extras/print/fb_json_print.h | 108 + src/lib/ESPSigner/wcs/HTTPCode.h | 6 +- ...P_Client.cpp => ESP_Signer_TCP_Client.cpp} | 10 +- .../wcs/esp32/ESP_Signer_TCP_Client.h | 10 +- .../wcs/esp8266/ESP_Signer_TCP_Client.cpp | 58 +- .../wcs/esp8266/ESP_Signer_TCP_Client.h | 64 +- 23 files changed, 3688 insertions(+), 2124 deletions(-) rename src/lib/ESPSigner/{SignerCommon.h => SignerConst.h} (89%) create mode 100644 src/lib/ESPSigner/json/MB_List.h create mode 100644 src/lib/ESPSigner/json/extras/print/fb_json_print.c create mode 100644 src/lib/ESPSigner/json/extras/print/fb_json_print.h rename src/lib/ESPSigner/wcs/esp32/{FB_TCP_Client.cpp => ESP_Signer_TCP_Client.cpp} (96%) diff --git a/LICENSE b/LICENSE index 80d1893..621c83e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 mobizt +Copyright (c) 2022 mobizt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index d2a8479..710335c 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,25 @@ # Arduino Google Sheet Client Library for ESP8266 and ESP32 -Arduino Google Sheet Client Library for ESP8266 and ESP32 v1.0.0. +Arduino Google Sheet Client Library for ESP8266 and ESP32 v1.0.1. This library allows devices to authenticate and communicate with Google Sheet APIs using the Service Account. Devices will be able to read, update, append and clear sheet values. Create, read, list, and delete the spreadsheet are also supported. -The spreadsheet that created using this library owned by the Service Account and shared access to the user. +The spreadsheet that created using this library, owned by the Service Account and shared access to the user. You can create, edit and deploy the Apps Script code via extension of spreadsheet that created by this library except for run the script due to permission denied. -Spreadsheet created or owned by you needed to share the access with Service Account's client email then library can read, edit except for delete the user's spreadsheet due to permission denied. +Spreadsheet created or owned by you, needed to share the access with Service Account's client email then library can read, and edit except for delete the user's spreadsheet due to permission denied. ## Important Note -The connection to Google Sheet API endpoint takes time and the time from sending request to complete response received can be as much as 3 seconds. +The connection to Google Sheet API endpoint takes time and the time from sending request to the complete response received can be as much as 3 seconds. The speed is not the library or device issue unless the server issue. @@ -1232,7 +1232,7 @@ bool search(FirebaseJson *response, spreadsheetId, FirebaseJsonArray *d The MIT License (MIT) -Copyright (C) 2021 K. Suwatchai (Mobizt) +Copyright (C) 2022 K. Suwatchai (Mobizt) Permission is hereby granted, free of charge, to any person returning a copy of diff --git a/library.json b/library.json index ec825be..379eddc 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ESP-Google-Sheet-Client", - "version": "1.0.0", + "version": "1.0.1", "keywords": "communication, REST, esp32, esp8266, arduino", "description": "Arduino Google Sheet REST client library for ESP8266 and ESP32. This library allows devices to communicate with Google Sheet API to read, edit and delete the spreadsheets", "repository": { diff --git a/library.properties b/library.properties index d205096..82972a7 100644 --- a/library.properties +++ b/library.properties @@ -1,6 +1,6 @@ name=ESP-Google-Sheet-Client -version=1.0.0 +version=1.0.1 author=Mobizt diff --git a/src/ESP_Google_Sheet_Client.cpp b/src/ESP_Google_Sheet_Client.cpp index 857d515..3916d10 100644 --- a/src/ESP_Google_Sheet_Client.cpp +++ b/src/ESP_Google_Sheet_Client.cpp @@ -1,17 +1,12 @@ /** - * Google Sheet Client, ESP_Google_Sheet_Client.cpp v1.0.0 + * Google Sheet Client, ESP_Google_Sheet_Client.cpp v1.0.1 * * This library supports Espressif ESP8266 and ESP32 MCUs * - * Created December 19, 2021 + * Created April 18, 2022 * - * - * - * This work is a part of Firebase ESP Client library - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2022 K. Suwatchai (Mobizt) * * * Permission is hereby granted, free of charge, to any person returning a copy of @@ -114,7 +109,7 @@ bool GSheetClass::setClock(float gmtOffset) return config._int.esp_signer_clock_rdy; } -void GSheetClass::beginRequest(FirebaseJson *response, MBSTRING &req, host_type_t host_type) +void GSheetClass::beginRequest(FirebaseJson *response, MB_String &req, host_type_t host_type) { if (response) @@ -141,7 +136,7 @@ void GSheetClass::beginRequest(FirebaseJson *response, MBSTRING &req, host_type_ setSecure(); } -void GSheetClass::addHeader(MBSTRING &req, host_type_t host_type, int len) +void GSheetClass::addHeader(MB_String &req, host_type_t host_type, int len) { req += FPSTR(" HTTP/1.1\r\n"); if (host_type == host_type_sheet) @@ -155,7 +150,7 @@ void GSheetClass::addHeader(MBSTRING &req, host_type_t host_type, int len) if (len > -1) { req += FPSTR("Content-Length: "); - req += NUM2S(len).get(); + req += len; req += FPSTR("\r\n"); req += FPSTR("Content-Type: application/json\r\n"); @@ -232,7 +227,7 @@ void GSheetClass::setSecure() } } -bool GSheetClass::processRequest(FirebaseJson *response, MBSTRING &req, int &httpcode) +bool GSheetClass::processRequest(FirebaseJson *response, MB_String &req, int &httpcode) { config.signer.json = new FirebaseJson(); @@ -242,7 +237,7 @@ bool GSheetClass::processRequest(FirebaseJson *response, MBSTRING &req, int &htt if (ret == 0) { - if (this->handleServerResponse(httpcode)) + if (this->handleTokenResponse(httpcode)) { ret = 1; if (parseJsonResponse(esp_signer_pgm_str_68) || parseJsonResponse(esp_signer_pgm_str_113)) @@ -264,7 +259,7 @@ bool GSheetClass::mGet(FirebaseJson *response, const char *spreadsheetId, const if (!checkToken()) return false; - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_sheet); @@ -285,14 +280,14 @@ bool GSheetClass::mGet(FirebaseJson *response, const char *spreadsheetId, const req += spreadsheetId; req += FPSTR("/values:batchGet"); - std::vector rngs = std::vector(); - MBSTRING rng = ranges; + std::vector rngs = std::vector(); + MB_String rng = ranges; ut->splitTk(rng, rngs, ","); if (rngs.size() == 0) return false; - MBSTRING s; + MB_String s; for (size_t i = 0; i < rngs.size(); i++) { @@ -438,7 +433,7 @@ bool GSheetClass::mUpdate(bool append, operation_type_t type, FirebaseJson *resp if (!checkToken()) return false; - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_sheet); @@ -528,7 +523,7 @@ bool GSheetClass::mClear(FirebaseJson *response, const char *spreadsheetId, cons if (!checkToken()) return false; - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_sheet); @@ -554,20 +549,20 @@ bool GSheetClass::mClear(FirebaseJson *response, const char *spreadsheetId, cons if (type == operation_type_batch) { req += FPSTR("/values:batchClear"); - std::vector rngs = std::vector(); - MBSTRING rng = ranges; + std::vector rngs = std::vector(); + MB_String rng = ranges; ut->splitTk(rng, rngs, ","); if (rngs.size() == 0) return false; FirebaseJson r; - MBSTRING tmp; + MB_String tmp; for (size_t i = 0; i < rngs.size(); i++) { tmp = (const char *)FPSTR("ranges/["); - tmp += NUM2S(i).get(); + tmp += i; tmp += (const char *)FPSTR("]"); r.set(tmp.c_str(), rngs[i].c_str()); @@ -602,7 +597,7 @@ bool GSheetClass::copyTo(FirebaseJson *response, const char *spreadsheetId, uint if (!checkToken()) return false; - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_sheet); @@ -611,10 +606,10 @@ bool GSheetClass::copyTo(FirebaseJson *response, const char *spreadsheetId, uint req += spreadsheetId; req += FPSTR("/sheets/"); - req += NUM2S(sheetId).get(); + req += sheetId; req += FPSTR(":copyTo"); - MBSTRING s; + MB_String s; s = FPSTR("{\"destinationSpreadsheetId\":\""); s += destinationSpreadsheetId; s += "\"}"; @@ -632,7 +627,7 @@ bool GSheetClass::batchUpdate(FirebaseJson *response, const char *spreadsheetId, if (!checkToken()) return false; - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_sheet); @@ -666,18 +661,18 @@ bool GSheetClass::batchUpdate(FirebaseJson *response, const char *spreadsheetId, if (strlen(responseRanges) > 0) { - std::vector rngs = std::vector(); - MBSTRING rng = responseRanges; + std::vector rngs = std::vector(); + MB_String rng = responseRanges; ut->splitTk(rng, rngs, ","); if (rngs.size() == 0) return false; - MBSTRING tmp; + MB_String tmp; for (size_t i = 0; i < rngs.size(); i++) { tmp = (const char *)FPSTR("responseRanges/["); - tmp += NUM2S(i).get(); + tmp += i; tmp += (const char *)FPSTR("]"); js.set(tmp.c_str(), rngs[i].c_str()); @@ -702,7 +697,7 @@ bool GSheetClass::create(FirebaseJson *response, FirebaseJson *spreadsheet, cons if (!checkToken()) return false; - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_sheet); @@ -737,7 +732,7 @@ bool GSheetClass::getMetadata(FirebaseJson *response, const char *spreadsheetId, if (!checkToken()) return false; - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_sheet); @@ -745,7 +740,7 @@ bool GSheetClass::getMetadata(FirebaseJson *response, const char *spreadsheetId, req = FPSTR("GET /v4/spreadsheets/"); req += spreadsheetId; req += FPSTR("/developerMetadata/"); - req += NUM2S(metadataId).get(); + req += metadataId; addHeader(req, host_type_sheet); @@ -761,7 +756,7 @@ bool GSheetClass::searchMetadata(FirebaseJson *response, const char *spreadsheet if (dataFiltersArray) { - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_sheet); @@ -790,7 +785,7 @@ bool GSheetClass::getSpreadsheet(FirebaseJson *response, const char *spreadsheet if (!checkToken()) return false; - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_drive); @@ -798,12 +793,12 @@ bool GSheetClass::getSpreadsheet(FirebaseJson *response, const char *spreadsheet req = FPSTR("GET /v4/spreadsheets/"); req += spreadsheetId; - MBSTRING s; + MB_String s; if (strlen(ranges) > 0) { - std::vector rngs = std::vector(); - MBSTRING rng = ranges; + std::vector rngs = std::vector(); + MB_String rng = ranges; ut->splitTk(rng, rngs, ","); if (rngs.size() == 0) @@ -852,7 +847,7 @@ bool GSheetClass::getSpreadsheetByDataFilter(FirebaseJson *response, const char if (dataFiltersArray) { - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_drive); @@ -891,7 +886,7 @@ bool GSheetClass::deleteFile(FirebaseJson *response, const char *spreadsheetId, config.signer.wcs = NULL; } - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_drive); @@ -973,7 +968,7 @@ bool GSheetClass::listFiles(FirebaseJson *response, uint32_t pageSize, const cha delete config.signer.wcs; config.signer.wcs = NULL; - MBSTRING req; + MB_String req; int httpcode = 0; if (pageSize == 0 || pageSize > 10) @@ -982,7 +977,7 @@ bool GSheetClass::listFiles(FirebaseJson *response, uint32_t pageSize, const cha beginRequest(response, req, host_type_drive); req = FPSTR("GET /drive/v3/files?pageSize="); - req += NUM2S(pageSize).get(); + req += pageSize; if (strlen(orderBy) > 0) { @@ -1015,7 +1010,7 @@ bool GSheetClass::createPermission(FirebaseJson *response, const char *fileid, c delete config.signer.wcs; config.signer.wcs = NULL; - MBSTRING req; + MB_String req; int httpcode = 0; beginRequest(response, req, host_type_drive); diff --git a/src/ESP_Google_Sheet_Client.h b/src/ESP_Google_Sheet_Client.h index 1f4c34e..8f82a62 100644 --- a/src/ESP_Google_Sheet_Client.h +++ b/src/ESP_Google_Sheet_Client.h @@ -1,21 +1,16 @@ #ifndef ESP_GOOGLE_SHEET_CLIENT_VERSION -#define ESP_GOOGLE_SHEET_CLIENT_VERSION "1.0.0" +#define ESP_GOOGLE_SHEET_CLIENT_VERSION "1.0.1" #endif /** - * Google Sheet Client, ESP_Google_Sheet_Client.h v1.0.0 + * Google Sheet Client, ESP_Google_Sheet_Client.h v1.0.1 * * This library supports Espressif ESP8266 and ESP32 MCUs * - * Created December 19, 2021 + * Created April 18, 2022 * - * Initial Released - * - * This work is a part of Firebase ESP Client library - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2022 K. Suwatchai (Mobizt) * * * Permission is hereby granted, free of charge, to any person returning a copy of @@ -78,7 +73,7 @@ class GSheetClass : public ESP_Signer SignerConfig config; int cert_addr = 0; bool cert_updated = false; - MBSTRING certFile; + MB_String certFile; esp_google_sheet_file_storage_type certFileStorageType; void auth(const char *client_email, const char *project_id, const char *private_key); @@ -104,9 +99,9 @@ class GSheetClass : public ESP_Signer bool getSpreadsheetByDataFilter(FirebaseJson *response, const char *spreadsheetId, FirebaseJsonArray *dataFiltersArray, const char *includeGridData = ""); bool deleteFiles(FirebaseJson *response); bool listFiles(FirebaseJson *response, uint32_t pageSize = 5, const char *orderBy = "", const char *pageToken = ""); - void beginRequest(FirebaseJson *response, MBSTRING &req, host_type_t host_type); - void addHeader(MBSTRING &req, host_type_t host_type, int len = -1); - bool processRequest(FirebaseJson *response, MBSTRING &req, int &httpcode); + void beginRequest(FirebaseJson *response, MB_String &req, host_type_t host_type); + void addHeader(MB_String &req, host_type_t host_type, int len = -1); + bool processRequest(FirebaseJson *response, MB_String &req, int &httpcode); void mUpdateInit(FirebaseJson *js, FirebaseJsonArray *rangeArr, const char *valueInputOption, const char *includeValuesInResponse, const char *responseValueRenderOption, const char *responseDateTimeRenderOption); bool mUpdate(bool append, operation_type_t type, FirebaseJson *response, const char *spreadsheetId, const char *range, FirebaseJson *valueRange, const char *valueInputOption = "USER_ENTERED", const char *insertDataOption = "", const char *includeValuesInResponse = "", const char *responseValueRenderOption = "", const char *responseDateTimeRenderOption = ""); bool mClear(FirebaseJson *response, const char *spreadsheetId, const char *ranges, operation_type_t type); @@ -542,16 +537,16 @@ class GSheet_Values protected: template - auto toString(const T &val) -> typename FB_JS::enable_if::value || FB_JS::is_arduino_string::value || FB_JS::is_mb_string::value || FB_JS::is_same::value, const char *>::type { return val.c_str(); } + auto toString(const T &val) -> typename mb_string::enable_if::value || mb_string::is_arduino_string::value || mb_string::is_mb_string::value || mb_string::is_same::value, const char *>::type { return val.c_str(); } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return val; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return val; } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return (const char *)val; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return (const char *)val; } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return ""; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return ""; } }; class GSheet_Sheets @@ -591,16 +586,16 @@ class GSheet_Sheets protected: template - auto toString(const T &val) -> typename FB_JS::enable_if::value || FB_JS::is_arduino_string::value || FB_JS::is_mb_string::value || FB_JS::is_same::value, const char *>::type { return val.c_str(); } + auto toString(const T &val) -> typename mb_string::enable_if::value || mb_string::is_arduino_string::value || mb_string::is_mb_string::value || mb_string::is_same::value, const char *>::type { return val.c_str(); } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return val; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return val; } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return (const char *)val; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return (const char *)val; } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return ""; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return ""; } }; class GSheet_Metadata @@ -654,16 +649,16 @@ class GSheet_Metadata protected: template - auto toString(const T &val) -> typename FB_JS::enable_if::value || FB_JS::is_arduino_string::value || FB_JS::is_mb_string::value || FB_JS::is_same::value, const char *>::type { return val.c_str(); } + auto toString(const T &val) -> typename mb_string::enable_if::value || mb_string::is_arduino_string::value || mb_string::is_mb_string::value || mb_string::is_same::value, const char *>::type { return val.c_str(); } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return val; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return val; } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return (const char *)val; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return (const char *)val; } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return ""; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return ""; } }; class ESP_Google_Sheet_Client @@ -937,16 +932,16 @@ class ESP_Google_Sheet_Client protected: template - auto toString(const T &val) -> typename FB_JS::enable_if::value || FB_JS::is_arduino_string::value || FB_JS::is_mb_string::value || FB_JS::is_same::value, const char *>::type { return val.c_str(); } + auto toString(const T &val) -> typename mb_string::enable_if::value || mb_string::is_arduino_string::value || mb_string::is_mb_string::value || mb_string::is_same::value, const char *>::type { return val.c_str(); } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return val; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return val; } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return (const char *)val; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return (const char *)val; } template - auto toString(T val) -> typename FB_JS::enable_if::value, const char *>::type { return ""; } + auto toString(T val) -> typename mb_string::enable_if::value, const char *>::type { return ""; } }; extern ESP_Google_Sheet_Client GSheet; diff --git a/src/lib/ESPSigner/ESPSigner.cpp b/src/lib/ESPSigner/ESPSigner.cpp index 5134001..d1ee6d6 100644 --- a/src/lib/ESPSigner/ESPSigner.cpp +++ b/src/lib/ESPSigner/ESPSigner.cpp @@ -1,38 +1,35 @@ /** - * Google's OAuth2.0 Access token Generation class, Signer.h version 1.1.1 - * + * Google's OAuth2.0 Access token Generation class, Signer.h version 1.1.2 + * * This library used RS256 for signing algorithm. - * + * * The signed JWT token will be generated and exchanged with the access token in the final generating process. - * + * * This library supports Espressif ESP8266 and ESP32 - * - * Created November 12, 2021 - * - * This work is a part of Firebase ESP Client library - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * + * + * Created April 18, 2022 + * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * + * Copyright (c) 2022 K. Suwatchai (Mobizt) + * + * * Permission is hereby granted, free of charge, to any person returning a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ + */ #ifndef ESP_SIGNER_CPP #define ESP_SIGNER_CPP @@ -264,7 +261,7 @@ bool ESP_Signer::isExpired() if (!config) return false; - //if the time was set (changed) after token has been generated, update its expiration + // if the time was set (changed) after token has been generated, update its expiration if (config->signer.tokens.expires > 0 && config->signer.tokens.expires < ESP_DEFAULT_TS && time(nullptr) > ESP_DEFAULT_TS) config->signer.tokens.expires += time(nullptr) - (millis() - config->signer.tokens.last_millis) / 1000 - 60; @@ -422,34 +419,34 @@ void ESP_Signer::setTokenError(int code) switch (code) { case ESP_SIGNER_ERROR_TOKEN_SET_TIME: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_21, true); + config->signer.tokens.error.message = esp_signer_pgm_str_21; break; case ESP_SIGNER_ERROR_TOKEN_PARSE_PK: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_22, true); + config->signer.tokens.error.message = esp_signer_pgm_str_22; break; case ESP_SIGNER_ERROR_TOKEN_CREATE_HASH: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_23, true); + config->signer.tokens.error.message = esp_signer_pgm_str_23; break; case ESP_SIGNER_ERROR_TOKEN_SIGN: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_24, true); + config->signer.tokens.error.message = esp_signer_pgm_str_24; break; case ESP_SIGNER_ERROR_TOKEN_EXCHANGE: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_25, true); + config->signer.tokens.error.message = esp_signer_pgm_str_25; break; case ESP_SIGNER_ERROR_TOKEN_NOT_READY: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_26, true); + config->signer.tokens.error.message = esp_signer_pgm_str_26; break; case ESP_SIGNER_ERROR_TOKEN_EXCHANGE_MAX_RETRY_REACHED: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_27, true); + config->signer.tokens.error.message = esp_signer_pgm_str_27; break; case ESP_SIGNER_ERROR_TCP_ERROR_NOT_CONNECTED: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_28); + config->signer.tokens.error.message += esp_signer_pgm_str_28; break; case ESP_SIGNER_ERROR_TCP_ERROR_CONNECTION_LOST: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_29); + config->signer.tokens.error.message += esp_signer_pgm_str_29; break; case ESP_SIGNER_ERROR_HTTP_CODE_REQUEST_TIMEOUT: - ut->appendP(config->signer.tokens.error.message, esp_signer_pgm_str_30); + config->signer.tokens.error.message += esp_signer_pgm_str_30; break; default: @@ -553,7 +550,7 @@ bool ESP_Signer::handleSignerError(int code, int httpCode) if (config->signer.result) delete config->signer.result; - config->signer.wcs= NULL; + config->signer.wcs = NULL; config->signer.json = NULL; config->signer.result = NULL; @@ -605,7 +602,7 @@ bool ESP_Signer::parseJsonResponse(PGM_P key_path) return config->signer.result->success; } -bool ESP_Signer::handleServerResponse(int &httpCode) +bool ESP_Signer::handleTokenResponse(int &httpCode) { if (config->_int.esp_signer_reconnect_wifi) ut->reconnect(0); @@ -622,11 +619,9 @@ bool ESP_Signer::handleServerResponse(int &httpCode) int chunkedDataState = 0; int chunkedDataSize = 0; int chunkedDataLen = 0; - MBSTRING header, payload; + MB_String header, payload; bool isHeader = false; - WiFiClient *stream = config->signer.wcs->stream(); - while (stream->connected() && stream->available() == 0) { if (!ut->reconnect(dataTime)) @@ -780,7 +775,7 @@ bool ESP_Signer::createJWT() config->signer.tokens.jwt.clear(); - //header + // header char *tmp = ut->strP(esp_signer_pgm_str_33); char *tmp2 = ut->strP(esp_signer_pgm_str_34); config->signer.json->add(tmp, (const char *)tmp2); @@ -792,7 +787,7 @@ bool ESP_Signer::createJWT() ut->delP(&tmp); ut->delP(&tmp2); - MBSTRING hdr; + MB_String hdr; config->signer.json->toString(hdr); size_t len = ut->base64EncLen(hdr.length()); char *buf = (char *)ut->newP(len); @@ -802,7 +797,7 @@ bool ESP_Signer::createJWT() config->signer.encHeadPayload = config->signer.encHeader; hdr.clear(); - //payload + // payload config->signer.json->clear(); tmp = ut->strP(esp_signer_pgm_str_37); config->signer.json->add(tmp, config->service_account.data.client_email.c_str()); @@ -811,15 +806,14 @@ bool ESP_Signer::createJWT() config->signer.json->add(tmp, config->service_account.data.client_email.c_str()); ut->delP(&tmp); tmp = ut->strP(esp_signer_pgm_str_39); - MBSTRING t; - ut->appendP(t, esp_signer_pgm_str_40); + MB_String t = esp_signer_pgm_str_40; if (config->signer.tokens.token_type == esp_signer_token_type_oauth2_access_token) { - ut->appendP(t, esp_signer_pgm_str_41); - ut->appendP(t, esp_signer_pgm_str_42); - ut->appendP(t, esp_signer_pgm_str_43); - ut->appendP(t, esp_signer_pgm_str_44); - ut->appendP(t, esp_signer_pgm_str_45); + t += esp_signer_pgm_str_41; + t += esp_signer_pgm_str_42; + t += esp_signer_pgm_str_43; + t += esp_signer_pgm_str_44; + t += esp_signer_pgm_str_45; } config->signer.json->add(tmp, t.c_str()); @@ -841,16 +835,16 @@ bool ESP_Signer::createJWT() if (config->signer.tokens.token_type == esp_signer_token_type_oauth2_access_token) { - MBSTRING s; + MB_String s; if (config->signer.tokens.scope.length() > 0) { - std::vector scopes = std::vector(); + std::vector scopes = std::vector(); ut->splitTk(config->signer.tokens.scope, scopes, ","); for (size_t i = 0; i < scopes.size(); i++) { if (s.length() > 0) - ut->appendP(s, esp_signer_pgm_str_32); + s += esp_signer_pgm_str_32; s += scopes[i]; scopes[i].clear(); } @@ -862,7 +856,7 @@ bool ESP_Signer::createJWT() ut->delP(&tmp); } - MBSTRING payload; + MB_String payload; config->signer.json->toString(payload); len = ut->base64EncLen(payload.length()); @@ -872,13 +866,13 @@ bool ESP_Signer::createJWT() ut->delP(&buf); payload.clear(); - ut->appendP(config->signer.encHeadPayload, esp_signer_pgm_str_42); + config->signer.encHeadPayload += esp_signer_pgm_str_42; config->signer.encHeadPayload += config->signer.encPayload; config->signer.encHeader.clear(); config->signer.encPayload.clear(); -//create message digest from encoded header and payload +// create message digest from encoded header and payload #if defined(ESP32) config->signer.hash = (uint8_t *)ut->newP(config->signer.hashSize); int ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), (const unsigned char *)config->signer.encHeadPayload.c_str(), config->signer.encHeadPayload.length(), config->signer.hash); @@ -903,7 +897,7 @@ bool ESP_Signer::createJWT() #endif config->signer.tokens.jwt = config->signer.encHeadPayload; - ut->appendP(config->signer.tokens.jwt, esp_signer_pgm_str_42); + config->signer.tokens.jwt += esp_signer_pgm_str_42; config->signer.encHeadPayload.clear(); delete config->signer.json; @@ -917,7 +911,7 @@ bool ESP_Signer::createJWT() config->signer.pk_ctx = new mbedtls_pk_context(); mbedtls_pk_init(config->signer.pk_ctx); - //parse priv key + // parse priv key int ret = 0; if (config->signer.pk.length() > 0) ret = mbedtls_pk_parse_key(config->signer.pk_ctx, (const unsigned char *)config->signer.pk.c_str(), config->signer.pk.length() + 1, NULL, 0); @@ -939,7 +933,7 @@ bool ESP_Signer::createJWT() return false; } - //generate RSA signature from private key and message digest + // generate RSA signature from private key and message digest config->signer.signature = (unsigned char *)ut->newP(config->signer.signatureSize); size_t sigLen = 0; config->signer.entropy_ctx = new mbedtls_entropy_context(); @@ -985,10 +979,10 @@ bool ESP_Signer::createJWT() if (ret != 0) return false; #elif defined(ESP8266) - //RSA private key + // RSA private key BearSSL::PrivateKey *pk = nullptr; ut->idle(); - //parse priv key + // parse priv key if (config->signer.pk.length() > 0) pk = new BearSSL::PrivateKey((const char *)config->signer.pk.c_str()); else if (strlen_P(config->service_account.data.private_key) > 0) @@ -1013,7 +1007,7 @@ bool ESP_Signer::createJWT() const br_rsa_private_key *br_rsa_key = pk->getRSA(); - //generate RSA signature from private key and message digest + // generate RSA signature from private key and message digest config->signer.signature = new unsigned char[config->signer.signatureSize]; ut->idle(); @@ -1028,7 +1022,7 @@ bool ESP_Signer::createJWT() ut->delP(&buf); ut->delP(&config->signer.signature); delete pk; - //get the signed JWT + // get the signed JWT if (ret > 0) { config->signer.tokens.jwt += config->signer.encSignature; @@ -1069,31 +1063,30 @@ bool ESP_Signer::requestTokens() config->_int.esp_signer_last_jwt_generation_error_cb_millis = 0; sendTokenStatusCB(); - if (config->signer.wcs) - delete config->signer.wcs; - config->signer.wcs = new ESP_SIGNER_TCP_Client(); + +#if defined(ESP32) config->signer.wcs->setCACert(nullptr); +#elif defined(ESP8266) + config->signer.wcs->setBufferSizes(1024, 1024); +#endif config->signer.json = new FirebaseJson(); config->signer.result = new FirebaseJsonData(); - MBSTRING host; - ut->appendP(host, esp_signer_pgm_str_48); - ut->appendP(host, esp_signer_pgm_str_42); - ut->appendP(host, esp_signer_pgm_str_43); + MB_String host = esp_signer_pgm_str_48; + host += esp_signer_pgm_str_42; + host += esp_signer_pgm_str_43; ut->idle(); + + config->signer.wcs->begin(host.c_str(), 443); #if defined(ESP8266) ut->ethDNSWorkAround(&ut->config->spi_ethernet_module, host.c_str(), 443); #endif - config->signer.wcs->begin(host.c_str(), 443); - - - MBSTRING req; - ut->appendP(req, esp_signer_pgm_str_57); - ut->appendP(req, esp_signer_pgm_str_32); + MB_String req = esp_signer_pgm_str_57; + req += esp_signer_pgm_str_32; if (config->signer.tokens.token_type == esp_signer_token_type_oauth2_access_token) { @@ -1106,28 +1099,29 @@ bool ESP_Signer::requestTokens() config->signer.json->add(tmp, config->signer.tokens.jwt.c_str()); ut->delP(&tmp); - ut->appendP(req, esp_signer_pgm_str_44); - ut->appendP(req, esp_signer_pgm_str_45); - ut->appendP(req, esp_signer_pgm_str_61); - ut->appendP(req, esp_signer_pgm_str_62); - ut->appendP(req, esp_signer_pgm_str_41); + req += esp_signer_pgm_str_44; + req += esp_signer_pgm_str_45; + req += esp_signer_pgm_str_61; + req += esp_signer_pgm_str_62; + req += esp_signer_pgm_str_41; } - ut->appendP(req, esp_signer_pgm_str_42); - ut->appendP(req, esp_signer_pgm_str_43); + req += esp_signer_pgm_str_42; + req += esp_signer_pgm_str_43; - ut->appendP(req, esp_signer_pgm_str_4); - ut->appendP(req, esp_signer_pgm_str_64); - ut->appendP(req, esp_signer_pgm_str_65); - req += NUM2S(strlen(config->signer.json->raw())).get(); - ut->appendP(req, esp_signer_pgm_str_4); - ut->appendP(req, esp_signer_pgm_str_66); - ut->appendP(req, esp_signer_pgm_str_67); - ut->appendP(req, esp_signer_pgm_str_4); - ut->appendP(req, esp_signer_pgm_str_4); + req += esp_signer_pgm_str_4; + req += esp_signer_pgm_str_64; + req += esp_signer_pgm_str_65; + req += strlen(config->signer.json->raw()); + req += esp_signer_pgm_str_4; + req += esp_signer_pgm_str_66; + req += esp_signer_pgm_str_67; + req += esp_signer_pgm_str_4; + req += esp_signer_pgm_str_4; req += config->signer.json->raw(); + config->signer.wcs->setInsecure(); int ret = config->signer.wcs->send(req.c_str()); req.clear(); if (ret < 0) @@ -1136,7 +1130,7 @@ bool ESP_Signer::requestTokens() struct esp_signer_auth_token_error_t error; int httpCode = 0; - if (handleServerResponse(httpCode)) + if (handleTokenResponse(httpCode)) { config->signer.tokens.jwt.clear(); if (parseJsonResponse(esp_signer_pgm_str_68)) @@ -1160,7 +1154,7 @@ bool ESP_Signer::requestTokens() if (error.code != 0 && config->signer.tokens.token_type == esp_signer_token_type_oauth2_access_token) { - //new jwt needed as it is already cleared + // new jwt needed as it is already cleared config->signer.step = esp_signer_jwt_generation_step_encode_header_payload; } @@ -1206,7 +1200,7 @@ void ESP_Signer::checkToken() if (!config) return; - //if the time was set (changed) after token has been generated, update its expiration + // if the time was set (changed) after token has been generated, update its expiration if (config->signer.tokens.expires > 0 && config->signer.tokens.expires < ESP_DEFAULT_TS && time(nullptr) > ESP_DEFAULT_TS) config->signer.tokens.expires += time(nullptr) - (millis() - config->signer.tokens.last_millis) / 1000 - 60; @@ -1255,14 +1249,14 @@ String ESP_Signer::getTokenType(TokenInfo info) if (!config) return ""; - MBSTRING s; + MB_String s; switch (info.type) { case esp_signer_token_type_undefined: - ut->appendP(s, esp_signer_pgm_str_49); + s = esp_signer_pgm_str_49; break; case esp_signer_token_type_oauth2_access_token: - ut->appendP(s, esp_signer_pgm_str_50); + s = esp_signer_pgm_str_50; break; default: break; @@ -1280,30 +1274,30 @@ String ESP_Signer::getTokenStatus(TokenInfo info) if (!config) return ""; - MBSTRING s; + MB_String s; switch (info.status) { case esp_signer_token_status_uninitialized: - ut->appendP(s, esp_signer_pgm_str_51); + s = esp_signer_pgm_str_51; break; case esp_signer_token_status_on_initialize: - ut->appendP(s, esp_signer_pgm_str_52); + s = esp_signer_pgm_str_52; break; case esp_signer_token_status_on_signing: - ut->appendP(s, esp_signer_pgm_str_53); + s = esp_signer_pgm_str_53; break; case esp_signer_token_status_on_request: - ut->appendP(s, esp_signer_pgm_str_54); + s = esp_signer_pgm_str_54; break; case esp_signer_token_status_on_refresh: - ut->appendP(s, esp_signer_pgm_str_55); + s = esp_signer_pgm_str_55; break; case esp_signer_token_status_ready: - ut->appendP(s, esp_signer_pgm_str_112); + s = esp_signer_pgm_str_112; break; case esp_signer_token_status_error: - ut->appendP(s, esp_signer_pgm_str_113); + s = esp_signer_pgm_str_113; break; default: break; @@ -1321,10 +1315,9 @@ String ESP_Signer::getTokenError(TokenInfo info) if (!config) return ""; - MBSTRING s; - ut->appendP(s, esp_signer_pgm_str_114); - s += NUM2S(info.error.code).get(); - ut->appendP(s, esp_signer_pgm_str_115); + MB_String s = esp_signer_pgm_str_114; + s += info.error.code; + s += esp_signer_pgm_str_115; s += info.error.message; return s.c_str(); } @@ -1345,7 +1338,7 @@ void ESP_Signer::refreshToken() checkToken(); } -void ESP_Signer::errorToString(int httpCode, MBSTRING &buff) +void ESP_Signer::errorToString(int httpCode, MB_String &buff) { buff.clear(); @@ -1361,118 +1354,118 @@ void ESP_Signer::errorToString(int httpCode, MBSTRING &buff) switch (httpCode) { case ESP_SIGNER_ERROR_TCP_ERROR_CONNECTION_REFUSED: - ut->appendP(buff, esp_signer_pgm_str_73); + buff += esp_signer_pgm_str_73; return; case ESP_SIGNER_ERROR_TCP_ERROR_SEND_HEADER_FAILED: - ut->appendP(buff, esp_signer_pgm_str_74); + buff += esp_signer_pgm_str_74; return; case ESP_SIGNER_ERROR_TCP_ERROR_SEND_PAYLOAD_FAILED: - ut->appendP(buff, esp_signer_pgm_str_75); + buff += esp_signer_pgm_str_75; return; case ESP_SIGNER_ERROR_TCP_ERROR_NOT_CONNECTED: - ut->appendP(buff, esp_signer_pgm_str_28); + buff += esp_signer_pgm_str_28; return; case ESP_SIGNER_ERROR_TCP_ERROR_CONNECTION_LOST: - ut->appendP(buff, esp_signer_pgm_str_29); + buff += esp_signer_pgm_str_29; return; case ESP_SIGNER_ERROR_TCP_ERROR_NO_HTTP_SERVER: - ut->appendP(buff, esp_signer_pgm_str_76); + buff += esp_signer_pgm_str_76; return; case ESP_SIGNER_ERROR_HTTP_CODE_BAD_REQUEST: - ut->appendP(buff, esp_signer_pgm_str_77); + buff += esp_signer_pgm_str_77; return; case ESP_SIGNER_ERROR_HTTP_CODE_NON_AUTHORITATIVE_INFORMATION: - ut->appendP(buff, esp_signer_pgm_str_78); + buff += esp_signer_pgm_str_78; return; case ESP_SIGNER_ERROR_HTTP_CODE_NO_CONTENT: - ut->appendP(buff, esp_signer_pgm_str_79); + buff += esp_signer_pgm_str_79; return; case ESP_SIGNER_ERROR_HTTP_CODE_MOVED_PERMANENTLY: - ut->appendP(buff, esp_signer_pgm_str_80); + buff += esp_signer_pgm_str_80; return; case ESP_SIGNER_ERROR_HTTP_CODE_USE_PROXY: - ut->appendP(buff, esp_signer_pgm_str_81); + buff += esp_signer_pgm_str_81; return; case ESP_SIGNER_ERROR_HTTP_CODE_TEMPORARY_REDIRECT: - ut->appendP(buff, esp_signer_pgm_str_82); + buff += esp_signer_pgm_str_82; return; case ESP_SIGNER_ERROR_HTTP_CODE_PERMANENT_REDIRECT: - ut->appendP(buff, esp_signer_pgm_str_83); + buff += esp_signer_pgm_str_83; return; case ESP_SIGNER_ERROR_HTTP_CODE_UNAUTHORIZED: - ut->appendP(buff, esp_signer_pgm_str_84); + buff += esp_signer_pgm_str_84; return; case ESP_SIGNER_ERROR_HTTP_CODE_FORBIDDEN: - ut->appendP(buff, esp_signer_pgm_str_85); + buff += esp_signer_pgm_str_85; return; case ESP_SIGNER_ERROR_HTTP_CODE_NOT_FOUND: - ut->appendP(buff, esp_signer_pgm_str_86); + buff += esp_signer_pgm_str_86; return; case ESP_SIGNER_ERROR_HTTP_CODE_METHOD_NOT_ALLOWED: - ut->appendP(buff, esp_signer_pgm_str_87); + buff += esp_signer_pgm_str_87; return; case ESP_SIGNER_ERROR_HTTP_CODE_NOT_ACCEPTABLE: - ut->appendP(buff, esp_signer_pgm_str_88); + buff += esp_signer_pgm_str_88; return; case ESP_SIGNER_ERROR_HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED: - ut->appendP(buff, esp_signer_pgm_str_89); + buff += esp_signer_pgm_str_89; return; case ESP_SIGNER_ERROR_HTTP_CODE_REQUEST_TIMEOUT: - ut->appendP(buff, esp_signer_pgm_str_30); + buff += esp_signer_pgm_str_30; return; case ESP_SIGNER_ERROR_HTTP_CODE_LENGTH_REQUIRED: - ut->appendP(buff, esp_signer_pgm_str_90); + buff += esp_signer_pgm_str_90; return; case ESP_SIGNER_ERROR_HTTP_CODE_TOO_MANY_REQUESTS: - ut->appendP(buff, esp_signer_pgm_str_91); + buff += esp_signer_pgm_str_91; return; case ESP_SIGNER_ERROR_HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE: - ut->appendP(buff, esp_signer_pgm_str_92); + buff += esp_signer_pgm_str_92; return; case ESP_SIGNER_ERROR_HTTP_CODE_INTERNAL_SERVER_ERROR: - ut->appendP(buff, esp_signer_pgm_str_93); + buff += esp_signer_pgm_str_93; return; case ESP_SIGNER_ERROR_HTTP_CODE_BAD_GATEWAY: - ut->appendP(buff, esp_signer_pgm_str_94); + buff += esp_signer_pgm_str_94; return; case ESP_SIGNER_ERROR_HTTP_CODE_SERVICE_UNAVAILABLE: - ut->appendP(buff, esp_signer_pgm_str_95); + buff += esp_signer_pgm_str_95; return; case ESP_SIGNER_ERROR_HTTP_CODE_GATEWAY_TIMEOUT: - ut->appendP(buff, esp_signer_pgm_str_96); + buff += esp_signer_pgm_str_96; return; case ESP_SIGNER_ERROR_HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED: - ut->appendP(buff, esp_signer_pgm_str_97); + buff += esp_signer_pgm_str_97; return; case ESP_SIGNER_ERROR_HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED: - ut->appendP(buff, esp_signer_pgm_str_98); + buff += esp_signer_pgm_str_98; return; case ESP_SIGNER_ERROR_HTTP_CODE_PRECONDITION_FAILED: - ut->appendP(buff, esp_signer_pgm_str_99); + buff += esp_signer_pgm_str_99; return; case ESP_SIGNER_ERROR_TCP_RESPONSE_PAYLOAD_READ_TIMED_OUT: - ut->appendP(buff, esp_signer_pgm_str_100); + buff += esp_signer_pgm_str_100; return; case ESP_SIGNER_ERROR_TCP_ERROR_CONNECTION_INUSED: - ut->appendP(buff, esp_signer_pgm_str_101); + buff += esp_signer_pgm_str_101; return; case ESP_SIGNER_ERROR_BUFFER_OVERFLOW: - ut->appendP(buff, esp_signer_pgm_str_102); + buff += esp_signer_pgm_str_102; return; case ESP_SIGNER_ERROR_HTTP_CODE_PAYLOAD_TOO_LARGE: - ut->appendP(buff, esp_signer_pgm_str_103); + buff += esp_signer_pgm_str_103; return; case ESP_SIGNER_ERROR_FILE_IO_ERROR: - ut->appendP(buff, esp_signer_pgm_str_104); + buff += esp_signer_pgm_str_104; return; case ESP_SIGNER_ERROR_FILE_NOT_FOUND: - ut->appendP(buff, esp_signer_pgm_str_105); + buff += esp_signer_pgm_str_105; return; case ESP_SIGNER_ERROR_TOKEN_NOT_READY: - ut->appendP(buff, esp_signer_pgm_str_26); + buff += esp_signer_pgm_str_26; return; case ESP_SIGNER_ERROR_UNINITIALIZED: - ut->appendP(buff, esp_signer_pgm_str_106); + buff += esp_signer_pgm_str_106; return; default: return; diff --git a/src/lib/ESPSigner/ESPSigner.h b/src/lib/ESPSigner/ESPSigner.h index 71af831..17938fe 100644 --- a/src/lib/ESPSigner/ESPSigner.h +++ b/src/lib/ESPSigner/ESPSigner.h @@ -1,5 +1,5 @@ /** - * Google's OAuth2.0 Access token Generation class, Signer.h version 1.1.1 + * Google's OAuth2.0 Access token Generation class, Signer.h version 1.1.2 * * This library used RS256 for signing algorithm. * @@ -7,13 +7,10 @@ * * This library supports Espressif ESP8266 and ESP32 * - * Created November 12, 2021 - * - * This work is a part of Firebase ESP Client library - * Copyright (c) 2021 K. Suwatchai (Mobizt) + * Created April 18, 2022 * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2022 K. Suwatchai (Mobizt) * * * Permission is hereby granted, free of charge, to any person returning a copy of @@ -170,13 +167,13 @@ class ESP_Signer void setTokenError(int code); bool handleSignerError(int code, int httpCode = 0); bool parseJsonResponse(PGM_P key_path); - bool handleServerResponse(int &httpCode); + bool handleTokenResponse(int &httpCode); void tokenProcessingTask(); bool createJWT(); bool requestTokens(); void getExpiration(const char *exp); void checkToken(); - void errorToString(int httpCode, MBSTRING &buff); + void errorToString(int httpCode, MB_String &buff); void sendTokenStatusCB(); unsigned long getExpireMS(); bool isExpired(); diff --git a/src/lib/ESPSigner/SignerCommon.h b/src/lib/ESPSigner/SignerConst.h similarity index 89% rename from src/lib/ESPSigner/SignerCommon.h rename to src/lib/ESPSigner/SignerConst.h index a628e25..2f22ff9 100644 --- a/src/lib/ESPSigner/SignerCommon.h +++ b/src/lib/ESPSigner/SignerConst.h @@ -1,30 +1,29 @@ /** - * Created December 12, 2021 - * - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * + * Created April 18, 2022 + * + * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * + * Copyright (c) 2022 K. Suwatchai (Mobizt) + * + * * Permission is hereby granted, free of charge, to any person returning a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ + */ #ifndef FB_COMMON_H_ #define FB_COMMON_H_ @@ -49,7 +48,6 @@ #define FS_NO_GLOBALS #endif - #define SD_CS_PIN 15 #define MAX_REDIRECT 5 #define WIFI_RECONNECT_TIMEOUT 10000 @@ -106,8 +104,8 @@ typedef struct esp_signer_spi_ethernet_module_t struct esp_signer_url_info_t { - MBSTRING host; - MBSTRING uri; + MB_String host; + MB_String uri; }; struct esp_signer_server_response_data_t @@ -119,24 +117,24 @@ struct esp_signer_server_response_data_t int payloadOfs = 0; bool noContent = false; bool isChunkedEnc = false; - MBSTRING location = ""; - MBSTRING contentType = ""; - MBSTRING connection = ""; - MBSTRING transferEnc = ""; + MB_String location = ""; + MB_String contentType = ""; + MB_String connection = ""; + MB_String transferEnc = ""; }; struct esp_signer_auth_token_error_t { - MBSTRING message; + MB_String message; int code = 0; }; struct esp_signer_auth_token_info_t { - MBSTRING access_token; - MBSTRING auth_type; - MBSTRING jwt; - MBSTRING scope; + MB_String access_token; + MB_String auth_type; + MB_String jwt; + MB_String scope; unsigned long expires = 0; unsigned long last_millis = 0; esp_signer_auth_token_type token_type = esp_signer_token_type_undefined; @@ -146,29 +144,29 @@ struct esp_signer_auth_token_info_t struct esp_signer_service_account_data_info_t { - MBSTRING client_email; - MBSTRING client_id; - MBSTRING project_id; - MBSTRING private_key_id; + MB_String client_email; + MB_String client_id; + MB_String project_id; + MB_String private_key_id; const char *private_key = ""; }; struct esp_signer_auth_signin_user_t { - MBSTRING email; - MBSTRING password; + MB_String email; + MB_String password; }; struct esp_signer_auth_cert_t { const char *data = ""; - MBSTRING file; + MB_String file; esp_signer_mem_storage_type file_storage = esp_signer_mem_storage_type_flash; }; struct esp_signer_service_account_file_info_t { - MBSTRING path; + MB_String path; esp_signer_mem_storage_type storage_type = esp_signer_mem_storage_type_flash; }; @@ -187,8 +185,8 @@ struct esp_signer_token_signer_resources_t unsigned long preRefreshSeconds = 60; unsigned long expiredSeconds = 3600; unsigned long reqTO = 2000; - MBSTRING pk; - size_t hashSize = 32; //SHA256 size (256 bits or 32 bytes) + MB_String pk; + size_t hashSize = 32; // SHA256 size (256 bits or 32 bytes) size_t signatureSize = 256; #if defined(ESP32) uint8_t *hash = nullptr; @@ -196,10 +194,10 @@ struct esp_signer_token_signer_resources_t char *hash = nullptr; #endif unsigned char *signature = nullptr; - MBSTRING encHeader; - MBSTRING encPayload; - MBSTRING encHeadPayload; - MBSTRING encSignature; + MB_String encHeader; + MB_String encPayload; + MB_String encHeadPayload; + MB_String encSignature; #if defined(ESP32) mbedtls_pk_context *pk_ctx = nullptr; mbedtls_entropy_context *entropy_ctx = nullptr; @@ -213,7 +211,6 @@ struct esp_signer_token_signer_resources_t struct esp_signer_auth_token_info_t tokens; }; - struct esp_signer_cfg_int_t { struct esp_signer_sd_config_info_t sd_config; @@ -238,21 +235,21 @@ struct esp_signer_cfg_int_t struct esp_signer_client_timeout_t { - //WiFi reconnect timeout (interval) in ms (10 sec - 5 min) when WiFi disconnected. + // WiFi reconnect timeout (interval) in ms (10 sec - 5 min) when WiFi disconnected. uint16_t wifiReconnect = 10 * 1000; - //Socket connection and ssl handshake timeout in ms (1 sec - 1 min). + // Socket connection and ssl handshake timeout in ms (1 sec - 1 min). unsigned long socketConnection = 10 * 1000; - //unused. + // unused. unsigned long sslHandshake = 0; - //Server response read timeout in ms (1 sec - 1 min). + // Server response read timeout in ms (1 sec - 1 min). unsigned long serverResponse = 10 * 1000; uint16_t tokenGenerationBeginStep = 300; - uint16_t tokenGenerationError = 5*1000; + uint16_t tokenGenerationError = 5 * 1000; }; typedef struct token_info_t @@ -277,20 +274,19 @@ struct esp_signer_cfg_t struct esp_signer_client_timeout_t timeout; }; - struct esp_signer_session_info_t { bool buffer_ovf = false; bool chunked_encoding = false; bool connected = false; - MBSTRING host = ""; + MB_String host = ""; unsigned long last_conn_ms = 0; const uint32_t conn_timeout = 3 * 60 * 1000; uint16_t resp_size = 2048; int http_code = -1000; int content_length = 0; - MBSTRING error = ""; + MB_String error = ""; #if defined(ESP8266) uint16_t bssl_rx_size = 512; @@ -302,8 +298,8 @@ typedef struct esp_signer_cfg_t SignerConfig; typedef std::function esp_signer_callback_function_t; -//static const char esp_signer_pgm_str_1[] PROGMEM = "true"; -//static const char esp_signer_pgm_str_2[] PROGMEM = "double"; +// static const char esp_signer_pgm_str_1[] PROGMEM = "true"; +// static const char esp_signer_pgm_str_2[] PROGMEM = "double"; static const char esp_signer_pgm_str_3[] PROGMEM = "Connection: "; static const char esp_signer_pgm_str_4[] PROGMEM = "\r\n"; static const char esp_signer_pgm_str_5[] PROGMEM = "Content-Type: "; @@ -364,7 +360,7 @@ static const char esp_signer_pgm_str_59[] PROGMEM = "urn:ietf:params:oauth:grant static const char esp_signer_pgm_str_60[] PROGMEM = "assertion"; static const char esp_signer_pgm_str_61[] PROGMEM = " HTTP/1.1\r\n"; static const char esp_signer_pgm_str_62[] PROGMEM = "Host: "; -//static const char esp_signer_pgm_str_63[] PROGMEM = "\r\n"; +// static const char esp_signer_pgm_str_63[] PROGMEM = "\r\n"; static const char esp_signer_pgm_str_64[] PROGMEM = "User-Agent: ESP\r\n"; static const char esp_signer_pgm_str_65[] PROGMEM = "Content-Length: "; static const char esp_signer_pgm_str_66[] PROGMEM = "Content-Type: "; diff --git a/src/lib/ESPSigner/SignerUtils.h b/src/lib/ESPSigner/SignerUtils.h index 67e31b4..54c013a 100644 --- a/src/lib/ESPSigner/SignerUtils.h +++ b/src/lib/ESPSigner/SignerUtils.h @@ -1,40 +1,39 @@ /** - * Util class, SignerUtils.h version 1.0.1 - * - * This library supports Espressif ESP8266 and ESP32 - * - * Created May 4, 2021 - * - * This work is a part of Firebase ESP Client library - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * + * Util class, SignerUtils.h version 1.0.3 + * + * + * Created April 18, 2022 + * + * This work is a part of ESP Signer library + * Copyright (c) 2022 K. Suwatchai (Mobizt) + * * The MIT License (MIT) - * Copyright (c)2021 K. Suwatchai (Mobizt) - * - * + * Copyright (c)2022 K. Suwatchai (Mobizt) + * + * * Permission is hereby granted, free of charge, to any person returning a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ + */ #ifndef SIGNER_UTILS_H #define SIGNER_UTILS_H #include -#include "SignerCommon.h" +#include "SignerConst.h" class SignerUtils { @@ -177,15 +176,6 @@ class SignerUtils return nullptr; } - void appendP(MBSTRING &buf, PGM_P p, bool empty = false) - { - if (empty) - buf.clear(); - char *b = strP(p); - buf += b; - delP(&b); - } - void strcat_c(char *str, char c) { for (; *str; str++) @@ -308,24 +298,24 @@ class SignerUtils return -1; } - void ltrim(MBSTRING &str, const MBSTRING &chars = " ") + void ltrim(MB_String &str, const MB_String &chars = " ") { size_t pos = str.find_first_not_of(chars); - if (pos != MBSTRING::npos) + if (pos != MB_String::npos) str.erase(0, pos); } - void rtrim(MBSTRING &str, const MBSTRING &chars = " ") + void rtrim(MB_String &str, const MB_String &chars = " ") { size_t pos = str.find_last_not_of(chars); - if (pos != MBSTRING::npos) + if (pos != MB_String::npos) str.erase(pos + 1); } - inline MBSTRING trim(const MBSTRING &s) + inline MB_String trim(const MB_String &s) { - MBSTRING chars = " "; - MBSTRING str = s; + MB_String chars = " "; + MB_String str = s; ltrim(str, chars); rtrim(str, chars); return str; @@ -382,7 +372,7 @@ class SignerUtils return p; } - void substr(MBSTRING &str, const char *s, int offset, size_t len) + void substr(MB_String &str, const char *s, int offset, size_t len) { if (!s) return; @@ -400,11 +390,11 @@ class SignerUtils for (int i = offset; i < last; i++) str += s[i]; } - void splitString(const char *str, std::vector out, const char delim) + void splitString(const char *str, std::vector out, const char delim) { int current = 0, previous = 0; current = strpos(str, delim, 0); - MBSTRING s; + MB_String s; while (current != -1) { s.clear(); @@ -454,9 +444,9 @@ class SignerUtils return o - dec; } - MBSTRING url_encode(const MBSTRING &s) + MB_String url_encode(const MB_String &s) { - MBSTRING ret; + MB_String ret; ret.reserve(s.length() * 3 + 1); for (size_t i = 0, l = s.size(); i < l; i++) { @@ -633,7 +623,7 @@ class SignerUtils return idx; } - int readLine(WiFiClient *stream, MBSTRING &buf) + int readLine(WiFiClient *stream, MB_String &buf) { int res = -1; char c = 0; @@ -692,7 +682,7 @@ class SignerUtils delP(&tmp); } - //last chunk + // last chunk if (chunkedSize < 1) olen = -1; } @@ -711,7 +701,7 @@ class SignerUtils if (readLen > 0) { - //chunk may contain trailing + // chunk may contain trailing if (dataLen + readLen - 2 < chunkedSize) { dataLen += readLen; @@ -739,7 +729,7 @@ class SignerUtils return olen; } - int readChunkedData(WiFiClient *stream, MBSTRING &out, int &chunkState, int &chunkedSize, int &dataLen) + int readChunkedData(WiFiClient *stream, MB_String &out, int &chunkState, int &chunkedSize, int &dataLen) { char *tmp = nullptr; @@ -751,7 +741,7 @@ class SignerUtils chunkState = 1; chunkedSize = -1; dataLen = 0; - MBSTRING s; + MB_String s; int readLen = readLine(stream, s); if (readLen) { @@ -773,7 +763,7 @@ class SignerUtils delP(&tmp); } - //last chunk + // last chunk if (chunkedSize < 1) olen = -1; } @@ -785,12 +775,12 @@ class SignerUtils if (chunkedSize > -1) { - MBSTRING s; + MB_String s; int readLen = readLine(stream, s); if (readLen > 0) { - //chunk may contain trailing + // chunk may contain trailing if (dataLen + readLen - 2 < chunkedSize) { dataLen += readLen; @@ -857,9 +847,9 @@ class SignerUtils return nullptr; } - void getHeaderStr(const MBSTRING &in, MBSTRING &out, PGM_P beginH, PGM_P endH, int &beginPos, int endPos) + void getHeaderStr(const MB_String &in, MB_String &out, PGM_P beginH, PGM_P endH, int &beginPos, int endPos) { - MBSTRING _in = in; + MB_String _in = in; char *tmp = strP(beginH); int p1 = strpos(in.c_str(), tmp, beginPos); @@ -912,7 +902,7 @@ class SignerUtils } } - bool decodeBase64Str(const MBSTRING &src, std::vector &out) + bool decodeBase64Str(const MB_String &src, std::vector &out) { unsigned char *dtable = (unsigned char *)newP(256); memset(dtable, 0x80, 256); @@ -1068,7 +1058,7 @@ class SignerUtils return false; } - void sendBase64Stream(WiFiClient *client, const MBSTRING &filePath, uint8_t storageType, fs::File &file) + void sendBase64Stream(WiFiClient *client, const MB_String &filePath, uint8_t storageType, fs::File &file) { if (storageType == esp_signer_mem_storage_type_flash) @@ -1430,12 +1420,12 @@ class SignerUtils return ret; } - MBSTRING encodeBase64Str(const unsigned char *src, size_t len) + MB_String encodeBase64Str(const unsigned char *src, size_t len) { return encodeBase64Str((uint8_t *)src, len); } - MBSTRING encodeBase64Str(uint8_t *src, size_t len) + MB_String encodeBase64Str(uint8_t *src, size_t len) { unsigned char *out, *pos; const unsigned char *end, *in; @@ -1447,7 +1437,7 @@ class SignerUtils olen = 4 * ((len + 2) / 3); /* 3-byte blocks to 4-byte */ - MBSTRING outStr; + MB_String outStr; outStr.resize(olen); out = (unsigned char *)&outStr[0]; @@ -1570,7 +1560,7 @@ class SignerUtils if (!config) return false; - MBSTRING filepath = "/sdtest01.txt"; + MB_String filepath = "/sdtest01.txt"; #if defined(CARD_TYPE_SD) if (!sdBegin(config->_int.sd_config.ss, config->_int.sd_config.sck, config->_int.sd_config.miso, config->_int.sd_config.mosi)) return false; @@ -1609,7 +1599,7 @@ class SignerUtils SD_FS.remove(filepath.c_str()); - MBSTRING().swap(filepath); + MB_String().swap(filepath); config->_int.esp_signer_sd_rdy = true; @@ -1628,7 +1618,6 @@ class SignerUtils } #endif - bool waitIdle(int &httpCode) { #if defined(ESP32) @@ -1647,12 +1636,12 @@ class SignerUtils return true; } - void splitTk(const MBSTRING &str, std::vector &tk, const char *delim) + void splitTk(const MB_String &str, std::vector &tk, const char *delim) { std::size_t current, previous = 0; current = str.find(delim, previous); - MBSTRING s; - while (current != MBSTRING::npos) + MB_String s; + while (current != MB_String::npos) { s = str.substr(previous, current - previous); tk.push_back(s); @@ -1661,7 +1650,7 @@ class SignerUtils } s = str.substr(previous, current - previous); tk.push_back(s); - MBSTRING().swap(s); + MB_String().swap(s); } bool reconnect(unsigned long dataTime) @@ -1696,7 +1685,7 @@ class SignerUtils { if (config->_int.esp_signer_reconnect_wifi) { - if (config->timeout.wifiReconnect < 10000 || config->timeout.wifiReconnect > 5 *60 *1000) + if (config->timeout.wifiReconnect < 10000 || config->timeout.wifiReconnect > 5 * 60 * 1000) config->timeout.wifiReconnect = 10000; if (millis() - config->_int.esp_signer_last_reconnect_millis > config->timeout.wifiReconnect) { diff --git a/src/lib/ESPSigner/json/FirebaseJson.cpp b/src/lib/ESPSigner/json/FirebaseJson.cpp index fa2cd84..3bbe0b1 100644 --- a/src/lib/ESPSigner/json/FirebaseJson.cpp +++ b/src/lib/ESPSigner/json/FirebaseJson.cpp @@ -1,42 +1,40 @@ - /* - * FirebaseJson, version 2.6.3 - * + * FirebaseJson, version 2.6.16 + * * The Easiest Arduino library to parse, create and edit JSON object using a relative path. - * - * December 20, 2021 - * + * + * Created April 18, 2022 + * * Features - * - Using path to access node element in search style e.g. json.get(result,"a/b/c") - * - Able to search with key/path and value in JSON object and array + * - Using path to access node element in search style e.g. json.get(result,"a/b/c") * - Serializing to writable objects e.g. String, C/C++ string, Client (WiFi and Ethernet), File and Hardware Serial. - * - Deserializing from const char, char array, string literal and stream e.g. Client (WiFi and Ethernet), File and + * - Deserializing from const char, char array, string literal and stream e.g. Client (WiFi and Ethernet), File and * Hardware Serial. * - Use managed class, FirebaseJsonData to keep the deserialized result, which can be casted to any primitive data types. - * - * + * + * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2022 K. Suwatchai (Mobizt) * Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - * - * + * + * * Permission is hereby granted, free of charge, to any person returning a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ + */ #ifndef FirebaseJson_CPP #define FirebaseJson_CPP @@ -102,7 +100,7 @@ void FirebaseJsonBase::prepareRoot() } } -void FirebaseJsonBase::searchElements(std::vector &keys, MB_JSON *parent, struct search_result_t &r) +void FirebaseJsonBase::searchElements(MB_VECTOR &keys, MB_JSON *parent, struct search_result_t &r) { MB_JSON *e = parent; for (size_t i = 0; i < keys.size(); i++) @@ -149,7 +147,7 @@ MB_JSON *FirebaseJsonBase::getElement(MB_JSON *parent, const char *key, struct s return e; } -void FirebaseJsonBase::mAdd(std::vector keys, MB_JSON **parent, int beginIndex, MB_JSON *value) +void FirebaseJsonBase::mAdd(MB_VECTOR keys, MB_JSON **parent, int beginIndex, MB_JSON *value) { MB_JSON *m_parent = *parent; @@ -187,13 +185,13 @@ void FirebaseJsonBase::mAdd(std::vector keys, MB_JSON **parent, int be } } -void FirebaseJsonBase::makeList(const char *str, std::vector &keys, char delim) +void FirebaseJsonBase::makeList(const char *str, MB_VECTOR &keys, char delim) { clearList(keys); int current = 0, previous = 0; current = strpos(str, delim, 0); - MBSTRING s; + MB_String s; while (current != -1) { s.clear(); @@ -219,7 +217,7 @@ void FirebaseJsonBase::makeList(const char *str, std::vector &keys, ch s.clear(); } -void FirebaseJsonBase::clearList(std::vector &keys) +void FirebaseJsonBase::clearList(MB_VECTOR &keys) { size_t len = keys.size(); for (size_t i = 0; i < len; i++) @@ -227,7 +225,9 @@ void FirebaseJsonBase::clearList(std::vector &keys) for (int i = len - 1; i >= 0; i--) keys.erase(keys.begin() + i); keys.clear(); - std::vector().swap(keys); +#if defined(MB_USE_STD_VECTOR) + MB_VECTOR().swap(keys); +#endif } bool FirebaseJsonBase::isArray(MB_JSON *e) @@ -247,7 +247,7 @@ MB_JSON *FirebaseJsonBase::addArray(MB_JSON *parent, MB_JSON *e, size_t size) return e; } -void FirebaseJsonBase::appendArray(std::vector &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *value) +void FirebaseJsonBase::appendArray(MB_VECTOR &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *value) { MB_JSON *item = NULL; @@ -282,7 +282,7 @@ void FirebaseJsonBase::appendArray(std::vector &keys, struct search_re MB_JSON_Delete(value); } -void FirebaseJsonBase::replaceItem(std::vector &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *value) +void FirebaseJsonBase::replaceItem(MB_VECTOR &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *value) { if (r.foundIndex == -1) { @@ -323,7 +323,7 @@ void FirebaseJsonBase::replaceItem(std::vector &keys, struct search_re } } -void FirebaseJsonBase::replace(std::vector &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *item) +void FirebaseJsonBase::replace(MB_VECTOR &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *item) { if (isArray(parent)) MB_JSON_ReplaceItemInArray(parent, getArrIndex(keys[r.foundIndex].c_str()), item); @@ -342,24 +342,20 @@ size_t FirebaseJsonBase::mIteratorBegin(MB_JSON *parent) MB_JSON_free(p); iterator_data.buf_size = buf.length(); int index = -1; - mIterate(parent, index, NULL); + mIterate(parent, index); return iterator_data.result.size(); } -size_t FirebaseJsonBase::mIteratorBegin(MB_JSON *parent, std::vector *keys, struct fb_js_search_criteria_t *criteria) +size_t FirebaseJsonBase::mIteratorBegin(MB_JSON *parent, MB_VECTOR *keys) { mIteratorEnd(); - if (keys == NULL || criteria == NULL) + if (keys == NULL) return 0; - iterator_data.searchEnable = true; - iterator_data.searchKeys = keys; int index = -1; - mIterate(parent, index, criteria); + mIterate(parent, index); - if (criteria->searchAll) - iterator_data.searchFinished = iterator_data.matchesCount > 0; return iterator_data.result.size(); } @@ -371,30 +367,18 @@ void FirebaseJsonBase::mIteratorEnd(bool clearBuf) iterator_data.buf_size = 0; iterator_data.buf_offset = 0; iterator_data.result.clear(); - iterator_data.pathList.clear(); iterator_data.depth = -1; iterator_data._depth = 0; - iterator_data.searchEnable = false; - iterator_data.searchFinished = false; - iterator_data.searchKeyDepth = -1; - iterator_data.matchesCount = 0; - iterator_data.searchKeys = NULL; if (iterator_data.parentArr != NULL) MB_JSON_Delete(iterator_data.parentArr); iterator_data.parentArr = NULL; } -void FirebaseJsonBase::mIterate(MB_JSON *parent, int &arrIndex, struct fb_js_search_criteria_t *criteria) +void FirebaseJsonBase::mIterate(MB_JSON *parent, int &arrIndex) { if (!parent) return; - if (iterator_data.searchEnable && !criteria->searchAll && iterator_data.searchFinished) - { - iterator_data.parent = parent; - return; - } - bool isAr = isArray(parent); if (isAr) @@ -406,14 +390,9 @@ void FirebaseJsonBase::mIterate(MB_JSON *parent, int &arrIndex, struct fb_js_sea iterator_data.depth++; while (e) { - if (iterator_data.searchEnable && !criteria->searchAll && iterator_data.searchFinished) - return; - - if (isAr && iterator_data.searchEnable) - collectResult(e, NULL, arrIndex, criteria); if (isArray(e) || isObject(e)) - mCollectIterator(e, e->string ? JSON_OBJECT : JSON_ARRAY, arrIndex, criteria); + mCollectIterator(e, e->string ? JSON_OBJECT : JSON_ARRAY, arrIndex); if (isArray(e)) { @@ -425,276 +404,60 @@ void FirebaseJsonBase::mIterate(MB_JSON *parent, int &arrIndex, struct fb_js_sea iterator_data.depth++; while (item) { - if (iterator_data.searchEnable && !criteria->searchAll && iterator_data.searchFinished) - return; - - if (iterator_data.searchEnable) - collectResult(item, NULL, _arrIndex, criteria); if (isArray(item) || isObject(item)) - mIterate(item, _arrIndex, criteria); + mIterate(item, _arrIndex); else - mCollectIterator(item, item->string ? JSON_OBJECT : JSON_ARRAY, _arrIndex, criteria); + mCollectIterator(item, item->string ? JSON_OBJECT : JSON_ARRAY, _arrIndex); item = item->next; _arrIndex++; } - - if (iterator_data.searchEnable && !criteria->searchAll && iterator_data.searchFinished) - return; - - removeDepthPath(); } } else if (isObject(e)) - mIterate(e, arrIndex, criteria); + mIterate(e, arrIndex); else - mCollectIterator(e, e->string ? JSON_OBJECT : JSON_ARRAY, arrIndex, criteria); + mCollectIterator(e, e->string ? JSON_OBJECT : JSON_ARRAY, arrIndex); e = e->next; if (isAr) arrIndex++; } - - if (iterator_data.searchEnable && !criteria->searchAll && iterator_data.searchFinished) - return; - - removeDepthPath(); } } -void FirebaseJsonBase::collectResult(MB_JSON *e, const char *key, int arrIndex, struct fb_js_search_criteria_t *criteria) +void FirebaseJsonBase::mCollectIterator(MB_JSON *e, int type, int &arrIndex) { - if (!iterator_data.searchEnable) - return; - - bool searchComplete = false; - bool keyMatches = false; - int matchesCount = iterator_data.matchesCount; - MB_JSON *ref = e; - - if (key != NULL) - { - if ((iterator_data._depth == iterator_data.depth || iterator_data.depth == 0) && iterator_data.pathList.size() > 0) - iterator_data.pathList[iterator_data.pathList.size() - 1] = key; - else - iterator_data.pathList.push_back(key); - } - else if (arrIndex > -1) - { - MBSTRING ar = (const char *)FLASH_MCR("["); - ar += NUM2S(arrIndex).get(); - ar += (const char *)FLASH_MCR("]"); - - if (arrIndex > 0 && iterator_data.pathList.size() > 0) - iterator_data.pathList[iterator_data.pathList.size() - 1] = ar.c_str(); - else - iterator_data.pathList.push_back(ar.c_str()); - ar.clear(); - } - - if (criteria->path.length() > 0) - keyMatches = checkKeys(criteria); + struct iterator_result_t result; - if (criteria->value.length() == 0) + if (e->string) { - if (!criteria->searchAll) - searchComplete = keyMatches; - else if (keyMatches) - iterator_data.matchesCount++; - } - else - { - if (iterator_data.depth >= criteria->depth) + size_t pos = buf.find((const char *)e->string, iterator_data.buf_offset); + if (pos != MB_String::npos) { - if (criteria->endDepth > -1 && iterator_data.depth > criteria->endDepth + 1) - return; - - char *p = MB_JSON_PrintUnformatted(e); - if (p) - { - if (strcmp(criteria->value.c_str(), p) == 0) - { - if (criteria->path.length() > 0 && keyMatches && iterator_data.depth == iterator_data.searchKeyDepth) - { - if (!criteria->searchAll) - searchComplete = true; - else - iterator_data.matchesCount++; - } - } - MB_JSON_free(p); - } - } - } - - if (!criteria->searchAll) - { - if (searchComplete) - iterator_data.parent = e; - iterator_data.searchFinished = searchComplete; - } - else - { - if (matchesCount != iterator_data.matchesCount) - { - if (ref != NULL) - { - MB_JSON *itm = MB_JSON_Duplicate(ref, true); - if (itm != NULL) - { - if (iterator_data.parentArr == NULL) - iterator_data.parentArr = MB_JSON_CreateArray(); - MB_JSON_AddItemToArray(iterator_data.parentArr, itm); - } - } - - MBSTRING path; - mGetPath(path, iterator_data.pathList); - - if (iterator_data.path.length() > 0) - iterator_data.path += (const char *)FLASH_MCR(",\""); - else - iterator_data.path += (const char *)FLASH_MCR("[\""); - - iterator_data.path += path; - iterator_data.path += (const char *)FLASH_MCR("\""); - - path.clear(); + result.ofs1 = pos; + result.len1 = strlen(e->string); + iterator_data.buf_offset = (e->type != MB_JSON_Object && e->type != MB_JSON_Array) ? pos + result.len1 : pos; } } -} - -void FirebaseJsonBase::removeDepthPath() -{ - iterator_data.depth--; - if (iterator_data.searchEnable) - { - if (iterator_data._depth != iterator_data.depth && iterator_data.pathList.size() > 0) - iterator_data.pathList.pop_back(); - } -} -void FirebaseJsonBase::mCollectIterator(MB_JSON *e, int type, int &arrIndex, struct fb_js_search_criteria_t *criteria) -{ - if (!iterator_data.searchEnable) + char *p = MB_JSON_PrintUnformatted(e); + if (p) { - struct iterator_result_t result; - - if (e->string) - { - size_t pos = buf.find((const char *)e->string, iterator_data.buf_offset); - if (pos != MBSTRING::npos) - { - result.ofs1 = pos; - result.len1 = strlen(e->string); - iterator_data.buf_offset = (e->type != MB_JSON_Object && e->type != MB_JSON_Array) ? pos + result.len1 : pos; - } - } - - char *p = MB_JSON_PrintUnformatted(e); - if (p) + int i = iterator_data.buf_offset; + size_t pos = buf.find(p, i); + if (pos != MB_String::npos) { - int i = iterator_data.buf_offset; - size_t pos = buf.find(p, i); - if (pos != MBSTRING::npos) - { - result.ofs2 = pos - result.ofs1 - result.len1; - result.len2 = strlen(p); - MB_JSON_free(p); - iterator_data.buf_offset = (e->type != MB_JSON_Object && e->type != MB_JSON_Array) ? pos + result.len2 : pos; - } + result.ofs2 = pos - result.ofs1 - result.len1; + result.len2 = strlen(p); + MB_JSON_free(p); + iterator_data.buf_offset = (e->type != MB_JSON_Object && e->type != MB_JSON_Array) ? pos + result.len2 : pos; } - result.type = type; - result.depth = iterator_data.depth; - iterator_data.result.push_back(result); - } - else - { - if (type == JSON_OBJECT) - collectResult(e, e->string, -1, criteria); - - iterator_data._depth = iterator_data.depth; } -} - -bool FirebaseJsonBase::checkKeys(struct fb_js_search_criteria_t *criteria) -{ - - if (iterator_data.searchKeyDepth != -1 && (int)iterator_data.pathList.size() - 1 != iterator_data.searchKeyDepth) - return false; - - bool matches = false; - int index = -1; - int k = 0; - MBSTRING sPath, cPath; - - for (int i = 0; i < (int)iterator_data.searchKeys->size(); i++) - { - matches = false; - k = i; - if (iterator_data.searchKeys->at(k)[0] == '*') - { - while (iterator_data.searchKeys->at(k)[0] == '*' && k < (int)iterator_data.searchKeys->size()) - { - k++; - if (k > (int)iterator_data.searchKeys->size() - 1) - break; - } - } - - if (k < (int)iterator_data.searchKeys->size()) - { - if (sPath.length() > 0) - sPath += (const char *)FLASH_MCR("/"); - sPath += iterator_data.searchKeys->at(k); - } - - if (k + criteria->depth < (int)iterator_data.pathList.size() && k < (int)iterator_data.searchKeys->size()) - { - for (int j = k + criteria->depth; j < (int)iterator_data.pathList.size(); j++) - { - if (j == criteria->depth && iterator_data.searchKeys->at(k)[0] != '*' && iterator_data.searchKeys->at(k) != iterator_data.pathList[j]) - break; - - if (iterator_data.searchKeys->at(k) == iterator_data.pathList[j] && j > index) - { - if (criteria->endDepth != -1 && j > criteria->endDepth + 1) - break; - - if (k > 0) - { - if (iterator_data.searchKeys->at(k - 1)[0] == '*' && j - index == 1) - { - index = j; - continue; - } - } - - if (cPath.length() > 0) - cPath += (const char *)FLASH_MCR("/"); - cPath += iterator_data.searchKeys->at(k).c_str(); - index = j; - } - } - } - - if (sPath == cPath) - matches = true; - - if (!matches) - break; - - i = k; - } - - if (matches) - iterator_data.searchKeyDepth = iterator_data.depth; - - sPath.clear(); - cPath.clear(); - - return matches; + result.type = type; + result.depth = iterator_data.depth; + iterator_data.result.push_back(result); } int FirebaseJsonBase::mIteratorGet(size_t index, int &type, String &key, String &value) @@ -768,7 +531,7 @@ void FirebaseJsonBase::toBuf(fb_json_serialize_mode mode) bool FirebaseJsonBase::mReadClient(Client *client) { - //blocking read + // blocking read buf.clear(); if (readClient(client, buf)) { @@ -783,7 +546,7 @@ bool FirebaseJsonBase::mReadClient(Client *client) bool FirebaseJsonBase::mReadStream(Stream *s, int timeoutMS) { - //non-blocking read + // non-blocking read if (readStream(s, serData, buf, true, timeoutMS)) { if (root != NULL) @@ -795,6 +558,22 @@ bool FirebaseJsonBase::mReadStream(Stream *s, int timeoutMS) return false; } +#if defined(ESP32_SD_FAT_INCLUDED) +bool FirebaseJsonBase::mReadSdFat(SD_FAT_FILE &file, int timeoutMS) +{ + // non-blocking read + if (readSdFatFile(file, serData, buf, true, timeoutMS)) + { + if (root != NULL) + MB_JSON_Delete(root); + root = parse(buf.c_str()); + buf.clear(); + return root != NULL; + } + return false; +} +#endif + const char *FirebaseJsonBase::mRaw() { toBuf(fb_json_serialize_mode_plain); @@ -805,7 +584,7 @@ bool FirebaseJsonBase::mRemove(const char *path) { bool ret = false; prepareRoot(); - std::vector keys = std::vector(); + MB_VECTOR keys = MB_VECTOR(); makeList(path, keys, '/'); if (keys.size() > 0) @@ -833,7 +612,7 @@ bool FirebaseJsonBase::mRemove(const char *path) MB_JSON_DeleteItemFromObjectCaseSensitive(parent, keys[r.stopIndex].c_str()); if (parent->child == NULL && r.stopIndex > 0) { - MBSTRING path; + MB_String path; mGetPath(path, keys, 0, r.stopIndex - 1); mRemove(path.c_str()); } @@ -844,7 +623,7 @@ bool FirebaseJsonBase::mRemove(const char *path) return ret; } -void FirebaseJsonBase::mGetPath(MBSTRING &path, std::vector paths, int begin, int end) +void FirebaseJsonBase::mGetPath(MB_String &path, MB_VECTOR paths, int begin, int end) { if (end < 0 || end >= (int)paths.size()) end = paths.size() - 1; @@ -854,7 +633,7 @@ void FirebaseJsonBase::mGetPath(MBSTRING &path, std::vector paths, int for (int i = begin; i <= end; i++) { if (i > 0) - path += (const char *)FLASH_MCR("/"); + path += (const char *)MBSTRING_FLASH_MCR("/"); path += paths[i].c_str(); } } @@ -885,7 +664,7 @@ bool FirebaseJsonBase::mGet(MB_JSON *parent, FirebaseJsonData *result, const cha { bool ret = false; prepareRoot(); - std::vector keys = std::vector(); + MB_VECTOR keys = MB_VECTOR(); makeList(path, keys, '/'); if (keys.size() > 0) @@ -935,7 +714,11 @@ void FirebaseJsonBase::mSetResInt(FirebaseJsonData *data, const char *value) if (strlen(value) > 0) { char *pEnd; +#if !defined(__AVR__) value[0] == '-' ? data->iVal.int64 = strtoll(value, &pEnd, 10) : data->iVal.uint64 = strtoull(value, &pEnd, 10); +#else + value[0] == '-' ? data->iVal.int64 = strtol(value, &pEnd, 10) : data->iVal.uint64 = strtoull_alt(value); +#endif } else data->iVal = {0}; @@ -963,17 +746,17 @@ void FirebaseJsonBase::mSetElementType(FirebaseJsonData *result) char *buf = (char *)newP(32); if (result->type_num == MB_JSON_Invalid) { - strcpy(buf, (const char *)FLASH_MCR("undefined")); + strcpy(buf, (const char *)MBSTRING_FLASH_MCR("undefined")); result->typeNum = JSON_UNDEFINED; } else if (result->type_num == MB_JSON_Object) { - strcpy(buf, (const char *)FLASH_MCR("object")); + strcpy(buf, (const char *)MBSTRING_FLASH_MCR("object")); result->typeNum = JSON_OBJECT; } else if (result->type_num == MB_JSON_Array) { - strcpy(buf, (const char *)FLASH_MCR("array")); + strcpy(buf, (const char *)MBSTRING_FLASH_MCR("array")); result->typeNum = JSON_ARRAY; } else if (result->type_num == MB_JSON_String) @@ -983,18 +766,25 @@ void FirebaseJsonBase::mSetElementType(FirebaseJsonData *result) if (result->stringValue.c_str()[result->stringValue.length() - 1] == '"') result->stringValue.remove(result->stringValue.length() - 1, 1); - strcpy(buf, (const char *)FLASH_MCR("string")); + strcpy(buf, (const char *)MBSTRING_FLASH_MCR("string")); result->typeNum = JSON_STRING; + + // try casting the string to numbers + if (result->stringValue.length() <= 32) + { + mSetResInt(result, result->stringValue.c_str()); + mSetResFloat(result, result->stringValue.c_str()); + } } else if (result->type_num == MB_JSON_NULL) { - strcpy(buf, (const char *)FLASH_MCR("null")); + strcpy(buf, (const char *)MBSTRING_FLASH_MCR("null")); result->typeNum = JSON_NULL; } else if (result->type_num == MB_JSON_False || result->type_num == MB_JSON_True) { - strcpy(buf, (const char *)FLASH_MCR("boolean")); - bool t = strcmp(result->stringValue.c_str(), (const char *)FLASH_MCR("true")) == 0; + strcpy(buf, (const char *)MBSTRING_FLASH_MCR("boolean")); + bool t = strcmp(result->stringValue.c_str(), (const char *)MBSTRING_FLASH_MCR("true")) == 0; result->typeNum = JSON_BOOL; result->iVal = {t}; @@ -1009,23 +799,23 @@ void FirebaseJsonBase::mSetElementType(FirebaseJsonData *result) mSetResInt(result, result->stringValue.c_str()); mSetResFloat(result, result->stringValue.c_str()); - if (strpos(result->stringValue.c_str(), (const char *)FLASH_MCR("."), 0) > -1) + if (strpos(result->stringValue.c_str(), (const char *)MBSTRING_FLASH_MCR("."), 0) > -1) { double d = atof(result->stringValue.c_str()); if (d > 0x7fffffff) { - strcpy(buf, (const char *)FLASH_MCR("double")); + strcpy(buf, (const char *)MBSTRING_FLASH_MCR("double")); result->typeNum = JSON_DOUBLE; } else { - strcpy(buf, (const char *)FLASH_MCR("float")); + strcpy(buf, (const char *)MBSTRING_FLASH_MCR("float")); result->typeNum = JSON_FLOAT; } } else { - strcpy(buf, (const char *)FLASH_MCR("int")); + strcpy(buf, (const char *)MBSTRING_FLASH_MCR("int")); result->typeNum = JSON_INT; } } @@ -1037,7 +827,7 @@ void FirebaseJsonBase::mSetElementType(FirebaseJsonData *result) void FirebaseJsonBase::mSet(const char *path, MB_JSON *value) { prepareRoot(); - std::vector keys = std::vector(); + MB_VECTOR keys = MB_VECTOR(); makeList(path, keys, '/'); if (keys.size() > 0) @@ -1070,106 +860,17 @@ void FirebaseJsonBase::mSet(const char *path, MB_JSON *value) clearList(keys); } -size_t FirebaseJsonBase::mSearch(MB_JSON *parent, struct fb_js_search_criteria_t *criteria) +#if defined(__AVR__) +unsigned long long FirebaseJsonBase::strtoull_alt(const char *s) { - size_t ret = 0; - std::vector keys = std::vector(); - if (criteria->path.length() > 0) - makeList(criteria->path.c_str(), keys, '/'); - - mIteratorBegin(parent, &keys, criteria); - if (iterator_data.searchFinished) - ret = criteria->searchAll ? iterator_data.matchesCount : 1; - - mIteratorEnd(); - clearList(keys); - - return ret; -} - -size_t FirebaseJsonBase::mSearch(MB_JSON *parent, const char *path, bool searchAll) -{ - struct fb_js_search_criteria_t criteria; - criteria.searchAll = searchAll; - criteria.path = path; - return mSearch(parent, &criteria); -} - -const char *FirebaseJsonBase::mGetElementFullPath(MB_JSON *parent, const char *path, bool searchAll) -{ - struct fb_js_search_criteria_t criteria; - criteria.searchAll = searchAll; - criteria.path = path; - mSearch(parent, NULL, &criteria); - return buf.c_str(); -} - -size_t FirebaseJsonBase::mSearch(MB_JSON *parent, FirebaseJsonData *result, struct fb_js_search_criteria_t *criteria, bool prettify) -{ - size_t ret = 0; - - std::vector keys = std::vector(); - if (criteria->path.length() > 0) - makeList(criteria->path.c_str(), keys, '/'); - - mIteratorBegin(parent, &keys, criteria); - - if (iterator_data.searchFinished) + unsigned long long sum = 0; + while (*s) { - ret = criteria->searchAll ? iterator_data.matchesCount : 1; - if (criteria->searchAll) - { - if (result == NULL) - { - buf.clear(); - iterator_data.path += (const char *)FLASH_MCR("]"); - buf = iterator_data.path.c_str(); - } - else - { - if (iterator_data.parentArr != NULL) - { - char *p = prettify ? MB_JSON_Print(iterator_data.parentArr) : MB_JSON_PrintUnformatted(iterator_data.parentArr); - result->stringValue = p; - MB_JSON_free(p); - result->type_num = iterator_data.parentArr->type; - iterator_data.path += (const char *)FLASH_MCR("]"); - result->searchPath = iterator_data.path.c_str(); - result->success = true; - mSetElementType(result); - } - } - } - else - { - if (result == NULL) - { - buf.clear(); - mGetPath(buf, iterator_data.pathList); - } - else - { - MBSTRING path; - mGetPath(path, iterator_data.pathList); - result->searchPath = path.c_str(); - if (iterator_data.parent != NULL) - { - char *p = prettify ? MB_JSON_Print(iterator_data.parent) : MB_JSON_PrintUnformatted(iterator_data.parent); - result->stringValue = p; - MB_JSON_free(p); - result->type_num = iterator_data.parent->type; - result->success = true; - mSetElementType(result); - } - } - } + sum = sum * 10 + (*s++ - '0'); } - - mIteratorEnd(result != NULL); - clearList(keys); - - return ret; + return sum; } +#endif FirebaseJson &FirebaseJson::operator=(FirebaseJson other) { @@ -1192,9 +893,10 @@ FirebaseJson::~FirebaseJson() FirebaseJson &FirebaseJson::nAdd(const char *key, MB_JSON *value) { prepareRoot(); - std::vector keys = std::vector(); - //makeList(key, keys, '/'); - keys.push_back(key); + MB_VECTOR keys = MB_VECTOR(); + // makeList(key, keys, '/'); + MB_String ky = key; + keys.push_back(ky); if (value == NULL) value = MB_JSON_CreateNull(); @@ -1362,10 +1064,64 @@ bool FirebaseJsonData::mGetJSON(const char *source, FirebaseJson &json) return json.root != NULL; } +size_t FirebaseJsonData::getReservedLen(size_t len) +{ + int blen = len + 1; + + int newlen = (blen / 4) * 4; + + if (newlen < blen) + newlen += 4; + + return (size_t)newlen; +} + +void FirebaseJsonData::delP(void *ptr) +{ + void **p = (void **)ptr; + if (*p) + { + free(*p); + *p = 0; + } +} + +void *FirebaseJsonData::newP(size_t len) +{ + void *p; + size_t newLen = getReservedLen(len); +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + if (ESP.getPsramSize() > 0) + p = (void *)ps_malloc(newLen); + else + p = (void *)malloc(newLen); + if (!p) + return NULL; + +#else + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.setExternalHeap(); +#endif + + p = (void *)malloc(newLen); + bool nn = p ? true : false; + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.resetHeap(); +#endif + + if (!nn) + return NULL; + +#endif + memset(p, 0, newLen); + return p; +} + void FirebaseJsonData::clear() { stringValue.remove(0, stringValue.length()); - searchPath.remove(0, searchPath.length()); iVal = {0}; fVal.setd(0); intValue = 0; diff --git a/src/lib/ESPSigner/json/FirebaseJson.h b/src/lib/ESPSigner/json/FirebaseJson.h index 38bf5ef..ef1e53a 100644 --- a/src/lib/ESPSigner/json/FirebaseJson.h +++ b/src/lib/ESPSigner/json/FirebaseJson.h @@ -1,42 +1,40 @@ /* - * FirebaseJson, version 2.6.3 - * + * FirebaseJson, version 2.6.16 + * * The Easiest Arduino library to parse, create and edit JSON object using a relative path. - * - * December 20, 2021 - * + * + * Created April 18, 2022 + * * Features - * - Using path to access node element in search style e.g. json.get(result,"a/b/c") - * - Able to search with key/path and value in JSON object and array + * - Using path to access node element in search style e.g. json.get(result,"a/b/c") * - Serializing to writable objects e.g. String, C/C++ string, Client (WiFi and Ethernet), File and Hardware Serial. - * - Deserializing from const char, char array, string literal and stream e.g. Client (WiFi and Ethernet), File and + * - Deserializing from const char, char array, string literal and stream e.g. Client (WiFi and Ethernet), File and * Hardware Serial. * - Use managed class, FirebaseJsonData to keep the deserialized result, which can be casted to any primitive data types. - * - * + * + * * The MIT License (MIT) - * - * Copyright (c) 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2022 K. Suwatchai (Mobizt) * Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - * - * + * + * * Permission is hereby granted, free of charge, to any person returning a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ + */ #ifndef FirebaseJson_H #define FirebaseJson_H @@ -47,75 +45,47 @@ #undef min #undef max #endif +#if __has_include() + +#if defined(ESP8266) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +#include + +#define MB_JSON_FS_H +#endif #endif #include +#include +#include "MB_List.h" + +#if !defined(__AVR__) #include #include #include -#include #include #include - -#if __has_include() -#include -#endif - -#if defined(FIREBASEJSON_USE_PSRAM) || defined(FIREBASE_USE_PSRAM) -#define MB_STRING_USE_PSRAM -#endif -#include "MB_String.h" - -#ifndef USE_MB_STRING -#define USE_MB_STRING +#include +#else +#include #endif -#ifndef MBSTRING -#define MBSTRING MB_String +#if defined __has_include +#if __has_include() +#include #endif - -#ifdef Serial_Printf -#undef Serial_Printf #endif -#if defined(ESP8266) || defined(ESP32) -#include -#define FLASH_MCR FPSTR -#define FILE_SYSTEM fs::File -#define FBJS_ENABLE_FS -#define Serial_Printf Serial.printf - -#elif defined(ARDUINO_ARCH_SAMD) -#include -#include -#include "extras/SD/SD.h" -#define FLASH_MCR PSTR -#define FILE_SYSTEM File -#define FBJS_ENABLE_FS -#define HardwareSerial Serial_ - -#elif defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F4) -#define FLASH_MCR(s) (s) - -#elif defined(TEENSYDUINO) -#define FILE_SYSTEM File -#define FLASH_MCR(s) (s) -#define HardwareSerial usb_serial_class -#define Serial_Printf Serial.printf - +#if defined(FIREBASEJSON_USE_PSRAM) || defined(FIREBASE_USE_PSRAM) +#define MB_STRING_USE_PSRAM #endif -#if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F4) -#include "extras/print/printf.h" - -extern "C" __attribute__((weak)) void _putchar(char c) -{ - Serial.print(c); -} - -#define Serial_Printf printf +#include "MB_String.h" -#endif +using namespace mb_string; #include @@ -128,49 +98,37 @@ extern "C" } #endif -#if defined(FBJS_ENABLE_SOFTWARE_SERIAL) || defined(ESP8266) -#include -#define FB_JS_INCLUDE_SW_SERIAL -#endif +#define MB_SERIAL_CLASS decltype(Serial) -#ifdef FBJS_ENABLE_WIFI_CLIENT -#include -#define FB_JS_INCLUDE_WIFI_CLIENT +#ifdef Serial_Printf +#undef Serial_Printf #endif -#ifdef FBJS_ENABLE_WIFI_CLIENT_SECURE -#include -#define FB_JS_INCLUDE_WIFI_CLIENT_SECURE +#if defined(ESP32) && defined(SD_FAT_VERSION) +#define ESP32_SD_FAT_INCLUDED +#if defined(SD_FS_FILE) +#define SD_FAT_FILE SD_FS_FILE +#else +#define SD_FAT_FILE SdFile #endif - -#ifdef FBJS_ENABLE_ARDUINO_MQTT -#include -#define FB_JS_INCLUDE_ARDUINO_MQTT #endif -#ifdef FBJS_ENABLE_LW_MQTT -#include -#define FB_JS_INCLUDE_LW_MQTT -#endif +#if defined(ESP8266) || defined(ESP32) || defined(TEENSYDUINO) -#if __has_include() -#include -#define FB_JS_INCLUDE_WIFI_CLIENT -#endif +#define Serial_Printf Serial.printf -#if __has_include() -#include -#define FB_JS_INCLUDE_WIFI_CLIENT_SECURE -#endif +#elif defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F4) || defined(__AVR__) -#if __has_include() -#include -#define FB_JS_INCLUDE_ARDUINO_MQTT -#endif +#include "extras/print/fb_json_print.h" + +extern "C" __attribute__((weak)) void +fb_json_putchar(char c) +{ + Serial.print(c); +} + +#define Serial_Printf fb_json_printf -#if __has_include() -#include -#define FB_JS_INCLUDE_LW_MQTT #endif /// HTTP codes see RFC7231 @@ -214,8 +172,12 @@ static void *fb_js_malloc(size_t len) void *p; size_t newLen = getReservedLen(len); -#if defined(BOARD_HAS_PSRAM) && defined(FIREBASEJSON_USE_PSRAM) - if ((p = (void *)ps_malloc(newLen)) == 0) +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + if (ESP.getPsramSize() > 0) + p = (void *)ps_malloc(newLen); + else + p = (void *)malloc(newLen); + if (!p) return NULL; #else @@ -223,7 +185,8 @@ static void *fb_js_malloc(size_t len) ESP.setExternalHeap(); #endif - bool nn = ((p = (void *)malloc(newLen)) > 0); + p = (void *)malloc(newLen); + bool nn = p ? true : false; #if defined(ESP8266_USE_EXTERNAL_HEAP) ESP.resetHeap(); @@ -244,8 +207,11 @@ static void fb_js_free(void *ptr) static void *fb_js_realloc(void *ptr, size_t sz) { size_t newLen = getReservedLen(sz); -#if defined(BOARD_HAS_PSRAM) && defined(FIREBASEJSON_USE_PSRAM) - ptr = (void *)ps_realloc(ptr, newLen); +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + if (ESP.getPsramSize() > 0) + ptr = (void *)ps_realloc(ptr, newLen); + else + ptr = (void *)realloc(ptr, newLen); #else #if defined(ESP8266_USE_EXTERNAL_HEAP) @@ -267,577 +233,38 @@ static void *fb_js_realloc(void *ptr, size_t sz) static MB_JSON_Hooks MB_JSON_hooks __attribute__((used)) = {fb_js_malloc, fb_js_free, fb_js_realloc}; -namespace FB_JS -{ - template - struct enable_if - { - }; - template - struct enable_if - { - typedef T type; - }; - template - struct is_same - { - static bool const value = false; - }; - template - struct is_same - { - static bool const value = true; - }; - - template - struct is_num_int8 - { - static bool const value = FB_JS::is_same::value || FB_JS::is_same::value; - }; - - template - struct is_num_uint8 - { - static bool const value = FB_JS::is_same::value || FB_JS::is_same::value; - }; - - template - struct is_num_int16 - { - static bool const value = FB_JS::is_same::value || FB_JS::is_same::value; - }; - - template - struct is_num_uint16 - { - static bool const value = FB_JS::is_same::value || FB_JS::is_same::value; - }; - - template - struct is_num_int32 - { - static bool const value = FB_JS::is_same::value || FB_JS::is_same::value || - FB_JS::is_same::value || FB_JS::is_same::value || - FB_JS::is_same::value; - }; - - template - struct is_num_uint32 - { - static bool const value = FB_JS::is_same::value || FB_JS::is_same::value || - FB_JS::is_same::value; - }; - - template - struct is_num_int64 - { - static bool const value = FB_JS::is_same::value || FB_JS::is_same::value; - }; - - template - struct is_num_uint64 - { - static bool const value = FB_JS::is_same::value || FB_JS::is_same::value; - }; - - template - struct is_num_neg_int - { - static bool const value = FB_JS::is_num_int8::value || FB_JS::is_num_int16::value || - FB_JS::is_num_int32::value || FB_JS::is_num_int64::value; - }; - - template - struct is_num_pos_int - { - static bool const value = FB_JS::is_num_uint8::value || FB_JS::is_num_uint16::value || - FB_JS::is_num_uint32::value || FB_JS::is_num_uint64::value; - }; - - template - struct is_num_int - { - static bool const value = FB_JS::is_num_pos_int::value || FB_JS::is_num_neg_int::value; - }; - - template - struct is_num_float - { - static bool const value = FB_JS::is_same::value || FB_JS::is_same::value; - }; - - template - struct is_bool - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct cs_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct ccs_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct as_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct cas_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct ss_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct css_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct ssh_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct fs_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct mbs_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct cmbs_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct pgm_t - { - static bool const value = FB_JS::is_same::value; - }; - - template - struct is_const_chars - { - static bool const value = cs_t::value || ccs_t::value; - }; - - template - struct is_arduino_string - { - static bool const value = as_t::value || cas_t::value; - }; - - template - struct is_std_string - { - static bool const value = ss_t::value || css_t::value; - }; - - template - struct is_mb_string - { - static bool const value = mbs_t::value || cmbs_t::value; - }; - - template - struct is_string - { - static bool const value = is_const_chars::value || is_arduino_string::value || - ssh_t::value || fs_t::value || - is_std_string::value || is_mb_string::value; - }; - - typedef union - { - float floatval; - int32_t int32; - uint8_t byte[4]; - } intconv; - - struct server_response_data_t - { - int httpCode = -1; - int payloadLen = -1; - int contentLen = -1; - int chunkRange = 0; - int payloadOfs = 0; - bool isChunkedEnc = false; - bool noContent = false; - MBSTRING location; - MBSTRING contentType; - MBSTRING connection; - MBSTRING transferEnc; - }; - - struct serial_data_t - { - int pos = -1, start = -1, end = -1; - int scnt = 0, ecnt = 0; - MBSTRING buf; - unsigned long dataTime = 0; - }; -}; -class PGM2S -{ -public: - PGM2S() { init(1); } - PGM2S(PGM_P p) { strP(p); } - ~PGM2S() { delP(&buf); } - const char *get() const { return buf; } - -private: - void init(size_t sz) - { - delP(&buf); - buf = (char *)newP(sz + 1); - } - - void strP(PGM_P pgm) - { - size_t len = strlen_P(pgm) + 5; - init(len); - strcpy_P(buf, pgm); - buf[strlen_P(pgm)] = 0; - } - - void delP(void *ptr) - { - void **p = (void **)ptr; - if (*p) - { - free(*p); - *p = 0; - } - } - - size_t getReservedLen(size_t len) - { - int blen = len + 1; - - int newlen = (blen / 4) * 4; - - if (newlen < blen) - newlen += 4; - - return (size_t)newlen; - } - - void *newP(size_t len) - { - void *p; - size_t newLen = getReservedLen(len); -#if defined(BOARD_HAS_PSRAM) && defined(FIREBASEJSON_USE_PSRAM) - - if ((p = (void *)ps_malloc(newLen)) == 0) - return NULL; - -#else - -#if defined(ESP8266_USE_EXTERNAL_HEAP) - ESP.setExternalHeap(); -#endif - - bool nn = ((p = (void *)malloc(newLen)) > 0); - -#if defined(ESP8266_USE_EXTERNAL_HEAP) - ESP.resetHeap(); -#endif - - if (!nn) - return NULL; - -#endif - memset(p, 0, newLen); - return p; - } - - char *buf = nullptr; -}; - -class NUM2S -{ -public: - NUM2S() { nullStr(); } - NUM2S(unsigned long long value) { uint64Str(value); } - NUM2S(signed long long value) { int64Str(value); } - NUM2S(unsigned int value) { uint64Str(value); } - NUM2S(unsigned long value) { uint64Str(value); } - NUM2S(int value) { int64Str(value); } - NUM2S(bool value) { boolStr(value); } - NUM2S(float value, int precision = 5) { floatStr(value, precision); } - NUM2S(double value, int precision = 9) { doubleStr(value, precision); } - ~NUM2S() { delP(&buf); } - const char *get() const { return buf; } - -private: - /*** dtostrf function is taken from - * https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/avr/dtostrf.c - */ - - /*** - * dtostrf - Emulation for dtostrf function from avr-libc - * Copyright (c) 2013 Arduino. All rights reserved. - * Written by Cristian Maglie - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * This library 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 - * Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - char *dtostrf(double val, signed char width, unsigned char prec, char *sout) - { - //Commented code is the original version - /*** - char fmt[20]; - sprintf(fmt, "%%%d.%df", width, prec); - sprintf(sout, fmt, val); - return sout; - */ - - // Handle negative numbers - uint8_t negative = 0; - if (val < 0.0) - { - negative = 1; - val = -val; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for (int i = 0; i < prec; ++i) - { - rounding /= 10.0; - } - - val += rounding; - - // Extract the integer part of the number - unsigned long int_part = (unsigned long)val; - double remainder = val - (double)int_part; - - if (prec > 0) - { - // Extract digits from the remainder - unsigned long dec_part = 0; - double decade = 1.0; - for (int i = 0; i < prec; i++) - { - decade *= 10.0; - } - remainder *= decade; - dec_part = (int)remainder; - - if (negative) - { - sprintf(sout, "-%ld.%0*ld", int_part, prec, dec_part); - } - else - { - sprintf(sout, "%ld.%0*ld", int_part, prec, dec_part); - } - } - else - { - if (negative) - { - sprintf(sout, "-%ld", int_part); - } - else - { - sprintf(sout, "%ld", int_part); - } - } - // Handle minimum field width of the output string - // width is signed value, negative for left adjustment. - // Range -128,127 - - char *fmt = (char *)newP(129); - unsigned int w = width; - if (width < 0) - { - negative = 1; - w = -width; - } - else - { - negative = 0; - } - - if (strlen(sout) < w) - { - memset(fmt, ' ', 128); - fmt[w - strlen(sout)] = '\0'; - if (negative == 0) - { - char *tmp = (char *)newP(strlen(sout) + 1); - strcpy(tmp, sout); - strcpy(sout, fmt); - strcat(sout, tmp); - delP(&tmp); - } - else - { - // left adjustment - strcat(sout, fmt); - } - } - - delP(&fmt); - - return sout; - } - - void init(size_t sz) - { - delP(&buf); - buf = (char *)newP(sz + 1); - } - - void delP(void *ptr) - { - void **p = (void **)ptr; - if (*p) - { - free(*p); - *p = 0; - } - } - - size_t getReservedLen(size_t len) - { - int blen = len + 1; - - int newlen = (blen / 4) * 4; - - if (newlen < blen) - newlen += 4; - - return (size_t)newlen; - } - - void *newP(size_t len) - { - void *p; - size_t newLen = getReservedLen(len); -#if defined(BOARD_HAS_PSRAM) && defined(FIREBASEJSON_USE_PSRAM) - - if ((p = (void *)ps_malloc(newLen)) == 0) - return NULL; - -#else - -#if defined(ESP8266_USE_EXTERNAL_HEAP) - ESP.setExternalHeap(); -#endif - - bool nn = ((p = (void *)malloc(newLen)) > 0); - -#if defined(ESP8266_USE_EXTERNAL_HEAP) - ESP.resetHeap(); -#endif - - if (!nn) - return NULL; - -#endif - memset(p, 0, newLen); - return p; - } - - char *intStr(int value) - { - char *t = (char *)newP(36); - sprintf(t, (const char *)FLASH_MCR("%d"), value); - return t; - } - - void int64Str(signed long long value) - { - init(64); - sprintf(buf, (const char *)FLASH_MCR("%lld"), value); - } - - void uint64Str(unsigned long long value) - { - init(64); - sprintf(buf, (const char *)FLASH_MCR("%llu"), value); - } - - void boolStr(bool value) - { - init(8); - value ? strcpy(buf, (const char *)FLASH_MCR("true")) : strcpy(buf, (const char *)FLASH_MCR("false")); - } - - void floatStr(float value, int precision) - { - init(32); - dtostrf(value, (precision + 2), precision, buf); - trim(); - } +namespace fb_js +{ - void doubleStr(double value, int precision) + typedef union { - init(64); - dtostrf(value, (precision + 2), precision, buf); - trim(); - } + float floatval; + int32_t int32; + uint8_t byte[4]; + } intconv; - void nullStr() + struct server_response_data_t { - init(6); - strcpy(buf, (const char *)FLASH_MCR("null")); - } + int httpCode = -1; + int payloadLen = -1; + int contentLen = -1; + int chunkRange = 0; + int payloadOfs = 0; + bool isChunkedEnc = false; + bool noContent = false; + MB_String location; + MB_String contentType; + MB_String connection; + MB_String transferEnc; + }; - void trim() + struct serial_data_t { - size_t i = strlen(buf) - 1; - while (buf[i] == '0' && i > 0) - { - if (buf[i - 1] == '.') - { - i--; - break; - } - if (buf[i - 1] != '0') - break; - i--; - } - if (i < strlen(buf) - 1) - buf[i] = '\0'; - } - - char *buf = nullptr; + int pos = -1, start = -1, end = -1; + int scnt = 0, ecnt = 0; + MB_String buf; + unsigned long dataTime = 0; + }; }; class FirebaseJsonData @@ -852,156 +279,165 @@ class FirebaseJsonData /** * Get array data as FirebaseJsonArray object from FirebaseJsonData object. - * + * * @param jsonArray The returning FirebaseJsonArray object. * @return bool status for successful operation. * This should call after parse or get function. - */ + */ bool getArray(FirebaseJsonArray &jsonArray); /** * Get array data as FirebaseJsonArray object from string. - * + * * @param source The JSON array string. * @param jsonArray The returning FirebaseJsonArray object. * @return bool status for successful operation. - * This should call after parse or get function. - */ + * + * @note This should call after parse or get function. + */ template - bool getArray(T source, FirebaseJsonArray &jsonArray) { return mGetArray(getStr(source), jsonArray); } + bool getArray(T source, FirebaseJsonArray &jsonArray) + { + uint32_t addr = 0; + bool ret = mGetArray(getStr(source, addr), jsonArray); + delAddr(addr); + return ret; + } /** * Get JSON data as FirebaseJson object from FirebaseJsonData object. - * + * * @param json The returning FirebaseJson object. * @return bool status for successful operation. * This should call after parse or get function. - */ + */ bool getJSON(FirebaseJson &json); /** * Get JSON data as FirebaseJson object from string. - * + * * @param source The JSON string. * @param json The returning FirebaseJson object. * @return bool status for successful operation. - * This should call after parse or get function. - */ + * + * @note This should call after parse or get function. + */ template - bool getJSON(T source, FirebaseJson &json) { return mGetJSON(getStr(source), json); } + bool getJSON(T source, FirebaseJson &json) + { + uint32_t addr = 0; + bool ret = mGetJSON(getStr(source, addr), json); + delAddr(addr); + return ret; + } /** * Get the value by specific type from FirebaseJsonData object. * This should call after parse or get function. - */ + */ template - auto to() -> typename FB_JS::enable_if::value || FB_JS::is_num_float::value || FB_JS::is_bool::value, T>::type + auto to() -> typename MB_ENABLE_IF::value || is_num_float::value || is_bool::value, T>::type { - if (FB_JS::is_bool::value) + if (is_bool::value) return iVal.uint32 > 0; - else if (FB_JS::is_num_int8::value) + else if (is_num_int8::value) return iVal.int8; - else if (FB_JS::is_num_uint8::value) + else if (is_num_uint8::value) return iVal.uint8; - else if (FB_JS::is_num_int16::value) + else if (is_num_int16::value) return iVal.int16; - else if (FB_JS::is_num_uint16::value) + else if (is_num_uint16::value) return iVal.uint16; - else if (FB_JS::is_num_int32::value) + else if (is_num_int32::value) return iVal.int32; - else if (FB_JS::is_num_uint32::value) + else if (is_num_uint32::value) return iVal.uint32; - else if (FB_JS::is_num_int64::value) + else if (is_num_int64::value) return iVal.int64; - else if (FB_JS::is_num_uint64::value) + else if (is_num_uint64::value) return iVal.uint64; - else if (FB_JS::is_same::value) + else if (MB_IS_SAME::value) return fVal.f; - else if (FB_JS::is_same::value) + else if (MB_IS_SAME::value) return fVal.d; else return 0; } template - auto to() -> typename FB_JS::enable_if::value || FB_JS::is_std_string::value || FB_JS::is_arduino_string::value || FB_JS::is_mb_string::value, T>::type + auto to() -> typename MB_ENABLE_IF::value || is_std_string::value || is_arduino_string::value || is_mb_string::value, T>::type { return stringValue.c_str(); } template - auto get(T &json) -> typename FB_JS::enable_if::value>::type + auto get(T &json) -> typename MB_ENABLE_IF::value>::type { getJSON(json); } template - auto get(T &arr) -> typename FB_JS::enable_if::value>::type + auto get(T &arr) -> typename MB_ENABLE_IF::value>::type { getArray(arr); } /** * Clear internal buffer. - */ + */ void clear(); /** * The String value of parses data. - */ + */ String stringValue; /** * The int value of parses data. - */ + */ int intValue = 0; /** * The float value of parses data. - */ + */ float floatValue = 0.0f; /** - * The double value of parses data. - */ + * The double value of parses data. + */ double doubleValue = 0.0; /** * The bool value of parses data. - */ + */ bool boolValue = false; /** * The type String of parses data. - */ + */ String type; /** * The type (number) of parses data. - */ + */ uint8_t typeNum = 0; - /** - * The returning full path of current search. - */ - String searchPath; - /** * The success flag of parsing data. - */ + */ bool success = false; private: union IVal { - std::uint64_t uint64; - std::int64_t int64; - std::uint32_t uint32; - std::int32_t int32; - std::int16_t int16; - std::uint16_t uint16; - std::int8_t int8; - std::uint8_t uint8; + uint64_t uint64; + int64_t int64; + uint32_t uint32; + int32_t int32; + int16_t int16; + uint16_t uint16; + int8_t int8; + uint8_t uint8; }; struct FVal @@ -1027,19 +463,44 @@ class FirebaseJsonData bool mGetArray(const char *source, FirebaseJsonArray &jsonArray); bool mGetJSON(const char *source, FirebaseJson &json); + size_t getReservedLen(size_t len); + void delP(void *ptr); + void *newP(size_t len); -protected: template - auto getStr(const T &val) -> typename FB_JS::enable_if::value || FB_JS::is_arduino_string::value || FB_JS::is_mb_string::value || FB_JS::is_same::value, const char *>::type + auto getStr(const T &val, uint32_t &addr) -> typename MB_ENABLE_IF::value || is_arduino_string::value || is_mb_string::value || MB_IS_SAME::value, const char *>::type { + addr = 0; return val.c_str(); } template - auto getStr(T val) -> typename FB_JS::enable_if::value, const char *>::type { return val; } + auto getStr(T val, uint32_t &addr) -> typename MB_ENABLE_IF::value, const char *>::type + { + return getStr(reinterpret_cast(val), addr); + } template - auto getStr(T val) -> typename FB_JS::enable_if::value, const char *>::type { return (const char *)val; } + auto getStr(T val, uint32_t &addr) -> typename MB_ENABLE_IF::value, const char *>::type + { + int len = strlen_P((PGM_P)val) + 1; + char *out = (char *)newP(len); + uint8_t *d = reinterpret_cast(out); + while (len-- > 0) + *d++ = pgm_read_byte(val++); + addr = toAddr(*out); + return (const char *)out; + } + + void delAddr(uint32_t addr) + { + if (addr > 0) + { + char *s = addrTo(addr); + delP(&s); + s = NULL; + } + } }; class FirebaseJsonBase @@ -1064,13 +525,6 @@ class FirebaseJsonBase key_status_out_of_range = 3 }; - typedef enum - { - search_mode_none = 0, - search_mode_once = 1, - search_mode_all = 2 - } fb_json_search_mode; - struct search_result_t { MB_JSON *parent = NULL; @@ -1091,20 +545,14 @@ class FirebaseJsonBase struct iterator_data_t { - std::vector result; + MB_VECTOR result; int buf_offset = 0; size_t buf_size = 0; int depth = -1; int _depth = 0; - int searchKeyDepth = -1; - bool searchEnable = false; - bool searchFinished = false; - int matchesCount = 0; MB_JSON *parent = NULL; MB_JSON *parentArr = NULL; - MBSTRING path; - std::vector *searchKeys = NULL; - std::vector pathList; + MB_String path; }; struct fb_js_iterator_value_t @@ -1115,46 +563,37 @@ class FirebaseJsonBase String value; }; - struct fb_js_search_criteria_t - { - int depth = 0; - int endDepth = -1; - bool searchAll = false; - String path; - String value; - }; - FirebaseJsonBase &mClear(); void mIteratorEnd(bool clearBuf = true); bool setRaw(const char *raw); void prepareRoot(); MB_JSON *parse(const char *raw); - void searchElements(std::vector &keys, MB_JSON *parent, struct search_result_t &r); + void searchElements(MB_VECTOR &keys, MB_JSON *parent, struct search_result_t &r); MB_JSON *getElement(MB_JSON *parent, const char *key, struct search_result_t &r); - void mAdd(std::vector keys, MB_JSON **parent, int beginIndex, MB_JSON *value); - void makeList(const char *str, std::vector &keys, char delim); - void clearList(std::vector &keys); + void mAdd(MB_VECTOR keys, MB_JSON **parent, int beginIndex, MB_JSON *value); + void makeList(const char *str, MB_VECTOR &keys, char delim); + void clearList(MB_VECTOR &keys); bool isArray(MB_JSON *e); bool isObject(MB_JSON *e); MB_JSON *addArray(MB_JSON *parent, MB_JSON *e, size_t size); - void appendArray(std::vector &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *value); - void replaceItem(std::vector &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *value); - void replace(std::vector &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *item); + void appendArray(MB_VECTOR &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *value); + void replaceItem(MB_VECTOR &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *value); + void replace(MB_VECTOR &keys, struct search_result_t &r, MB_JSON *parent, MB_JSON *item); size_t mIteratorBegin(MB_JSON *parent); - size_t mIteratorBegin(MB_JSON *parent, std::vector *keys, struct fb_js_search_criteria_t *criteria); - void collectResult(MB_JSON *e, const char *key, int arrIndex, struct fb_js_search_criteria_t *criteria); - void removeDepthPath(); - void mCollectIterator(MB_JSON *e, int type, int &arrIndex, struct fb_js_search_criteria_t *criteria); - void mIterate(MB_JSON *parent, int &arrIndex, struct fb_js_search_criteria_t *criteria); - bool checkKeys(struct fb_js_search_criteria_t *criteria); + size_t mIteratorBegin(MB_JSON *parent, MB_VECTOR *keys); + void mCollectIterator(MB_JSON *e, int type, int &arrIndex); + void mIterate(MB_JSON *parent, int &arrIndex); int mIteratorGet(size_t index, int &type, String &key, String &value); struct fb_js_iterator_value_t mValueAt(size_t index); void toBuf(fb_json_serialize_mode mode); bool mReadClient(Client *client); bool mReadStream(Stream *s, int timeoutMS); +#if defined(ESP32_SD_FAT_INCLUDED) + bool mReadSdFat(SD_FAT_FILE &file, int timeoutMS); +#endif const char *mRaw(); bool mRemove(const char *path); - void mGetPath(MBSTRING &path, std::vector paths, int begin = 0, int end = -1); + void mGetPath(MB_String &path, MB_VECTOR paths, int begin = 0, int end = -1); size_t mGetSerializedBufferLength(bool prettify); void mSetFloatDigits(uint8_t digits); void mSetDoubleDigits(uint8_t digits); @@ -1165,10 +604,9 @@ class FirebaseJsonBase void mSetElementType(FirebaseJsonData *result); void mSet(const char *path, MB_JSON *value); void mCopy(FirebaseJsonBase &other); - size_t mSearch(MB_JSON *parent, struct fb_js_search_criteria_t *criteria); - size_t mSearch(MB_JSON *parent, FirebaseJsonData *result, struct fb_js_search_criteria_t *criteria, bool prettify = false); - size_t mSearch(MB_JSON *parent, const char *path, bool searchAll = false); - const char *mGetElementFullPath(MB_JSON *parent, const char *path, bool searchAll = false); +#if defined(__AVR__) + unsigned long long strtoull_alt(const char *s); +#endif public: enum fb_json_root_type @@ -1208,24 +646,37 @@ class FirebaseJsonBase uint8_t floatDigits = 5; int httpCode = 0; int errorPos = -1; - struct FB_JS::serial_data_t serData; + struct fb_js::serial_data_t serData; fb_json_root_type root_type = Root_Type_JSON; struct iterator_data_t iterator_data; MB_JSON *root = NULL; MB_JSON_Hooks *hooks = NULL; - MBSTRING buf; + MB_String buf; template - auto getStr(const T &val) -> typename FB_JS::enable_if::value || FB_JS::is_arduino_string::value || FB_JS::is_mb_string::value || FB_JS::is_same::value, const char *>::type + auto getStr(const T &val, uint32_t &addr) -> typename MB_ENABLE_IF::value || is_arduino_string::value || is_mb_string::value || MB_IS_SAME::value, const char *>::type { + addr = 0; return val.c_str(); } template - auto getStr(T val) -> typename FB_JS::enable_if::value, const char *>::type { return val; } + auto getStr(T val, uint32_t &addr) -> typename MB_ENABLE_IF::value, const char *>::type + { + return getStr(reinterpret_cast(val), addr); + } template - auto getStr(T val) -> typename FB_JS::enable_if::value, const char *>::type { return (const char *)val; } + auto getStr(T val, uint32_t &addr) -> typename MB_ENABLE_IF::value, const char *>::type + { + int len = strlen_P((PGM_P)val) + 1; + char *out = (char *)newP(len); + uint8_t *d = reinterpret_cast(out); + while (len-- > 0) + *d++ = pgm_read_byte(val++); + addr = toAddr(*out); + return (const char *)out; + } template bool toStringPtrHandler(T *ptr, bool prettify) @@ -1233,7 +684,7 @@ class FirebaseJsonBase if (!root || !ptr) return false; - if (std::is_same::value) + if (MB_IS_SAME::value) { char *p = prettify ? MB_JSON_Print(root) : MB_JSON_PrintUnformatted(root); if (p) @@ -1247,7 +698,7 @@ class FirebaseJsonBase } template - auto toStringHandler(T &out, bool prettify) -> typename FB_JS::enable_if::value, bool>::type + auto toStringHandler(T &out, bool prettify) -> typename MB_ENABLE_IF::value, bool>::type { if (!root) return false; @@ -1263,11 +714,7 @@ class FirebaseJsonBase } template -#ifdef FB_JS_INCLUDE_SW_SERIAL - auto toStringHandler(T &out, bool prettify) -> typename FB_JS::enable_if::value || FB_JS::is_same::value, bool>::type -#else - auto toStringHandler(T &out, bool prettify) -> typename FB_JS::enable_if::value, bool>::type -#endif + auto toStringHandler(T &out, bool prettify) -> typename MB_ENABLE_IF::value, bool>::type { char *p = prettify ? MB_JSON_Print(root) : MB_JSON_PrintUnformatted(root); if (p) @@ -1279,77 +726,38 @@ class FirebaseJsonBase return false; } -#ifdef FB_JS_INCLUDE_LW_MQTT - template - auto toStringHandler(T1 &out, T2 topic) -> typename FB_JS::enable_if::value && FB_JS::is_string::value, bool>::type - { - char *p = MB_JSON_PrintUnformatted(root); - if (p) - { - out.publish(topic, p); - MB_JSON_free(p); - return true; - } - return false; - } -#endif - -#if defined(FBJS_ENABLE_FS) - template - auto toStringHandler(T &out, bool prettify) -> typename FB_JS::enable_if::value || FB_JS::is_same::value, bool>::type - { - return writeHelper(out, prettify); - } -#endif - template - auto toStringHandler(T &out, bool prettify) -> typename FB_JS::enable_if::value, bool>::type + auto toStringHandler(T &out, bool prettify) -> typename MB_ENABLE_IF::value, bool>::type { - return writeHelper(out, prettify); + return writeStream(out, prettify); } -#if defined(FB_JS_INCLUDE_WIFI_CLIENT) - template - auto toStringHandler(T &out, bool prettify) -> typename FB_JS::enable_if::value, bool>::type - { - return writeHelper(out, prettify); - } -#endif +#if defined(MB_JSON_FS_H) -#if defined(FB_JS_INCLUDE_WIFI_CLIENT_SECURE) template - auto toStringHandler(T &out, bool prettify) -> typename FB_JS::enable_if::value, bool>::type + auto toStringHandler(T &out, bool prettify) -> typename MB_ENABLE_IF::value, bool>::type { - return writeHelper(out, prettify); + return writeStream(out, prettify); } -#endif -#if defined(FB_JS_INCLUDE_ARDUINO_MQTT) - template - auto toStringHandler(T &out, bool prettify) -> typename FB_JS::enable_if::value, bool>::type - { - return writeHelper(out, prettify); - } #endif template - bool writeHelper(T &out, bool prettify) + bool writeStream(T &out, bool prettify) { bool ret = false; if (!root) return false; - if (out) + char *p = prettify ? MB_JSON_Print(root) : MB_JSON_PrintUnformatted(root); + if (p) { - char *p = prettify ? MB_JSON_Print(root) : MB_JSON_PrintUnformatted(root); - if (p) - { - ret = out.write((const uint8_t *)p, strlen(p)) == strlen(p); - MB_JSON_free(p); - return ret; - } + ret = out.write((const uint8_t *)p, strlen(p)) == strlen(p); + MB_JSON_free(p); + return ret; } + return ret; } @@ -1359,7 +767,7 @@ class FirebaseJsonBase delay(0); } - void shrinkS(MBSTRING &s) + void shrinkS(MB_String &s) { s.shrink_to_fit(); } @@ -1390,9 +798,12 @@ class FirebaseJsonBase { void *p; size_t newLen = getReservedLen(len); -#if defined(BOARD_HAS_PSRAM) && defined(FIREBASEJSON_USE_PSRAM) - - if ((p = (void *)ps_malloc(newLen)) == 0) +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + if (ESP.getPsramSize() > 0) + p = (void *)ps_malloc(newLen); + else + p = (void *)malloc(newLen); + if (!p) return NULL; #else @@ -1401,7 +812,8 @@ class FirebaseJsonBase ESP.setExternalHeap(); #endif - bool nn = ((p = (void *)malloc(newLen)) > 0); + p = (void *)malloc(newLen); + bool nn = p ? true : false; #if defined(ESP8266_USE_EXTERNAL_HEAP) ESP.resetHeap(); @@ -1536,7 +948,7 @@ class FirebaseJsonBase return -1; } - void substr(MBSTRING &str, const char *s, int offset, size_t len) + void substr(MB_String &str, const char *s, int offset, size_t len) { if (!s) return; @@ -1654,7 +1066,7 @@ class FirebaseJsonBase return nullptr; } - void parseRespHeader(const char *buf, struct FB_JS::server_response_data_t &response) + void parseRespHeader(const char *buf, struct fb_js::server_response_data_t &response) { int beginPos = 0, pmax = 0, payloadPos = 0; @@ -1697,7 +1109,7 @@ class FirebaseJsonBase if (tmp) { response.transferEnc = tmp; - if (strcmp(tmp, (const char *)FLASH_MCR("chunked")) == 0) + if (strcmp(tmp, (const char *)MBSTRING_FLASH_MCR("chunked")) == 0) response.isChunkedEnc = true; delP(&tmp); } @@ -1754,7 +1166,7 @@ class FirebaseJsonBase return idx; } - int readLine(Client *stream, MBSTRING &buf) + int readLine(Client *stream, MB_String &buf) { int res = -1; char c = 0; @@ -1810,7 +1222,7 @@ class FirebaseJsonBase delP(&tmp); } - //last chunk + // last chunk if (chunkedSize < 1) olen = -1; } @@ -1829,7 +1241,7 @@ class FirebaseJsonBase if (readLen > 0) { - //chunk may contain trailing + // chunk may contain trailing if (dataLen + readLen - 2 < chunkedSize) { dataLen += readLen; @@ -1857,7 +1269,7 @@ class FirebaseJsonBase return olen; } - int readChunkedData(Client *stream, MBSTRING &out, int &chunkState, int &chunkedSize, int &dataLen) + int readChunkedData(Client *stream, MB_String &out, int &chunkState, int &chunkedSize, int &dataLen) { char *tmp = nullptr; int p1 = 0; @@ -1868,7 +1280,7 @@ class FirebaseJsonBase chunkState = 1; chunkedSize = -1; dataLen = 0; - MBSTRING s; + MB_String s; int readLen = readLine(stream, s); if (readLen) { @@ -1888,7 +1300,7 @@ class FirebaseJsonBase delP(&tmp); } - //last chunk + // last chunk if (chunkedSize < 1) olen = -1; } @@ -1900,12 +1312,12 @@ class FirebaseJsonBase if (chunkedSize > -1) { - MBSTRING s; + MB_String s; int readLen = readLine(stream, s); if (readLen > 0) { - //chunk may contain trailing + // chunk may contain trailing if (dataLen + readLen - 2 < chunkedSize) { dataLen += readLen; @@ -1931,7 +1343,7 @@ class FirebaseJsonBase return olen; } - int readClient(Client *client, MBSTRING &buf) + int readClient(Client *client, MB_String &buf) { int ret = -1; @@ -1940,7 +1352,7 @@ class FirebaseJsonBase char *header = nullptr; bool isHeader = false; - struct FB_JS::server_response_data_t response; + struct fb_js::server_response_data_t response; int chunkIdx = 0; int pChunkIdx = 0; @@ -1983,7 +1395,7 @@ class FirebaseJsonBase if (chunkIdx == 0) { - //the first chunk can be http response header + // the first chunk can be http response header header = (char *)newP(chunkBufSize); hstate = 1; int readLen = readLine(client, header, chunkBufSize); @@ -1994,7 +1406,7 @@ class FirebaseJsonBase dataTime = millis(); if (tmp) { - //http response header with http response code + // http response header with http response code isHeader = true; hBufPos = readLen; response.httpCode = atoi(tmp); @@ -2006,15 +1418,15 @@ class FirebaseJsonBase { idle(); dataTime = millis(); - //the next chunk data can be the remaining http header + // the next chunk data can be the remaining http header if (isHeader) { - //read one line of next header field until the empty header has found + // read one line of next header field until the empty header has found tmp = (char *)newP(chunkBufSize); int readLen = readLine(client, tmp, chunkBufSize); bool headerEnded = false; - //check is it the end of http header (\n or \r\n)? + // check is it the end of http header (\n or \r\n)? if (readLen == 1) if (tmp[0] == '\r') headerEnded = true; @@ -2026,7 +1438,7 @@ class FirebaseJsonBase if (headerEnded) { buf.clear(); - //parse header string to get the header field + // parse header string to get the header field isHeader = false; parseRespHeader(header, response); @@ -2042,7 +1454,7 @@ class FirebaseJsonBase } else { - //accumulate the remaining header field + // accumulate the remaining header field memcpy(header + hBufPos, tmp, readLen); hBufPos += readLen; } @@ -2050,15 +1462,15 @@ class FirebaseJsonBase } else { - //the next chuunk data is the payload + // the next chuunk data is the payload if (!response.noContent) { pChunkIdx++; pChunk = (char *)newP(chunkBufSize + 1); if (response.isChunkedEnc) delay(10); - //read the avilable data - //chunk transfer encoding? + // read the avilable data + // chunk transfer encoding? if (response.isChunkedEnc) availablePayload = readChunkedData(client, pChunk, chunkedDataState, chunkedDataSize, chunkedDataLen, chunkBufSize); else @@ -2081,7 +1493,7 @@ class FirebaseJsonBase } else { - //read all the rest data + // read all the rest data while (client->available() > 0) client->read(); break; @@ -2112,7 +1524,7 @@ class FirebaseJsonBase return ret; } - void clearSerialData(struct FB_JS::serial_data_t &data) + void clearSerialData(struct fb_js::serial_data_t &data) { data.buf.clear(); data.start = -1; @@ -2123,7 +1535,7 @@ class FirebaseJsonBase data.dataTime = millis(); } - bool readStreamChar(int r, struct FB_JS::serial_data_t &data, MBSTRING &buf, bool isJson) + bool readStreamChar(int r, struct fb_js::serial_data_t &data, MB_String &buf, bool isJson) { bool ret = false; if (r > -1) @@ -2158,7 +1570,7 @@ class FirebaseJsonBase } if (data.scnt > 0) - data.buf += r; + data.buf += (char)r; if (data.scnt == data.ecnt && data.scnt > 0) { @@ -2180,7 +1592,7 @@ class FirebaseJsonBase return ret; } - bool readStream(Stream *s, struct FB_JS::serial_data_t &data, MBSTRING &buf, bool isJson, int timeoutMS) + bool readStream(Stream *s, struct fb_js::serial_data_t &data, MB_String &buf, bool isJson, int timeoutMS) { bool ret = false; @@ -2209,58 +1621,71 @@ class FirebaseJsonBase return ret; } - Stream *toStream(HardwareSerial *ser) +#if defined(ESP32_SD_FAT_INCLUDED) + + bool readSdFatFile(SD_FAT_FILE &file, struct fb_js::serial_data_t &data, MB_String &buf, bool isJson, int timeoutMS) { - return reinterpret_cast(ser); + + bool ret = false; + + if (timeoutMS > -1) + { + if (millis() - data.dataTime > (unsigned long)timeoutMS) + clearSerialData(data); + } + else + clearSerialData(data); + + while (file.available()) + { + idle(); + int r = file.read(); + ret = readStreamChar(r, data, buf, isJson); + if (ret) + { + if (timeoutMS == -1) + clearSerialData(data); + return true; + } + } + + return ret; } -#ifdef FB_JS_INCLUDE_SW_SERIAL - Stream *toStream(SoftwareSerial *ser) + +#endif + + Stream *toStream(MB_SERIAL_CLASS *ser) { return reinterpret_cast(ser); } -#endif #if defined(FBJS_ENABLE_FS) - Stream *toStream(File *file) + Stream *toStream(fs::File *file) { return reinterpret_cast(file); } #endif -#ifdef FB_JS_INCLUDE_WIFI_CLIENT - Client *toClient(WiFiClient *client) - { - return reinterpret_cast(client); - } -#endif - -#ifdef FB_JS_INCLUDE_WIFI_CLIENT_SECURE - Client *toClient(WiFiClientSecure *client) - { - return reinterpret_cast(client); - } -#endif - - void ltrim(MBSTRING &str, const MBSTRING &chars = " ") + void ltrim(MB_String &str, const MB_String &chars = " ") { size_t pos = str.find_first_not_of(chars); - if (pos != MBSTRING::npos) + if (pos != MB_String::npos) str.erase(0, pos); } - void rtrim(MBSTRING &str, const MBSTRING &chars = " ") + void rtrim(MB_String &str, const MB_String &chars = " ") { size_t pos = str.find_last_not_of(chars); - if (pos != MBSTRING::npos) + if (pos != MB_String::npos) str.erase(pos + 1); } - void trim(MBSTRING &str, const MBSTRING &chars = " ") + void trim(MB_String &str, const MB_String &chars = " ") { ltrim(str, chars); rtrim(str, chars); } - bool isArrayKey(int &keyIndex, std::vector &keys) + bool isArrayKey(int &keyIndex, MB_VECTOR &keys) { if (keyIndex < (int)keys.size()) return keys[keyIndex][0] == '[' && keys[keyIndex][keys[keyIndex].length() - 1] == ']'; @@ -2276,7 +1701,7 @@ class FirebaseJsonBase return false; } - int getArrIndex(int &keyIndex, std::vector &keys) + int getArrIndex(int &keyIndex, MB_VECTOR &keys) { int res = -1; if (keyIndex < (int)keys.size()) @@ -2290,7 +1715,7 @@ class FirebaseJsonBase int getArrIndex(const char *key) { - MBSTRING s = key; + MB_String s = key; int res = -1; res = atoi(s.substr(1, s.length() - 2).c_str()); if (res < 0) @@ -2307,7 +1732,6 @@ class FirebaseJsonArray : public FirebaseJsonBase public: typedef struct FirebaseJsonBase::fb_js_iterator_value_t IteratorValue; - typedef struct FirebaseJsonBase::fb_js_search_criteria_t SearchCriteria; FirebaseJsonArray() { @@ -2318,7 +1742,7 @@ class FirebaseJsonArray : public FirebaseJsonBase FirebaseJsonArray(T data) { this->root_type = Root_Type_JSONArray; - setRaw(getStr(data)); + setJsonArrayData(data); } FirebaseJsonArray &operator=(FirebaseJsonArray other); @@ -2327,32 +1751,38 @@ class FirebaseJsonArray : public FirebaseJsonBase /** * Set or deserialize the JSON array data (JSON array literal) as FirebaseJsonArray object. - * + * * @param data The JSON array literal string to set or deserialize. * @return boolean status of the operation. - * - * Call FirebaseJsonArray.errorPosition to get the error. - */ + * + * @note Call FirebaseJsonArray.errorPosition to get the error. + */ template - bool setJsonArrayData(T data) { return setRaw(getStr(data)); } + bool setJsonArrayData(T data) + { + uint32_t addr = 0; + bool ret = setRaw(getStr(data, addr)); + delAddr(addr); + return ret; + } /** * Add null to FirebaseJsonArray object. - * + * * @return instance of an object. - */ + */ FirebaseJsonArray &add() { return nAdd(MB_JSON_CreateNull()); } /** * Add value to FirebaseJsonArray object. - * + * * @param value The value to add. * @return instance of an object. - * - * The value that can be added is the following supported types e.g. flash string (PROGMEM and FPSTR/PSTR), - * String, C/C++ std::string, const char*, char array, string literal, all integer and floating point numbers, + * + * @note The value that can be added is the following supported types e.g. flash string (PROGMEM and FPSTR/PSTR), + * String, C/C++ std::string, const char*, char array, string literal, all integer and floating point numbers, * boolean, FirebaseJson object and array. - */ + */ template FirebaseJsonArray &add(T value) { return dataAddHandler(value); } @@ -2363,11 +1793,11 @@ class FirebaseJsonArray : public FirebaseJsonBase /** * Add multiple values to FirebaseJsonArray object. * e.g. add("a","b",1,2) - * + * * @param v The value of any type to add. * @param n The consecutive values of any type to add. * @return instance of an object. - */ + */ template FirebaseJsonArray &add(First v, Next... n) { @@ -2376,188 +1806,124 @@ class FirebaseJsonArray : public FirebaseJsonBase } /** - * Set JSON array data (Client response) to FirebaseJsonArray object. - * - * @param client The pointer to or instance of Client class. - * @return boolean status of the operation. - * - */ - bool readFrom(Client *client) { return mReadClient(client); } - - bool readFrom(Client &client) { return mReadClient(&client); } - - /** - * Set JSON array data (WiFiClient response) to FirebaseJsonArray object. - * - * @param client The pointer to or instance of WiFiClient object. + * Set JSON array data via derived Stream object to FirebaseJsonArray object. + * + * @param stream The pointer to or instance of derived Stream class. * @return boolean status of the operation. - * - */ -#if defined(FB_JS_INCLUDE_WIFI_CLIENT) - bool readFrom(WiFiClient *client) - { - return mReadClient(toClient(client)); - } + * + */ + bool readFrom(Stream &stream) { return mReadStream(&stream, -1); } - bool readFrom(WiFiClient &client) { return mReadClient(&client); } -#endif + bool readFrom(Stream *stream) { return mReadStream(stream, -1); } /** - * Set JSON array data (WiFiClientSecure response) to FirebaseJsonArray object. - * - * @param client The pointer to or instance of WiFiClientSecure object. + * Set JSON array data via derived Client object to FirebaseJsonArray object. + * + * @param client The pointer to or instance of derived Client class. * @return boolean status of the operation. - */ -#if defined(FB_JS_INCLUDE_WIFI_CLIENT_SECURE) - bool readFrom(WiFiClientSecure *client) - { - return mReadClient(toClient(client)); - } + * + */ + bool readFrom(Client &client) { return mReadClient(&client); } - bool readFrom(WiFiClientSecure &client) { return mReadClient(&client); } -#endif + bool readFrom(Client *client) { return mReadClient(client); } /** - * Set JSON array data (Seral object) to FirebaseJsonArray object. - * + * Set JSON array data via Serial to FirebaseJsonArray object. + * * @param ser The HW or SW Serial object. * @param timeoutMS The timeout in millisecond to wait for Serial data to be completed. * @return boolean status of the operation. - */ - bool readFrom(HardwareSerial &ser, uint32_t timeoutMS = 5000) { return mReadStream(toStream(&ser), (int)timeoutMS); } -#ifdef FB_JS_INCLUDE_SW_SERIAL - bool readFrom(SoftwareSerial &ser, uint32_t timeoutMS = 5000) - { - return mReadStream(toStream(&ser), (int)timeoutMS); - } -#endif + */ + bool readFrom(MB_SERIAL_CLASS &ser, uint32_t timeoutMS = 5000) { return mReadStream(toStream(&ser), (int)timeoutMS); } -#if defined(FBJS_ENABLE_FS) +#if defined(ESP32_SD_FAT_INCLUDED) /** - * Set JSON array data (File object) to FirebaseJsonArray object. - * - * @param file The File object. + * Set JSON array data via SdFat's SdFile object to FirebaseJsonArray object. + * + * @param sdFatFile The SdFat file object. * @return boolean status of the operation. - */ - bool readFrom(FILE_SYSTEM &file) { return mReadStream(toStream(&file), -1); } + */ + bool readFrom(SD_FAT_FILE &sdFatFile) { return mReadSdFat(sdFatFile, -1); } #endif /** * Get the array value at the specified index or path from the FirebaseJsonArray object. - * + * * @param result The reference of FirebaseJsonData object that holds data at the specified index. * @param index_or_path Index of data or relative path to data in FirebaseJsonArray object. * @param prettify The text indentation and new line serialization option. * @return boolean status of the operation. - * - * The relative path must begin with array index (number placed inside square brackets) followed by + * + * @note The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2 - */ + */ template bool get(FirebaseJsonData &result, T index_or_path, bool prettify = false) { return dataGetHandler(index_or_path, result, prettify); } - /** - * Search element by key or path in FirebaseJsonArray object. - * - * @param result The reference of FirebaseJsonData that holds the result. - * @param criteria The FirebaseJson::SearchCriteria data. - * @param prettify The text indentation and new line serialization option. - * @return number of elements found from search. - * - * The SearchCriteria data has the properties e.g. - * path - The key of path to search. - * Path can be wildcard with * in search path and * should use as key in part and do not mix with any character. - * value - The value string to search. - * depth - The begin depth (int) of element to search, default is 0. - * endDepth - The end depth (int) of element to search, default is -1. - * searchAll - The boolean option to search all occurrences of elements. - * - */ - size_t search(SearchCriteria &criteria) { return mSearch(root, &criteria); } - - size_t search(FirebaseJsonData &result, SearchCriteria &criteria, bool prettify = false) { return mSearch(root, &result, &criteria, prettify); } - - /** - * Search element by key or path in FirebaseJsonArray object. - * - * @param path The key or path to search. - * @param searchAll Search all occurrences. - * @return number of elements found from search. - * - */ - template - size_t search(T path, bool searchAll = false) { return mSearch(root, getStr(path), searchAll); } - - /** - * Get the full path to any element in FirebaseJson object. - * - * @param path The key or path to search in to. - * @param searchAll Search all occurrences. - * @return full path string in case of found. - * - */ - template - String getPath(T path, bool searchAll = false) { return mGetElementFullPath(root, getStr(path), searchAll); } - /** * Check whether key or path to the child element existed in FirebaseJsonArray or not. - * + * * @param path The key or path of child element check. * @return boolean status indicated the existence of element. - * - */ + */ template - bool isMember(T path) { return mGet(root, NULL, getStr(path)); } + bool isMember(T path) + { + uint32_t addr = 0; + bool ret = mGet(root, NULL, getStr(path, addr)); + delAddr(addr); + return ret; + } /** * Parse and collect all node/array elements in FirebaseJsonArray object. * @return number of child/array elements in FirebaseJson object. - */ + */ size_t iteratorBegin(const char *data = NULL) { return mIteratorBegin(root); } /** * Get child/array elements from FirebaseJsonArray objects at specified index. - * + * * @param index The element index to get. * @param type The integer which holds the type of data i.e. JSON_OBJECT and JSON_ARR * @param key The string which holds the key/key of an object, can return empty String if the data type is an array. * @param value The string which holds the value for the element key or array. * @return depth of element. - */ + */ int iteratorGet(size_t index, int &type, String &key, String &value) { return mIteratorGet(index, type, key, value); } /** * Get child/array elements from FirebaseJsonArray objects at specified index. - * + * * @param index The element index to get. * @return IteratorValue struct. - * + * * This should call after iteratorBegin. - * + * * The IteratorValue struct contains the following members. * int type * String key * String value - */ + */ IteratorValue valueAt(size_t index) { return mValueAt(index); } /** * Clear all iterator buffer (should be called since iteratorBegin was called). - */ + */ void iteratorEnd() { mIteratorEnd(); } /** * Get the length of the array in FirebaseJsonArray object. * @return length of the array. - */ + */ size_t size() { return MB_JSON_GetArraySize(root); } /** * Get the FirebaseJsonArray object serialized string. - * + * * @param out The object e.g. Serial, String, std::string, char array, Stream, File, Client, that accepts the returning string. * @param prettify The text indentation and new line serialization option. - */ + */ template bool toString(T &out, bool prettify = false) { return toStringHandler(out, prettify); } @@ -2567,53 +1933,55 @@ class FirebaseJsonArray : public FirebaseJsonBase /** * Get raw JSON Array * @return raw JSON Array string - */ + */ const char *raw() { return mRaw(); } /** * Get the size of serialized JSON array buffer * @param prettify The text indentation and new line serialization option. - * @return size in byte of buffer - */ + * @return size in byte of buffer + */ size_t serializedBufferLength(bool prettify = false) { return mGetSerializedBufferLength(prettify); } /** * Clear all array in FirebaseJsonArray object. - * + * * @return instance of an object. - */ + */ FirebaseJsonArray &clear(); /** * Set null to FirebaseJsonArray object at specified index or path. - * + * * @param index_or_path The array index or path that null to be set. - */ + */ template void set(T index_or_path) { dataSetHandler(index_or_path, nullptr); } /** - * Set String to FirebaseJsonArray object at the specified index. - * + * Set value to FirebaseJsonArray object at the specified index. + * * @param index_or_path The array index or path that value to be set. - * @param value The String to set. - */ + * @param value The value to set. + */ template void set(T1 index_or_path, T2 value) { dataSetHandler(index_or_path, value); } + template void set(T index_or_path, FirebaseJson &value) { return dataSetHandler(index_or_path, value); } + template void set(T index_or_path, FirebaseJsonArray &value) { return dataSetHandler(index_or_path, value); } /** * Remove the array value at the specified index or path from the FirebaseJsonArray object. - * + * * @param index_or_path The array index or relative path to array to be removed. * @return bool value represents the successful operation. - * - * The relative path must begin with array index (number placed inside square brackets) followed by + * + * @note The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would remove the data of myData key inside the array indexes 2. - */ + */ template bool remove(T1 index_or_path) { return dataRemoveHandler(index_or_path); } @@ -2621,23 +1989,23 @@ class FirebaseJsonArray : public FirebaseJsonBase * Get the error position at the JSON object literal from parsing. * @return the position of error in JSON object literal * Return -1 when for no parsing error. - */ + */ int errorPosition() { return errorPos; } /** * Set the precision for float to JSON Array object - */ + */ void setFloatDigits(uint8_t digits) { mSetFloatDigits(digits); } /** * Set the precision for double to JSON Array object - */ + */ void setDoubleDigits(uint8_t digits) { mSetDoubleDigits(digits); } /** * Get http response code of reading JSON data from WiFi/Ethernet Client. * @return the response code of reading JSON data from WiFi/Ethernet Client - */ + */ int responseCode() { return mResponseCode(); } private: @@ -2647,163 +2015,203 @@ class FirebaseJsonArray : public FirebaseJsonBase bool mRemoveIdx(int index); template - auto dataGetHandler(T arg, FirebaseJsonData &result, bool prettify) -> typename FB_JS::enable_if::value, bool>::type + auto dataGetHandler(T arg, FirebaseJsonData &result, bool prettify) -> typename MB_ENABLE_IF::value, bool>::type { - return mGet(root, &result, getStr(arg), prettify); + uint32_t addr = 0; + bool ret = mGet(root, &result, getStr(arg, addr), prettify); + delAddr(addr); + return ret; } template - auto dataGetHandler(T arg, FirebaseJsonData &result, bool prettify) -> typename FB_JS::enable_if::value, bool>::type + auto dataGetHandler(T arg, FirebaseJsonData &result, bool prettify) -> typename MB_ENABLE_IF::value, bool>::type { return mGetIdx(&result, arg, prettify); } template - auto dataRemoveHandler(T arg) -> typename FB_JS::enable_if::value, bool>::type + auto dataRemoveHandler(T arg) -> typename MB_ENABLE_IF::value, bool>::type { - return mRemove(getStr(arg)); + uint32_t addr = 0; + bool ret = mRemove(getStr(arg, addr)); + delAddr(addr); + return ret; } template - auto dataRemoveHandler(T arg) -> typename FB_JS::enable_if::value, bool>::type + auto dataRemoveHandler(T arg) -> typename MB_ENABLE_IF::value, bool>::type { return mRemoveIdx(arg); } template - auto dataAddHandler(T arg) -> typename FB_JS::enable_if::value, FirebaseJsonArray &>::type + auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type { nAdd(MB_JSON_CreateBool(arg)); return *this; } template - auto dataAddHandler(T arg) -> typename FB_JS::enable_if::value, FirebaseJsonArray &>::type + auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type { - nAdd(MB_JSON_CreateRaw(NUM2S(arg).get())); + nAdd(MB_JSON_CreateRaw(num2Str(arg, -1))); return *this; } template - auto dataAddHandler(T arg) -> typename FB_JS::enable_if::value, FirebaseJsonArray &>::type + auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type { - nAdd(MB_JSON_CreateRaw(NUM2S(arg, floatDigits).get())); + nAdd(MB_JSON_CreateRaw(num2Str(arg, floatDigits))); return *this; } template - auto dataAddHandler(T arg) -> typename FB_JS::enable_if::value, FirebaseJsonArray &>::type + auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type { - nAdd(MB_JSON_CreateRaw(NUM2S(arg, doubleDigits).get())); + nAdd(MB_JSON_CreateRaw(num2Str(arg, doubleDigits))); return *this; } template - auto dataAddHandler(T arg) -> typename FB_JS::enable_if::value, FirebaseJsonArray &>::type + auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type { - nAdd(MB_JSON_CreateString(getStr(arg))); + uint32_t addr = 0; + nAdd(MB_JSON_CreateString(getStr(arg, addr))); + delAddr(addr); return *this; } +#if !defined(__AVR__) template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { - mSet(getStr(arg1), MB_JSON_CreateNull()); + uint32_t addr = 0; + mSet(getStr(arg1, addr), MB_JSON_CreateNull()); + delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { mSetIdx(arg1, MB_JSON_CreateNull); } +#endif template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_bool::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_bool::value>::type { - mSet(getStr(arg1), MB_JSON_CreateBool(arg2)); + uint32_t addr = 0; + mSet(getStr(arg1, addr), MB_JSON_CreateBool(arg2)); + delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_bool::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_bool::value>::type { mSetIdx(arg1, MB_JSON_CreateBool(arg2)); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_num_int::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_num_int::value>::type { - mSet(getStr(arg1), MB_JSON_CreateRaw(NUM2S(arg2).get())); + uint32_t addr = 0; + mSet(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, -1))); + delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_num_int::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_num_int::value>::type { - mSetIdx(arg1, MB_JSON_CreateRaw(NUM2S(arg2).get())); + mSetIdx(arg1, MB_JSON_CreateRaw(num2Str(arg2, -1))); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { - mSet(getStr(arg1), MB_JSON_CreateRaw(NUM2S(arg2, floatDigits).get())); + uint32_t addr = 0; + mSet(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, floatDigits))); + delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { - mSetIdx(arg1, MB_JSON_CreateRaw(NUM2S(arg2, floatDigits).get())); + mSetIdx(arg1, MB_JSON_CreateRaw(num2Str(arg2, floatDigits))); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { - mSet(getStr(arg1), MB_JSON_CreateRaw(NUM2S(arg2, doubleDigits).get())); + uint32_t addr = 0; + mSet(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, doubleDigits))); + delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { - mSetIdx(arg1, MB_JSON_CreateRaw(NUM2S(arg2, doubleDigits).get())); + mSetIdx(arg1, MB_JSON_CreateRaw(num2Str(arg2, doubleDigits))); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_string::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_string::value>::type { - mSet(getStr(arg1), MB_JSON_CreateString(getStr(arg2))); + uint32_t addr1 = 0; + uint32_t addr2 = 0; + mSet(getStr(arg1, addr1), MB_JSON_CreateString(getStr(arg2, addr2))); + delAddr(addr1); + delAddr(addr2); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename FB_JS::enable_if::value && FB_JS::is_string::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_string::value>::type { - mSetIdx(arg1, MB_JSON_CreateString(getStr(arg2))); + uint32_t addr = 0; + mSetIdx(arg1, MB_JSON_CreateString(getStr(arg2, addr))); + delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 &arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { MB_JSON *e = MB_JSON_Duplicate(arg2.root, true); - mSet(getStr(arg1), e); + uint32_t addr = 0; + mSet(getStr(arg1, addr), e); + delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 &arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { MB_JSON *e = MB_JSON_Duplicate(arg2.root, true); mSetIdx(arg1, e); } template - auto dataSetHandler(T1 arg1, T2 &arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { MB_JSON *e = MB_JSON_Duplicate(arg2.root, true); - mSet(getStr(arg1), e); + uint32_t addr = 0; + mSet(getStr(arg1, addr), e); + delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 &arg2) -> typename FB_JS::enable_if::value && FB_JS::is_same::value>::type + auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { MB_JSON *e = MB_JSON_Duplicate(arg2.root, true); mSetIdx(arg1, e); } + + void delAddr(uint32_t addr) + { + if (addr > 0) + { + char *s = addrTo(addr); + delP(&s); + s = NULL; + } + } }; class FirebaseJson : public FirebaseJsonBase @@ -2814,7 +2222,6 @@ class FirebaseJson : public FirebaseJsonBase public: typedef enum FirebaseJsonBase::fb_js_json_data_type jsonDataType; typedef struct FirebaseJsonBase::fb_js_iterator_value_t IteratorValue; - typedef struct FirebaseJsonBase::fb_js_search_criteria_t SearchCriteria; FirebaseJson() { this->root_type = Root_Type_JSON; } @@ -2822,7 +2229,7 @@ class FirebaseJson : public FirebaseJsonBase FirebaseJson(T data) { this->root_type = Root_Type_JSON; - setRaw(getStr(data)); + setJsonData(data); } FirebaseJson &operator=(FirebaseJson other); @@ -2833,138 +2240,117 @@ class FirebaseJson : public FirebaseJsonBase /** * Clear internal buffer of FirebaseJson object. - * + * * @return instance of an object. - */ + */ FirebaseJson &clear(); /** * Set or deserialize the JSON array data (JSON object literal) as FirebaseJson object. - * + * * @param data The JSON object literal string to set or deserialize. * @return boolean status of the operation. - * - * Call FirebaseJson.errorPosition to get the error. - */ + * + * @note Call FirebaseJson.errorPosition to get the error. + */ template - bool setJsonData(T data) { return setRaw(getStr(data)); } - - /** - * Set JSON data (Client response) to FirebaseJson object. - * - * @param client The pointer to or instance of Client object. - * @return boolean status of the operation. - */ - bool readFrom(Client *client) { return mReadClient(client); } - - bool readFrom(Client &client) { return mReadClient(&client); } - - /** - * Set JSON data (WiFiClient response) to FirebaseJson object. - * - * @param client The pointer to or instance of WiFiClient object. - * @return boolean status of the operation. - */ -#if defined(FB_JS_INCLUDE_WIFI_CLIENT) - bool readFrom(WiFiClient *client) + bool setJsonData(T data) { - return mReadClient(toClient(client)); + uint32_t addr = 0; + bool ret = setRaw(getStr(data, addr)); + delAddr(addr); + return ret; } - bool readFrom(WiFiClient &client) { return mReadClient(&client); } -#endif - /** - * Set JSON data (WiFiClientSecure response) to FirebaseJson object. - * - * @param client The pointer to or instance of WiFiClientSecure object. + * Set JSON data via derived Stream object to FirebaseJson object. + * + * @param stream The pointer to or instance of derived Stream object. * @return boolean status of the operation. - */ -#if defined(FB_JS_INCLUDE_WIFI_CLIENT_SECURE) - bool readFrom(WiFiClientSecure *client) - { - return mReadClient(toClient(client)); - } + */ + bool readFrom(Stream &stream) { return mReadStream(&stream, -1); } - bool readFrom(WiFiClientSecure &client) { return mReadClient(&client); } -#endif + /** + * Set JSON data via derived Client object to FirebaseJson object. + * + * @param client The pointer to or instance of derived Client object. + * @return boolean status of the operation. + */ + bool readFrom(Client &client) { return mReadClient(&client); } /** - * Set JSON array data (Seral object) to FirebaseJson object. - * + * Set JSON array data via Serial to FirebaseJson object. + * * @param ser The HW or SW Serial object. * @param timeoutMS The timeout in millisecond to wait for Serial data to be completed. * @return boolean status of the operation. - */ - bool readFrom(HardwareSerial &ser, uint32_t timeoutMS = 5000) { return mReadStream(toStream(&ser), (int)timeoutMS); } -#ifdef FB_JS_INCLUDE_SW_SERIAL - bool readFrom(SoftwareSerial &ser, uint32_t timeoutMS = 5000) - { - return mReadStream(toStream(&ser), (int)timeoutMS); - } -#endif + */ + bool readFrom(MB_SERIAL_CLASS &ser, uint32_t timeoutMS = 5000) { return mReadStream(toStream(&ser), (int)timeoutMS); } -#if defined(FBJS_ENABLE_FS) +#if defined(ESP32_SD_FAT_INCLUDED) /** - * Set JSON array data (File object) to FirebaseJson object. - * - * @param file The File object. + * Set JSON data via SdFat's SdFile object to FirebaseJson object. + * + * @param sdFatFile The SdFat's SdFile object. * @return boolean status of the operation. - */ - bool readFrom(FILE_SYSTEM &file) { return mReadStream(toStream(&file), -1); } + */ + bool readFrom(SD_FAT_FILE &sdFatFile) { return mReadSdFat(sdFatFile, -1); } #endif /** * Add null to FirebaseJson object. - * + * * @param key The new key string that null to be added. * @return instance of an object. - */ + */ template - FirebaseJson &add(T key) { return nAdd(getStr(key), NULL); } + FirebaseJson &add(T key) + { + uint32_t addr = 0; + nAdd(getStr(key, addr), NULL); + delAddr(addr); + return *this; + } /** * Add value to FirebaseJson object. - * + * * @param key The new key string that string value to be added. * @param value The value for the new specified key. - * * @return instance of an object. - */ + */ template FirebaseJson &add(T1 key, T2 value) { return dataHandler(key, value, fb_json_func_type_add); } + template FirebaseJson &add(T key, FirebaseJson &value) { return dataHandler(key, value, fb_json_func_type_add); } + template FirebaseJson &add(T key, FirebaseJsonArray &value) { return dataHandler(key, value, fb_json_func_type_add); } /** * Get the FirebaseJson object serialized string. - * + * * @param out The writable object e.g. String, std::string, char array, Stream e.g ile, WiFi/Ethernet Client and LWMQTT, that accepts the returning string. - * @param topic The MQTT topic (LWMQTT). * @param prettify The text indentation and new line serialization option. - */ - template - bool toString(T &out, bool prettify = false) { return toStringHandler(out, prettify); } + */ - template - auto toString(T1 &out, T2 topic) -> typename FB_JS::enable_if::value, bool>::type { return toStringHandler(out, getStr(topic)); } + bool toString(Stream &out, bool prettify = false) { return toStringHandler(out, prettify); } template bool toString(T *ptr, bool prettify = false) { return toStringPtrHandler(ptr, prettify); } - template - bool toString(T1 *out, T2 topic) { return toStringHandler(out, getStr(topic)); } + template + bool toString(T &out, bool prettify = false) { return toStringHandler(out, prettify); } /** * Get the value from the specified node path in FirebaseJson object. - * + * * @param result The reference of FirebaseJsonData that holds the result. * @param path Relative path to the specific node in FirebaseJson object. * @param prettify The text indentation and new line serialization option. * @return boolean status of the operation. - * + * * The FirebaseJsonData object holds the returned data which can be read from the following properties. * result.stringValue - contains the returned string. * result.intValue - contains the returned signed 32-bit integer value. @@ -2974,7 +2360,7 @@ class FirebaseJson : public FirebaseJsonBase * result.success - used to determine the result of the get operation. * result.type - used to determine the type of returned value in string represent * the types of value e.g. string, int, double, boolean, array, object, null and undefined. - * + * * result.typeNum used to determine the type of returned value is an integer as represented by the following value. * FirebaseJson::UNDEFINED = 0 * FirebaseJson::OBJECT = 1 @@ -2985,251 +2371,259 @@ class FirebaseJson : public FirebaseJsonBase * FirebaseJson::DOUBLE = 6 * FirebaseJson::BOOL = 7 and * FirebaseJson::NULL = 8 - */ - template - bool get(FirebaseJsonData &result, T path, bool prettify = false) { return mGet(root, &result, getStr(path), prettify); } - - /** - * Search element by key or path in FirebaseJsonArray object. - * - * @param result The reference of FirebaseJsonData that holds the result. - * @param criteria The FirebaseJson::SearchCriteria data. - * @param prettify The text indentation and new line serialization option. - * @return number of elements found from search. - * - * The SearchCriteria data has the properties e.g. - * path - The key of path to search. - * Path can be wildcard with * in search path and * should use as key in part and do not mix with any character. - * value - The value string to search. - * depth - The begin depth (int) of element to search, default is 0. - * endDepth - The end depth (int) of element to search, default is -1. - * searchAll - The boolean option to search all occurrences of elements. - * - */ - size_t search(SearchCriteria &criteria) { return mSearch(root, &criteria); } - - size_t search(FirebaseJsonData &result, SearchCriteria &criteria, bool prettify = false) { return mSearch(root, &result, &criteria, prettify); } - - /** - * Search element by key or path in FirebaseJson object. - * - * @param path The key or path to search. - * @param searchAll Search all occurrences. - * @return number of elements found from search. - * - */ - template - size_t search(T path, bool searchAll = false) { return mSearch(root, getStr(path), searchAll); } - - /** - * Get the full path to any element in FirebaseJson object. - * - * @param path The key or path to search in to. - * @param searchAll Search all occurrences. - * @return full path string in case of found. - * - */ + */ template - String getPath(T path, bool searchAll = false) { return mGetElementFullPath(root, getStr(path), searchAll); } + bool get(FirebaseJsonData &result, T path, bool prettify = false) + { + uint32_t addr = 0; + bool ret = mGet(root, &result, getStr(path, addr), prettify); + delAddr(addr); + return ret; + } /** * Check whether key or path to the child element existed in FirebaseJson object or not. - * + * * @param path The key or path of child element check. * @return boolean status indicated the existence of element. - * - */ + */ template - bool isMember(T path) { return mGet(root, NULL, getStr(path)); } + bool isMember(T path) + { + uint32_t addr = 0; + bool ret = mGet(root, NULL, getStr(path, addr)); + delAddr(addr); + return ret; + } /** * Parse and collect all node/array elements in FirebaseJson object. - * + * * @return number of child/array elements in FirebaseJson object. - */ + */ size_t iteratorBegin() { return mIteratorBegin(root); } /** * Get child/array elements from FirebaseJson objects at specified index. - * + * * @param index The element index to get. * @param type The integer which holds the type of data i.e. JSON_OBJECT and JSON_ARR * @param key The string which holds the key/key of an object, can return empty String if the data type is an array. * @param value The string which holds the value for the element key or array. * @return depth of element. - */ + */ int iteratorGet(size_t index, int &type, String &key, String &value) { return mIteratorGet(index, type, key, value); } /** * Get child/array elements from FirebaseJson objects at specified index. - * + * * @param index The element index to get. * @return IteratorValue struct. - * + * * This should call after iteratorBegin. - * + * * The IteratorValue struct contains the following members. * int type * String key * String value - */ + */ IteratorValue valueAt(size_t index) { return mValueAt(index); } /** * Clear all iterator buffer (should be called since iteratorBegin was called). - */ + */ void iteratorEnd() { mIteratorEnd(); } /** * Set null to FirebaseJson object at the specified node path. - * + * * @param path The relative path that null to be set. - * The relative path can be mixed with array index (number placed inside square brackets) and node names + * + * @note The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. - */ + */ template - void set(T key) { mSet(getStr(key), NULL); } + void set(T key) + { + uint32_t addr = 0; + mSet(getStr(key, addr), NULL); + delAddr(addr); + } /** * Set value to FirebaseJson object at the specified node path. - * + * * @param path The relative path that string value to be set. * @param value The value to set. - * - * The relative path can be mixed with array index (number placed inside square brackets) and node names + * + * @note The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. - * - * The value that can be added is the following supported types e.g. flash string (PROGMEM and FPSTR/PSTR), + * + * The value that can be added is the following supported types e.g. flash string (PROGMEM and FPSTR/PSTR), * String, C/C++ std::string, const char*, char array, string literal, all integer and floating point numbers, * boolean, FirebaseJson object and array. - */ + */ template void set(T1 key, T2 value) { dataHandler(key, value, fb_json_func_type_set); } + template FirebaseJson &set(T key, FirebaseJson &value) { return dataHandler(key, value, fb_json_func_type_set); } + template FirebaseJson &set(T key, FirebaseJsonArray &value) { return dataHandler(key, value, fb_json_func_type_set); } /** * Remove the specified node and its content. - * + * * @param path The relative path to remove its contents/children. * @return bool value represents the success operation. - */ + */ template - bool remove(T path) { return mRemove(getStr(path)); } + bool remove(T path) + { + uint32_t addr = 0; + bool ret = mRemove(getStr(path, addr)); + delAddr(addr); + return ret; + } /** * Get raw JSON * @return raw JSON string - */ + */ const char *raw() { return mRaw(); } /** * Get the error position at the JSON object literal from parsing. * @return the position of error in JSON object literal * Return -1 when for no parsing error - */ + */ int errorPosition() { return errorPos; } /** * Get the size of serialized JSON object buffer * @param prettify The text indentation and new line serialization option. - * @return size in byte of buffer - */ + * @return size in byte of buffer + */ size_t serializedBufferLength(bool prettify = false) { return mGetSerializedBufferLength(prettify); } /** * Set the precision for float to JSON object * @param digits The number of decimal places. - */ + */ void setFloatDigits(uint8_t digits) { mSetFloatDigits(digits); } /** * Set the precision for double to JSON object - */ + */ void setDoubleDigits(uint8_t digits) { mSetDoubleDigits(digits); } /** * Get http response code of reading JSON data from WiFi/Ethernet Client. * @return the response code of reading JSON data from WiFi/Ethernet Client - */ + */ int responseCode() { return mResponseCode(); } private: FirebaseJson &nAdd(const char *key, MB_JSON *value); template - auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename FB_JS::enable_if::value && FB_JS::is_bool::value, FirebaseJson &>::type + auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && is_bool::value, FirebaseJson &>::type { + uint32_t addr = 0; if (type == fb_json_func_type_add) - nAdd(getStr(arg1), MB_JSON_CreateBool(arg2)); + nAdd(getStr(arg1, addr), MB_JSON_CreateBool(arg2)); else if (type == fb_json_func_type_set) - mSet(getStr(arg1), MB_JSON_CreateBool(arg2)); + mSet(getStr(arg1, addr), MB_JSON_CreateBool(arg2)); + delAddr(addr); return *this; } template - auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename FB_JS::enable_if::value && FB_JS::is_num_int::value, FirebaseJson &>::type + auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && is_num_int::value, FirebaseJson &>::type { + uint32_t addr = 0; if (type == fb_json_func_type_add) - nAdd(getStr(arg1), MB_JSON_CreateRaw(NUM2S(arg2).get())); + nAdd(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, -1))); else if (type == fb_json_func_type_set) - mSet(getStr(arg1), MB_JSON_CreateRaw(NUM2S(arg2).get())); + mSet(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, -1))); + delAddr(addr); return *this; } template - auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename FB_JS::enable_if::value && FB_JS::is_same::value, FirebaseJson &>::type + auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value, FirebaseJson &>::type { + uint32_t addr = 0; if (type == fb_json_func_type_add) - nAdd(getStr(arg1), MB_JSON_CreateRaw(NUM2S(arg2, floatDigits).get())); + nAdd(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, floatDigits))); else if (type == fb_json_func_type_set) - mSet(getStr(arg1), MB_JSON_CreateRaw(NUM2S(arg2, floatDigits).get())); + mSet(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, floatDigits))); + delAddr(addr); return *this; } template - auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename FB_JS::enable_if::value && FB_JS::is_same::value, FirebaseJson &>::type + auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value, FirebaseJson &>::type { + uint32_t addr = 0; if (type == fb_json_func_type_add) - nAdd(getStr(arg1), MB_JSON_CreateRaw(NUM2S(arg2, doubleDigits).get())); + nAdd(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, doubleDigits))); else if (type == fb_json_func_type_set) - mSet(getStr(arg1), MB_JSON_CreateRaw(NUM2S(arg2, doubleDigits).get())); + mSet(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, doubleDigits))); + delAddr(addr); return *this; } template - auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename FB_JS::enable_if::value && FB_JS::is_string::value, FirebaseJson &>::type + auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && is_string::value, FirebaseJson &>::type { + uint32_t addr1 = 0; + uint32_t addr2 = 0; if (type == fb_json_func_type_add) - nAdd(getStr(arg1), MB_JSON_CreateString(getStr(arg2))); + nAdd(getStr(arg1, addr1), MB_JSON_CreateString(getStr(arg2, addr2))); else if (type == fb_json_func_type_set) - mSet(getStr(arg1), MB_JSON_CreateString(getStr(arg2))); + mSet(getStr(arg1, addr1), MB_JSON_CreateString(getStr(arg2, addr2))); + delAddr(addr1); + delAddr(addr2); return *this; } template - auto dataHandler(T arg, FirebaseJson &json, fb_json_func_type_t type) -> typename FB_JS::enable_if::value, FirebaseJson &>::type + auto dataHandler(T arg, FirebaseJson &json, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value, FirebaseJson &>::type { MB_JSON *e = MB_JSON_Duplicate(json.root, true); + uint32_t addr = 0; if (type == fb_json_func_type_add) - nAdd(getStr(arg), e); + nAdd(getStr(arg, addr), e); else if (type == fb_json_func_type_set) - mSet(getStr(arg), e); + mSet(getStr(arg, addr), e); + delAddr(addr); return *this; } template - auto dataHandler(T arg, FirebaseJsonArray &arr, fb_json_func_type_t type) -> typename FB_JS::enable_if::value, FirebaseJson &>::type + auto dataHandler(T arg, FirebaseJsonArray &arr, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value, FirebaseJson &>::type { MB_JSON *e = MB_JSON_Duplicate(arr.root, true); + uint32_t addr = 0; if (type == fb_json_func_type_add) - nAdd(getStr(arg), e); + nAdd(getStr(arg, addr), e); else if (type == fb_json_func_type_set) - mSet(getStr(arg), e); + mSet(getStr(arg, addr), e); + delAddr(addr); return *this; } + + void delAddr(uint32_t addr) + { + if (addr > 0) + { + char *s = addrTo(addr); + delP(&s); + s = NULL; + } + } }; #endif \ No newline at end of file diff --git a/src/lib/ESPSigner/json/MB_JSON/MB_JSON.c b/src/lib/ESPSigner/json/MB_JSON/MB_JSON.c index 3a334a0..3baa1ce 100644 --- a/src/lib/ESPSigner/json/MB_JSON/MB_JSON.c +++ b/src/lib/ESPSigner/json/MB_JSON/MB_JSON.c @@ -3,9 +3,9 @@ All original static cJSON functions and static variables will be prefixed with MB_JSON_. - Created December 20, 2021 + Created December 20, 2022 - Copyright (c) 2021 Mobizt (K. Suwatchai) + Copyright (c) 2022 Mobizt (K. Suwatchai) Copyright (c) 2009-2017 Dave Gamble and cJSON contributors diff --git a/src/lib/ESPSigner/json/MB_JSON/MB_JSON.h b/src/lib/ESPSigner/json/MB_JSON/MB_JSON.h index 637db89..0b49abb 100644 --- a/src/lib/ESPSigner/json/MB_JSON/MB_JSON.h +++ b/src/lib/ESPSigner/json/MB_JSON/MB_JSON.h @@ -3,9 +3,9 @@ All original static cJSON functions and static variables will be prefixed with MB_JSON_. - Created December 20, 2021 + Created December 20, 2022 - Copyright (c) 2021 Mobizt (K. Suwatchai) + Copyright (c) 2022 Mobizt (K. Suwatchai) Copyright (c) 2009-2017 Dave Gamble and cJSON contributors diff --git a/src/lib/ESPSigner/json/MB_List.h b/src/lib/ESPSigner/json/MB_List.h new file mode 100644 index 0000000..69163b7 --- /dev/null +++ b/src/lib/ESPSigner/json/MB_List.h @@ -0,0 +1,224 @@ +/* + * Just a simple dynamic array implementation, MB_List v1.0.3 + * + * Created February 4, 2022 + * + * The MIT License (MIT) + * Copyright (c) 2022 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MB_LIST_H +#define MB_LIST_H + +#if !defined(__AVR__) +#define MB_VECTOR std::vector +#define MB_USE_STD_VECTOR +#else +#define MB_VECTOR MB_List +#endif + +#if defined(__AVR__) +#define MB_LIST_NULL NULL +#else +#define MB_LIST_NULL nullptr +#endif + +template +class MB_List +{ +public: + MB_List() + { + clear(); + } + + ~MB_List() + { + clear(); + } + + void swap(MB_List &el) + { + MB_List _el; + _el.e = this->e; + _el.eSize = this->eSize; + clear(); + this->e = el.e; + this->eSize = el.eSize; + el.clear(); + el.e = _el.e; + el.eSize = _el.eSize; + } + + void push_back(eType &e) + { + add(&e, eSize, 1); + } + + void insert(int position, eType &e) + { + add(&e, position, 1); + } + + void insert(int position, int size, eType &e) + { + add(&e, position, size); + } + + void pop_back() + { + remove(eSize - 1, 1); + } + + void erase(int beginIndex, int endIndex) + { + + if (beginIndex > endIndex || beginIndex < 0) + return; + + remove(beginIndex, endIndex - beginIndex + 1); + } + + void erase(int beginIndex) + { + remove(beginIndex, 1); + } + + int begin() + { + return 0; + } + + int end() + { + if (eSize > 0) + return eSize - 1; + return 0; + } + + void clear() + { + if (e) + delete[] e; + e = MB_LIST_NULL; + eSize = 0; + } + + size_t size() + { + return eSize; + } + + eType &operator[](int index) + { + if (index < eSize && index >= 0) + return e[index]; + return e[0]; + } + +private: + eType *e = NULL; + int eSize = 0; + + void add(eType *e, int index, int size) + { + + if (index > eSize) + return; + + if (eSize == 0) + { + this->e = new eType[1]; + if (this->e) + { + eSize = 1; + this->e[0] = *e; + } + } + else + { + eType *tmp = new eType[eSize]; + + if (tmp) + { + + for (int i = 0; i < eSize; i++) + tmp[i] = this->e[i]; + + delete[] this->e; + + this->e = new eType[eSize + size]; + if (this->e) + { + for (int i = 0; i < index; i++) + this->e[i] = tmp[i]; + + for (int i = index; i < index + size; i++) + this->e[i] = *e; + + for (int i = index; i < eSize; i++) + this->e[i + size] = tmp[i]; + + eSize += size; + } + + delete[] tmp; + } + } + } + + void remove(int index, int size) + { + + if (eSize == 0 || index < 0) + return; + + if (index + size > eSize) + size = eSize - index; + + eType *tmp = new eType[eSize]; + + if (tmp) + { + + for (int i = 0; i < eSize; i++) + tmp[i] = this->e[i]; + + delete[] this->e; + + this->e = new eType[eSize - size]; + if (this->e) + { + for (int i = 0; i < index; i++) + this->e[i] = tmp[i]; + + for (int i = index; i < eSize - size; i++) + this->e[i] = tmp[i + size]; + + eSize -= size; + } + + delete[] tmp; + } + } +}; + +#endif \ No newline at end of file diff --git a/src/lib/ESPSigner/json/MB_String.h b/src/lib/ESPSigner/json/MB_String.h index 8e12000..f462d46 100644 --- a/src/lib/ESPSigner/json/MB_String.h +++ b/src/lib/ESPSigner/json/MB_String.h @@ -1,60 +1,77 @@ /** - * Mobizt's SRAM/PSRAM supported String, version 1.1.2 - * - * - * November 29, 2021 - * + * Mobizt's SRAM/PSRAM supported String, version 1.2.4 + * + * Created February 28, 2022 + * * Changes Log - * + * + * v1.2.4 + * - Check PSRAM availability before allocating the memory + * + * v1.2.3 + * - Fixed flash string F and PSTR handle + * + * v1.2.2 + * - Add supports more MCUs. + * + * v1.2.1 + * - Add flash string manipulation functions. + * + * v1.2.0 + * - Add supports bool, integer and float manipulation. + * * v1.1.2 * - Fix substring with zero length returns the original string issue. - * + * * v1.1.1 * - Fix possible ESP8266 code exit without resetting the external heap stack - * + * * v1.1.0 * - Add support ESP8266 external virtual RAM (SRAM or PSRAM) - * + * * v1.0.1 * - Add trim function * - Add version enum - * + * * v1.0.0 * - Initial release - * + * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * + * Copyright (c) 2022 K. Suwatchai (Mobizt) + * + * * Permission is hereby granted, free of charge, to any person returning a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ + */ #ifndef MB_String_H #define MB_String_H #include +#if !defined(__AVR__) #include #include +#include +#endif #define MB_STRING_MAJOR 1 -#define MB_STRING_MINOR 1 -#define MB_STRING_PATCH 2 +#define MB_STRING_MINOR 2 +#define MB_STRING_PATCH 4 #if defined(ESP8266) && defined(MMU_EXTERNAL_HEAP) && defined(MB_STRING_USE_PSRAM) #include @@ -62,16 +79,400 @@ #define ESP8266_USE_EXTERNAL_HEAP #endif +#if defined(ESP8266) || defined(ESP32) +#define MBSTRING_FLASH_MCR FPSTR +#elif defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) +#define MBSTRING_FLASH_MCR PSTR +#else +#define MBSTRING_FLASH_MCR(s) (s) +#endif + +class MB_String; + +#define pgm2Str(p) (MB_String().appendP(p).c_str()) +#define num2Str(v, p) (MB_String().appendNum(v, p).c_str()) + +#if defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F4) +#define MB_IS_SAME std::is_same +#define MB_ENABLE_IF std::enable_if +#else +#define MB_IS_SAME is_same +#define MB_ENABLE_IF enable_if +#endif + +namespace mb_string +{ + enum mb_string_sub_type + { + mb_string_sub_type_none, + mb_string_sub_type_bool, + mb_string_sub_type_float, + mb_string_sub_type_double, + mb_string_sub_type_int8, + mb_string_sub_type_uint8, + mb_string_sub_type_int16, + mb_string_sub_type_uint16, + mb_string_sub_type_int32, + mb_string_sub_type_uint32, + mb_string_sub_type_int64, + mb_string_sub_type_uint64, + mb_string_sub_type_cstring, + mb_string_sub_type_chars, + mb_string_sub_type_mb_string, + mb_string_sub_type_arduino_string, + mb_string_sub_type_std_string, + mb_string_sub_type_fptr + }; + + typedef struct mb_string_ptr_t + { + + public: + mb_string_ptr_t(uint32_t addr = 0, mb_string_sub_type type = mb_string_sub_type_cstring, int precision = -1) + { + _addr = addr; + _type = type; + _precision = precision; + } + int precision() { return _precision; } + mb_string_sub_type type() { return _type; } + uint32_t address() { return _addr; } + + private: + mb_string_sub_type _type = mb_string_sub_type_none; + int _precision = -1; + uint32_t _addr = 0; + + } MB_StringPtr; + + template + struct enable_if + { + }; + template + struct enable_if + { + typedef T type; + }; + template + struct is_same + { + static bool const value = false; + }; + template + struct is_same + { + static bool const value = true; + }; + + template + struct is_num_int8 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_uint8 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_int16 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_uint16 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_int32 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value || + MB_IS_SAME::value || MB_IS_SAME::value || + MB_IS_SAME::value; + }; + + template + struct is_num_uint32 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value || + MB_IS_SAME::value; + }; + + template + struct is_num_int64 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_uint64 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_neg_int + { + static bool const value = is_num_int8::value || is_num_int16::value || + is_num_int32::value || is_num_int64::value; + }; + + template + struct is_num_pos_int + { + static bool const value = is_num_uint8::value || is_num_uint16::value || + is_num_uint32::value || is_num_uint64::value; + }; + + template + struct is_num_int + { + static bool const value = is_num_pos_int::value || is_num_neg_int::value; + }; + + template + struct is_num_float + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_bool + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct cs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct ccs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct as_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct cas_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct ss_t + { +#if !defined(__AVR__) + static bool const value = MB_IS_SAME::value; +#else + static bool const value = false; +#endif + }; + + template + struct css_t + { +#if !defined(__AVR__) + static bool const value = MB_IS_SAME::value; +#else + static bool const value = false; +#endif + }; + + template + struct ssh_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct fs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct mbs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct cmbs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct pgm_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct is_const_chars + { + static bool const value = cs_t::value || ccs_t::value; + }; + + template + struct is_arduino_string + { + static bool const value = as_t::value || cas_t::value; + }; + + template + struct is_std_string + { + static bool const value = ss_t::value || css_t::value; + }; + + template + struct is_mb_string + { + static bool const value = mbs_t::value || cmbs_t::value; + }; + + template + struct is_arduino_string_sum_helper + { + static bool const value = ssh_t::value; + }; + + template + struct is_arduino_flash_string_helper + { + static bool const value = fs_t::value; + }; + + template + struct is_string + { + static bool const value = is_const_chars::value || is_arduino_string::value || + is_arduino_string_sum_helper::value || is_arduino_flash_string_helper::value || + is_std_string::value || is_mb_string::value; + }; + + template + uint32_t toAddr(T &v) { return reinterpret_cast(&v); } + +#if defined(__AVR__) + template + T addrTo(int address) + { + return reinterpret_cast(address); + } +#else + template + auto addrTo(int address) -> typename MB_ENABLE_IF::value, T>::type + { + return reinterpret_cast(address); + } +#endif + + template + auto getSubType(T val) -> typename MB_ENABLE_IF::value || is_num_float::value || MB_IS_SAME::value || is_const_chars::value || is_arduino_flash_string_helper::value || is_arduino_string::value || is_std_string::value || is_mb_string::value || MB_IS_SAME::value, mb_string_sub_type>::type + { + if (is_num_uint64::value) + return mb_string_sub_type_uint64; + else if (is_num_int64::value) + return mb_string_sub_type_int64; + else if (is_num_uint32::value) + return mb_string_sub_type_uint32; + else if (is_num_int32::value) + return mb_string_sub_type_int32; + else if (is_num_uint16::value) + return mb_string_sub_type_uint16; + else if (is_num_int16::value) + return mb_string_sub_type_int16; + else if (is_num_uint8::value) + return mb_string_sub_type_uint8; + else if (is_num_int8::value) + return mb_string_sub_type_int8; + else if (MB_IS_SAME::value) + return mb_string_sub_type_bool; + else if (MB_IS_SAME::value) + return mb_string_sub_type_float; + else if (MB_IS_SAME::value) + return mb_string_sub_type_double; + else if (is_arduino_string::value) + return mb_string_sub_type_arduino_string; + else if (is_std_string::value || MB_IS_SAME::value) + return mb_string_sub_type_std_string; + else if (is_mb_string::value) + return mb_string_sub_type_mb_string; + else if (is_arduino_flash_string_helper::value) + return mb_string_sub_type_fptr; + else if (ccs_t::value) + return mb_string_sub_type_cstring; + else if (cs_t::value) + return mb_string_sub_type_chars; + + return mb_string_sub_type_int8; + } + + template + auto getSubType(T *val) -> typename MB_ENABLE_IF::value || is_num_float::value || MB_IS_SAME::value || is_const_chars::value || is_arduino_flash_string_helper::value || is_arduino_string::value || is_std_string::value || is_mb_string::value || MB_IS_SAME::value, mb_string_sub_type>::type + { + return getSubType(*val); + } + + template + auto toStringPtr(const T &val) -> typename MB_ENABLE_IF::value || is_arduino_string::value || is_mb_string::value || MB_IS_SAME::value, MB_StringPtr>::type + { + return MB_StringPtr(reinterpret_cast(&val), getSubType(val)); + } + + template + auto toStringPtr(T val) -> typename MB_ENABLE_IF::value, MB_StringPtr>::type { return MB_StringPtr(reinterpret_cast(val), getSubType(val)); } + + template + auto toStringPtr(T &val) -> typename MB_ENABLE_IF::value, MB_StringPtr>::type { return MB_StringPtr(reinterpret_cast(val), getSubType(val)); } + +#if !defined(__AVR__) + template + auto toStringPtr(T val) -> typename MB_ENABLE_IF::value, MB_StringPtr>::type + { + return MB_StringPtr(); + } +#endif + + template + auto toStringPtr(T val) -> typename MB_ENABLE_IF::value, MB_StringPtr>::type + { + return val; + } + + template + auto toStringPtr(T &val, int precision = -1) -> typename MB_ENABLE_IF::value || is_num_float::value || MB_IS_SAME::value, MB_StringPtr>::type { return MB_StringPtr(reinterpret_cast(&val), getSubType(val), precision); } +} + +using namespace mb_string; + class MB_String { public: MB_String() { #if defined(ESP8266_USE_EXTERNAL_HEAP) - //reserve default 1 byte external heap to refer to its pointer later + // reserve default 1 byte external heap to refer to its pointer later reset(1); #endif }; + ~MB_String() { allocate(0, false); @@ -79,17 +480,99 @@ class MB_String MB_String(const char *cstr) { - clear(); if (cstr) - copy(cstr, strlen(cstr)); + copy(cstr, strlen_P(cstr)); } MB_String(const MB_String &value) { - clear(); *this = value; } + MB_String(const __FlashStringHelper *str) + { + *this = str; + } + + MB_String(MB_StringPtr value) + { + *this = value; + } + + MB_String(bool value) + { + appendNum(value); + } + + MB_String(unsigned char value, unsigned char base = 10) + { + int len = 1 + 8 * sizeof(unsigned char); + reserve(len); + + if (bufLen > 0) + utoa(value, buf, base); + } + + MB_String(int value, unsigned char base = 10) + { + int len = 2 + 8 * sizeof(int); + reserve(len); + + if (bufLen > 0) + { + if (base == 10) + sprintf(buf, (const char *)MBSTRING_FLASH_MCR("%d"), value); + else + itoa(value, buf, base); + } + } + + MB_String(unsigned int value, unsigned char base = 10) + { + int len = 1 + 8 * sizeof(unsigned int); + reserve(len); + + if (bufLen > 0) + utoa(value, buf, base); + } + + MB_String(long value, unsigned char base = 10) + { + int len = 2 + 8 * sizeof(long); + reserve(len); + + if (bufLen > 0) + { + if (base == 10) + sprintf(buf, (const char *)MBSTRING_FLASH_MCR("%ld"), value); + else + ltoa(value, buf, base); + } + } + + MB_String(unsigned long value, unsigned char base = 10) + { + int len = 1 + 8 * sizeof(unsigned long); + reserve(len); + + if (bufLen > 0) + ultoa(value, buf, base); + } + + MB_String(float value, unsigned char decimalPlaces = 2) + { + reserve(33); + if (bufLen > 0) + dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); + } + + MB_String(double value, unsigned char decimalPlaces = 3) + { + reserve(33); + if (bufLen > 0) + dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); + } +#if !defined(__AVR__) MB_String &operator=(const std::string &rhs) { if (rhs.length() > 0) @@ -99,7 +582,7 @@ class MB_String return *this; } - +#endif MB_String &operator=(const String &rhs) { @@ -111,29 +594,48 @@ class MB_String return *this; } + MB_String &operator=(const __FlashStringHelper *str) + { + if (str) + appendF(str, true); + + return *this; + } + + MB_String &operator+=(const __FlashStringHelper *str) + { + if (str) + appendF(str); + + return *this; + } + unsigned char operator==(const MB_String &rhs) const { return equals(rhs); } + unsigned char operator==(const char *cstr) const { return equals(cstr); } + unsigned char operator!=(const MB_String &rhs) const { return !equals(rhs); } + unsigned char operator!=(const char *cstr) const { return !equals(cstr); } - +#if !defined(__AVR__) MB_String &operator+=(const std::string &rhs) { concat(rhs.c_str()); return (*this); } - +#endif MB_String &operator+=(const String &rhs) { concat(rhs.c_str()); @@ -161,12 +663,12 @@ class MB_String MB_String &operator+=(const char *cstr) { - size_t len = strlen(cstr); + size_t len = strlen_P(cstr); size_t slen = length(); if (_reserve(slen + len, false)) { - strcat(buf, cstr); + strcat_P(buf, (PGM_P)cstr); *(buf + slen + len) = '\0'; } @@ -179,10 +681,184 @@ class MB_String return (*this); } + MB_String &operator+=(bool value) + { + appendNum(value); + return (*this); + } + + MB_String &operator=(MB_StringPtr ptr) + { + setPtr(ptr); + return (*this); + } + + MB_String &operator+=(MB_StringPtr ptr) + { + appendPtr(ptr); + return (*this); + } + + template + auto operator=(T value) -> typename MB_ENABLE_IF::value || is_num_float::value || is_bool::value, MB_String &>::type + { + clear(); + appendNum(value); + return (*this); + } + + template + auto operator+=(T value) -> typename MB_ENABLE_IF::value || is_num_float::value || is_bool::value, MB_String &>::type + { + appendNum(value); + return (*this); + } + + MB_String &appendP(PGM_P pgms, bool clear = false) + { + if (clear) + this->clear(); + + char *t = pgmStr(pgms); + if (t) + { + *this += t; + delP(&t); + } + + return (*this); + } + + MB_String &appendF(const __FlashStringHelper *pstr, bool clear = false) + { + if (clear) + this->clear(); + + int len = strlen_P((PGM_P)pstr); + if (len > 0) + { + unsigned int newlen = length() + len; + reserve(newlen); + + if (bufLen > 0) + memcpy_P(buf + length(), (PGM_P)pstr, len + 1); + } + + return (*this); + } + + MB_String &setPtr(MB_StringPtr src) + { + clear(); + appendPtr(src); + return (*this); + }; + + MB_String &appendPtr(MB_StringPtr src) + { + if (src.type() == mb_string_sub_type_fptr) + appendF(addrTo(src.address())); + else if (src.type() == mb_string_sub_type_cstring || src.type() == mb_string_sub_type_chars) + *this += addrTo(src.address()); + else if (src.type() == mb_string_sub_type_arduino_string) + *this += *addrTo(src.address()); +#if !defined(__AVR__) + else if (src.type() == mb_string_sub_type_std_string) + *this += *addrTo(src.address()); +#endif + else if (src.type() == mb_string_sub_type_mb_string) + *this += *addrTo(src.address()); + else if (src.type() == mb_string_sub_type_uint64) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_int64) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_uint32) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_int32) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_uint16) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_int16) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_uint8) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_int8) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_bool) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_float) + appendNum(*addrTo(src.address()), src.precision()); + else if (src.type() == mb_string_sub_type_double) + appendNum(*addrTo(src.address()), src.precision()); + + return (*this); + }; + + template + auto appendNum(T value, int precision = 0) -> typename MB_ENABLE_IF::value || is_bool::value, MB_String &>::type + { + char *s = NULL; + + if (is_bool::value) + s = boolStr(value); + else if (is_num_neg_int::value) + { +#if defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) + s = int32Str(value); +#else + s = int64Str(value); +#endif + } + else if (is_num_pos_int::value) + { +#if defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) + s = uint32Str(value); +#else + s = uint64Str(value); +#endif + } + + if (s) + { + *this += s; + delP(&s); + } + + return (*this); + } + + MB_String &appendNum(float value, int precision = 5) + { + if (precision < 0) + precision = 5; + + char *s = floatStr(value, precision); + if (s) + { + *this += s; + delP(&s); + } + return (*this); + } + + MB_String &appendNum(double value, int precision = 9) + { + if (precision < 0) + precision = 9; + + char *s = doubleStr(value, precision); + if (s) + { + *this += s; + delP(&s); + } + return (*this); + } + MB_String &operator=(const char *cstr) { if (cstr) - copy(cstr, strlen(cstr)); + copy(cstr, strlen_P(cstr)); else clear(); @@ -344,7 +1020,7 @@ class MB_String return bufLen; } - size_t find(const MB_String &s, size_t index) const + size_t find(const MB_String &s, size_t index = 0) const { if (!s.buf) return -1; @@ -694,6 +1370,269 @@ class MB_String static const size_t npos = -1; private: + /*** dtostrf function is taken from + * https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/avr/dtostrf.c + */ + + /*** + * dtostrf - Emulation for dtostrf function from avr-libc + * Copyright (c) 2013 Arduino. All rights reserved. + * Written by Cristian Maglie + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * This library 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 + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + char *dtostrf(double val, signed char width, unsigned char prec, char *sout) + { + // Commented code is the original version + /*** + char fmt[20]; + sprintf(fmt, "%%%d.%df", width, prec); + sprintf(sout, fmt, val); + return sout; + */ + + // Handle negative numbers + uint8_t negative = 0; + if (val < 0.0) + { + negative = 1; + val = -val; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (int i = 0; i < prec; ++i) + { + rounding /= 10.0; + } + + val += rounding; + + // Extract the integer part of the number + unsigned long int_part = (unsigned long)val; + double remainder = val - (double)int_part; + + if (prec > 0) + { + // Extract digits from the remainder + unsigned long dec_part = 0; + double decade = 1.0; + for (int i = 0; i < prec; i++) + { + decade *= 10.0; + } + remainder *= decade; + dec_part = (int)remainder; + + if (negative) + { + sprintf(sout, (const char *)MBSTRING_FLASH_MCR("-%ld.%0*ld"), int_part, prec, dec_part); + } + else + { + sprintf(sout, (const char *)MBSTRING_FLASH_MCR("%ld.%0*ld"), int_part, prec, dec_part); + } + } + else + { + if (negative) + { + sprintf(sout, (const char *)MBSTRING_FLASH_MCR("-%ld"), int_part); + } + else + { + sprintf(sout, (const char *)MBSTRING_FLASH_MCR("%ld"), int_part); + } + } + // Handle minimum field width of the output string + // width is signed value, negative for left adjustment. + // Range -128,127 + + char *fmt = (char *)newP(129); + unsigned int w = width; + if (width < 0) + { + negative = 1; + w = -width; + } + else + { + negative = 0; + } + + if (strlen(sout) < w) + { + memset(fmt, ' ', 128); + fmt[w - strlen(sout)] = '\0'; + if (negative == 0) + { + char *tmp = (char *)newP(strlen(sout) + 1); + strcpy(tmp, sout); + strcpy(sout, fmt); + strcat(sout, tmp); + delP(&tmp); + } + else + { + // left adjustment + strcat(sout, fmt); + } + } + + delP(&fmt); + + return sout; + } + + char *intStr(int value) + { + char *t = (char *)newP(36); + sprintf(t, (const char *)MBSTRING_FLASH_MCR("%d"), value); + return t; + } + +#if defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) + + char *int32Str(signed long value) + { + char *t = (char *)newP(64); + sprintf(t, (const char *)MBSTRING_FLASH_MCR("%ld"), value); + return t; + } + + char *uint32Str(unsigned long value) + { + char *t = (char *)newP(64); + sprintf(t, (const char *)MBSTRING_FLASH_MCR("%lu"), value); + return t; + } + +#endif + + char *int64Str(signed long long value) + { + char *t = (char *)newP(64); + sprintf(t, (const char *)MBSTRING_FLASH_MCR("%lld"), value); + return t; + } + + char *uint64Str(unsigned long long value) + { + char *t = (char *)newP(64); + sprintf(t, (const char *)MBSTRING_FLASH_MCR("%llu"), value); + return t; + } + + char *boolStr(bool value) + { + char *t = (char *)newP(8); + value ? strcpy(t, (const char *)MBSTRING_FLASH_MCR("true")) : strcpy(t, (const char *)MBSTRING_FLASH_MCR("false")); + return t; + } + + char *floatStr(float value, int precision) + { + char *t = (char *)newP(32); + dtostrf(value, (precision + 2), precision, t); + trim(t); + return t; + } + + char *doubleStr(double value, int precision) + { + char *t = (char *)newP(64); + dtostrf(value, (precision + 2), precision, t); + trim(t); + return t; + } + + char *nullStr() + { + char *t = (char *)newP(6); + strcpy(t, (const char *)MBSTRING_FLASH_MCR("null")); + return t; + } + + char *pgmStr(PGM_P p) + { + char *t = (char *)newP(strlen_P(p)); + strcpy_P(t, p); + return t; + } + + void trim(char *s) + { + if (!s) + return; + size_t i = strlen(s) - 1; + while (s[i] == '0' && i > 0) + { + if (s[i - 1] == '.') + { + i--; + break; + } + if (s[i - 1] != '0') + break; + i--; + } + if (i < strlen(s) - 1) + s[i] = '\0'; + } + + void *newP(size_t len) + { + void *p; + size_t newLen = getReservedLen(len); +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + if (ESP.getPsramSize() > 0) + p = (void *)ps_malloc(newLen); + else + p = (void *)malloc(newLen); + if (!p) + return NULL; + +#else + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.setExternalHeap(); +#endif + + p = (void *)malloc(newLen); + bool nn = p ? true : false; + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.resetHeap(); +#endif + + if (!nn) + return NULL; + +#endif + memset(p, 0, newLen); + return p; + } + + void delP(void *ptr) + { + void **p = (void **)ptr; + if (*p) + { + free(*p); + *p = 0; + } + } + size_t getReservedLen(size_t len) { int blen = len + 1; @@ -762,6 +1701,27 @@ class MB_String concat(cstr, strlen(cstr)); } + void move(MB_String &rhs) + { + if (buf) + { + if (bufLen >= rhs.bufLen) + { + strcpy(buf, rhs.buf); + bufLen = rhs.bufLen; + rhs.bufLen = 0; + return; + } + else + { + free(buf); + } + } + buf = rhs.buf; + bufLen = rhs.bufLen; + rhs.buf = NULL; + } + void allocate(size_t len, bool shrink) { @@ -786,7 +1746,10 @@ class MB_String int slen = length(); #if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) - buf = (char *)ps_realloc(buf, len); + if (ESP.getPsramSize() > 0) + buf = (char *)ps_realloc(buf, len); + else + buf = (char *)realloc(buf, len); #else buf = (char *)realloc(buf, len); #endif @@ -798,13 +1761,15 @@ class MB_String } else { - bool nn = false; #if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) - nn = ((buf = (char *)ps_malloc(len)) > 0); + if (ESP.getPsramSize() > 0) + buf = (char *)ps_malloc(len); + else + buf = (char *)malloc(len); #else - nn = ((buf = (char *)malloc(len)) > 0); + buf = (char *)malloc(len); #endif - if (nn) + if (buf) { buf[0] = '\0'; bufLen = len; @@ -827,7 +1792,7 @@ class MB_String return *this; } - memmove(buf, cstr, length); + memcpy_P(buf, (PGM_P)cstr, length); buf[length] = '\0'; return *this; @@ -986,6 +1951,104 @@ class MB_String return strcmp(buf, cstr) == 0; } + char *ultoa(unsigned long value, char *str, int radix) + { + const char *format = NULL; + + switch (radix) + { + case 8: + format = "%o"; + break; + case 10: + format = "%ul"; + break; + case 16: + format = "%x"; + break; + } + + if (format == NULL) + return str; + + int size = sprintf(str, format, value); + return &str[size]; + } + +#if (!defined(ESP32) && !defined(ESP8266) && !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_SAMD)) || defined(ARDUINO_NANO_RP2040_CONNECT) + char *ltoa(long value, char *str, int radix) + { + const char *format = NULL; + + switch (radix) + { + case 8: + format = "%o"; + break; + case 10: + format = "%l"; + break; + case 16: + format = "%x"; + break; + } + + if (format == NULL) + return str; + + int size = sprintf(str, format, value); + return &str[size]; + } + + char *utoa(unsigned int value, char *str, int radix) + { + const char *format = NULL; + + switch (radix) + { + case 8: + format = "%o"; + break; + case 10: + format = "%u"; + break; + case 16: + format = "%x"; + break; + } + + if (format == NULL) + return str; + + int size = sprintf(str, format, value); + return &str[size]; + } + + char *itoa(int value, char *str, int radix) + { + const char *format = NULL; + + switch (radix) + { + case 8: + format = "%o"; + break; + case 10: + format = "%d"; + break; + case 16: + format = "%x"; + break; + } + + if (format == NULL) + return str; + + int size = sprintf(str, format, value); + return &str[size]; + } +#endif + char *buf = NULL; size_t bufLen = 0; }; @@ -999,6 +2062,8 @@ inline MB_String operator+(const MB_String &lhs, const MB_String &rhs) return res; } +#if !defined(__AVR__) + inline MB_String operator+(MB_String &&lhs, const MB_String &rhs) { lhs += rhs; @@ -1025,8 +2090,9 @@ inline MB_String operator+(char lhs, MB_String &rhs) inline MB_String operator+(MB_String &&lhs, char rhs) { - Serial.println(rhs); return std::move(lhs.insert(0, rhs)); } +#endif + #endif \ No newline at end of file diff --git a/src/lib/ESPSigner/json/extras/print/fb_json_print.c b/src/lib/ESPSigner/json/extras/print/fb_json_print.c new file mode 100644 index 0000000..fd4d385 --- /dev/null +++ b/src/lib/ESPSigner/json/extras/print/fb_json_print.c @@ -0,0 +1,1049 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. These routines are thread +// safe and reentrant! +// Use this instead of the bloated standard/newlib printf cause these use +// malloc for printf (and may not be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef FB_JSON_PRINT_C +#define FB_JSON_PRINT_C + +#include +#include + +#include "fb_json_print.h" + +// define this globally (e.g. gcc -DFB_JSON_PRINT_INCLUDE_CONFIG_H ...) to include the +// printf_config.h header file +// default: undefined +#ifdef FB_JSON_PRINT_INCLUDE_CONFIG_H +#include "printf_config.h" +#endif + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef FB_JSON_PRINT_NTOA_BUFFER_SIZE +#define FB_JSON_PRINT_NTOA_BUFFER_SIZE 32U +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef FB_JSON_PRINT_FTOA_BUFFER_SIZE +#define FB_JSON_PRINT_FTOA_BUFFER_SIZE 32U +#endif + +// support for the floating point type (%f) +// default: activated +#ifndef FB_JSON_PRINT_DISABLE_SUPPORT_FLOAT +#define FB_JSON_PRINT_SUPPORT_FLOAT +#endif + +// support for exponential floating point notation (%e/%g) +// default: activated +#ifndef FB_JSON_PRINT_DISABLE_SUPPORT_EXPONENTIAL +#define FB_JSON_PRINT_SUPPORT_EXPONENTIAL +#endif + +// define the default floating point precision +// default: 6 digits +#ifndef FB_JSON_PRINT_DEFAULT_FLOAT_PRECISION +#define FB_JSON_PRINT_DEFAULT_FLOAT_PRECISION 6U +#endif + +// define the largest float suitable to print with %f +// default: 1e9 +#ifndef FB_JSON_PRINT_MAX_FLOAT +#define FB_JSON_PRINT_MAX_FLOAT 1e9 +#endif + +// support for the long long types (%llu or %p) +// default: activated +#ifndef FB_JSON_PRINT_DISABLE_SUPPORT_LONG_LONG +#define FB_JSON_PRINT_SUPPORT_LONG_LONG +#endif + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#ifndef FB_JSON_PRINT_DISABLE_SUPPORT_PTRDIFF_T +#define FB_JSON_PRINT_SUPPORT_PTRDIFF_T +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FB_JSON_PRINT_FLAGS_ZEROPAD (1U << 0U) +#define FB_JSON_PRINT_FLAGS_LEFT (1U << 1U) +#define FB_JSON_PRINT_FLAGS_PLUS (1U << 2U) +#define FB_JSON_PRINT_FLAGS_SPACE (1U << 3U) +#define FB_JSON_PRINT_FLAGS_HASH (1U << 4U) +#define FB_JSON_PRINT_FLAGS_UPPERCASE (1U << 5U) +#define FB_JSON_PRINT_FLAGS_CHAR (1U << 6U) +#define FB_JSON_PRINT_FLAGS_SHORT (1U << 7U) +#define FB_JSON_PRINT_FLAGS_LONG (1U << 8U) +#define FB_JSON_PRINT_FLAGS_LONG_LONG (1U << 9U) +#define FB_JSON_PRINT_FLAGS_PRECISION (1U << 10U) +#define FB_JSON_PRINT_FLAGS_ADAPT_EXP (1U << 11U) + +// import float.h for DBL_MAX +#if defined(FB_JSON_PRINT_SUPPORT_FLOAT) +#include +#endif + +// output function type +typedef void (*fb_json_out_fn_type)(char character, void *buffer, size_t idx, size_t maxlen); + +// wrapper (used as buffer) for output function type +typedef struct +{ + void (*fct)(char character, void *arg); + void *arg; +} fb_json_out_fn_wrap_type; + +// internal buffer output +static inline void fb_json_out_buffer(char character, void *buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) + { + ((char *)buffer)[idx] = character; + } +} + +// internal null output +static inline void fb_json_out_null(char character, void *buffer, size_t idx, size_t maxlen) +{ + (void)character; + (void)buffer; + (void)idx; + (void)maxlen; +} + +// internal _putchar wrapper +static inline void fb_json_out_char(char character, void *buffer, size_t idx, size_t maxlen) +{ + (void)buffer; + (void)idx; + (void)maxlen; + if (character) + { + fb_json_putchar(character); + } +} + +// internal output function wrapper +static inline void fb_json_out_fn(char character, void *buffer, size_t idx, size_t maxlen) +{ + (void)idx; + (void)maxlen; + if (character) + { + // buffer is the output fct pointer + ((fb_json_out_fn_wrap_type *)buffer)->fct(character, ((fb_json_out_fn_wrap_type *)buffer)->arg); + } +} + +// internal secure strlen +// \return The length of the string (excluding the terminating 0) limited by 'maxsize' +static inline unsigned int fb_json_strlen(const char *str, size_t maxsize) +{ + const char *s; + for (s = str; *s && maxsize--; ++s) + ; + return (unsigned int)(s - str); +} + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool fb_json_is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +// internal ASCII string to unsigned int conversion +static unsigned int fb_json_atoi(const char **str) +{ + unsigned int i = 0U; + while (fb_json_is_digit(**str)) + { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + +// output the specified string in reverse, taking care of any zero-padding +static size_t fb_json_out_rev(fb_json_out_fn_type out, char *buffer, size_t idx, size_t maxlen, const char *buf, size_t len, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FB_JSON_PRINT_FLAGS_LEFT) && !(flags & FB_JSON_PRINT_FLAGS_ZEROPAD)) + { + for (size_t i = len; i < width; i++) + { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) + { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FB_JSON_PRINT_FLAGS_LEFT) + { + while (idx - start_idx < width) + { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + +// internal itoa format +static size_t fb_json_itoa_format(fb_json_out_fn_type out, char *buffer, size_t idx, size_t maxlen, char *buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + // pad leading zeros + if (!(flags & FB_JSON_PRINT_FLAGS_LEFT)) + { + if (width && (flags & FB_JSON_PRINT_FLAGS_ZEROPAD) && (negative || (flags & (FB_JSON_PRINT_FLAGS_PLUS | FB_JSON_PRINT_FLAGS_SPACE)))) + { + width--; + } + while ((len < prec) && (len < FB_JSON_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = '0'; + } + while ((flags & FB_JSON_PRINT_FLAGS_ZEROPAD) && (len < width) && (len < FB_JSON_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & FB_JSON_PRINT_FLAGS_HASH) + { + if (!(flags & FB_JSON_PRINT_FLAGS_PRECISION) && len && ((len == prec) || (len == width))) + { + len--; + if (len && (base == 16U)) + { + len--; + } + } + if ((base == 16U) && !(flags & FB_JSON_PRINT_FLAGS_UPPERCASE) && (len < FB_JSON_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = 'x'; + } + else if ((base == 16U) && (flags & FB_JSON_PRINT_FLAGS_UPPERCASE) && (len < FB_JSON_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = 'X'; + } + else if ((base == 2U) && (len < FB_JSON_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = 'b'; + } + if (len < FB_JSON_PRINT_NTOA_BUFFER_SIZE) + { + buf[len++] = '0'; + } + } + + if (len < FB_JSON_PRINT_NTOA_BUFFER_SIZE) + { + if (negative) + { + buf[len++] = '-'; + } + else if (flags & FB_JSON_PRINT_FLAGS_PLUS) + { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FB_JSON_PRINT_FLAGS_SPACE) + { + buf[len++] = ' '; + } + } + + return fb_json_out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + +// internal itoa for 'long' type +static size_t fb_json_itoa_long(fb_json_out_fn_type out, char *buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[FB_JSON_PRINT_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) + { + flags &= ~FB_JSON_PRINT_FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FB_JSON_PRINT_FLAGS_PRECISION) || value) + { + do + { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FB_JSON_PRINT_FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < FB_JSON_PRINT_NTOA_BUFFER_SIZE)); + } + + return fb_json_itoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + +// internal itoa for 'long long' type +#if defined(FB_JSON_PRINT_SUPPORT_LONG_LONG) +static size_t fb_json_itoa_long_long(fb_json_out_fn_type out, char *buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[FB_JSON_PRINT_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) + { + flags &= ~FB_JSON_PRINT_FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FB_JSON_PRINT_FLAGS_PRECISION) || value) + { + do + { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FB_JSON_PRINT_FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < FB_JSON_PRINT_NTOA_BUFFER_SIZE)); + } + + return fb_json_itoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // FB_JSON_PRINT_SUPPORT_LONG_LONG + +#if defined(FB_JSON_PRINT_SUPPORT_FLOAT) + +#if defined(FB_JSON_PRINT_SUPPORT_EXPONENTIAL) +// forward declaration so that fb_json_ftoa can switch to exp notation for values > FB_JSON_PRINT_MAX_FLOAT +static size_t fb_json_ftoa_exp(fb_json_out_fn_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); +#endif + +// internal ftoa for fixed decimal floating point +static size_t fb_json_ftoa(fb_json_out_fn_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[FB_JSON_PRINT_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; + + // test for special values + if (value != value) + return fb_json_out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return fb_json_out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return fb_json_out_rev(out, buffer, idx, maxlen, (flags & FB_JSON_PRINT_FLAGS_PLUS) ? "fni+" : "fni", (flags & FB_JSON_PRINT_FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad + if ((value > FB_JSON_PRINT_MAX_FLOAT) || (value < -FB_JSON_PRINT_MAX_FLOAT)) + { +#if defined(FB_JSON_PRINT_SUPPORT_EXPONENTIAL) + return fb_json_ftoa_exp(out, buffer, idx, maxlen, value, prec, width, flags); +#else + return 0U; +#endif + } + + // test for negative + bool negative = false; + if (value < 0) + { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & FB_JSON_PRINT_FLAGS_PRECISION)) + { + prec = FB_JSON_PRINT_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < FB_JSON_PRINT_FTOA_BUFFER_SIZE) && (prec > 9U)) + { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) + { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) + { + frac = 0; + ++whole; + } + } + else if (diff < 0.5) + { + } + else if ((frac == 0U) || (frac & 1U)) + { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) + { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) + { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else + { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < FB_JSON_PRINT_FTOA_BUFFER_SIZE) + { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) + { + break; + } + } + // add extra 0s + while ((len < FB_JSON_PRINT_FTOA_BUFFER_SIZE) && (count-- > 0U)) + { + buf[len++] = '0'; + } + if (len < FB_JSON_PRINT_FTOA_BUFFER_SIZE) + { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < FB_JSON_PRINT_FTOA_BUFFER_SIZE) + { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) + { + break; + } + } + + // pad leading zeros + if (!(flags & FB_JSON_PRINT_FLAGS_LEFT) && (flags & FB_JSON_PRINT_FLAGS_ZEROPAD)) + { + if (width && (negative || (flags & (FB_JSON_PRINT_FLAGS_PLUS | FB_JSON_PRINT_FLAGS_SPACE)))) + { + width--; + } + while ((len < width) && (len < FB_JSON_PRINT_FTOA_BUFFER_SIZE)) + { + buf[len++] = '0'; + } + } + + if (len < FB_JSON_PRINT_FTOA_BUFFER_SIZE) + { + if (negative) + { + buf[len++] = '-'; + } + else if (flags & FB_JSON_PRINT_FLAGS_PLUS) + { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FB_JSON_PRINT_FLAGS_SPACE) + { + buf[len++] = ' '; + } + } + + return fb_json_out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + +#if defined(FB_JSON_PRINT_SUPPORT_EXPONENTIAL) +// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse +static size_t fb_json_ftoa_exp(fb_json_out_fn_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) + { + return fb_json_ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) + { + value = -value; + } + + // default precision + if (!(flags & FB_JSON_PRINT_FLAGS_PRECISION)) + { + prec = FB_JSON_PRINT_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union + { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) + { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & FB_JSON_PRINT_FLAGS_ADAPT_EXP) + { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) + { + if ((int)prec > expval) + { + prec = (unsigned)((int)prec - expval - 1); + } + else + { + prec = 0; + } + flags |= FB_JSON_PRINT_FLAGS_PRECISION; // make sure fb_json_ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } + else + { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & FB_JSON_PRINT_FLAGS_PRECISION)) + { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) + { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; + } + else + { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & FB_JSON_PRINT_FLAGS_LEFT) && minwidth) + { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) + { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = fb_json_ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FB_JSON_PRINT_FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) + { + // output the exponential symbol + out((flags & FB_JSON_PRINT_FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = fb_json_itoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth - 1, FB_JSON_PRINT_FLAGS_ZEROPAD | FB_JSON_PRINT_FLAGS_PLUS); + // might need to right-pad spaces + if (flags & FB_JSON_PRINT_FLAGS_LEFT) + { + while (idx - start_idx < width) + out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // FB_JSON_PRINT_SUPPORT_EXPONENTIAL +#endif // FB_JSON_PRINT_SUPPORT_FLOAT + +// internal vsnprintf +static int fb_json_vsnprintf_int(fb_json_out_fn_type out, char *buffer, const size_t maxlen, const char *format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) + { + // use null output function + out = fb_json_out_null; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') + { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else + { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do + { + switch (*format) + { + case '0': + flags |= FB_JSON_PRINT_FLAGS_ZEROPAD; + format++; + n = 1U; + break; + case '-': + flags |= FB_JSON_PRINT_FLAGS_LEFT; + format++; + n = 1U; + break; + case '+': + flags |= FB_JSON_PRINT_FLAGS_PLUS; + format++; + n = 1U; + break; + case ' ': + flags |= FB_JSON_PRINT_FLAGS_SPACE; + format++; + n = 1U; + break; + case '#': + flags |= FB_JSON_PRINT_FLAGS_HASH; + format++; + n = 1U; + break; + default: + n = 0U; + break; + } + } while (n); + + // evaluate width field + width = 0U; + if (fb_json_is_digit(*format)) + { + width = fb_json_atoi(&format); + } + else if (*format == '*') + { + const int w = va_arg(va, int); + if (w < 0) + { + flags |= FB_JSON_PRINT_FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else + { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') + { + flags |= FB_JSON_PRINT_FLAGS_PRECISION; + format++; + if (fb_json_is_digit(*format)) + { + precision = fb_json_atoi(&format); + } + else if (*format == '*') + { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) + { + case 'l': + flags |= FB_JSON_PRINT_FLAGS_LONG; + format++; + if (*format == 'l') + { + flags |= FB_JSON_PRINT_FLAGS_LONG_LONG; + format++; + } + break; + case 'h': + flags |= FB_JSON_PRINT_FLAGS_SHORT; + format++; + if (*format == 'h') + { + flags |= FB_JSON_PRINT_FLAGS_CHAR; + format++; + } + break; +#if defined(FB_JSON_PRINT_SUPPORT_PTRDIFF_T) + case 't': + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FB_JSON_PRINT_FLAGS_LONG : FB_JSON_PRINT_FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j': + flags |= (sizeof(intmax_t) == sizeof(long) ? FB_JSON_PRINT_FLAGS_LONG : FB_JSON_PRINT_FLAGS_LONG_LONG); + format++; + break; + case 'z': + flags |= (sizeof(size_t) == sizeof(long) ? FB_JSON_PRINT_FLAGS_LONG : FB_JSON_PRINT_FLAGS_LONG_LONG); + format++; + break; + default: + break; + } + + // evaluate specifier + switch (*format) + { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + case 'b': + { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') + { + base = 16U; + } + else if (*format == 'o') + { + base = 8U; + } + else if (*format == 'b') + { + base = 2U; + } + else + { + base = 10U; + flags &= ~FB_JSON_PRINT_FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') + { + flags |= FB_JSON_PRINT_FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) + { + flags &= ~(FB_JSON_PRINT_FLAGS_PLUS | FB_JSON_PRINT_FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FB_JSON_PRINT_FLAGS_PRECISION) + { + flags &= ~FB_JSON_PRINT_FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) + { + // signed + if (flags & FB_JSON_PRINT_FLAGS_LONG_LONG) + { +#if defined(FB_JSON_PRINT_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = fb_json_itoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & FB_JSON_PRINT_FLAGS_LONG) + { + const long value = va_arg(va, long); + idx = fb_json_itoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + else + { + const int value = (flags & FB_JSON_PRINT_FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FB_JSON_PRINT_FLAGS_SHORT) ? (short int)va_arg(va, int) + : va_arg(va, int); + idx = fb_json_itoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } + else + { + // unsigned + if (flags & FB_JSON_PRINT_FLAGS_LONG_LONG) + { +#if defined(FB_JSON_PRINT_SUPPORT_LONG_LONG) + idx = fb_json_itoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } + else if (flags & FB_JSON_PRINT_FLAGS_LONG) + { + idx = fb_json_itoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } + else + { + const unsigned int value = (flags & FB_JSON_PRINT_FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FB_JSON_PRINT_FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) + : va_arg(va, unsigned int); + idx = fb_json_itoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if defined(FB_JSON_PRINT_SUPPORT_FLOAT) + case 'f': + case 'F': + if (*format == 'F') + flags |= FB_JSON_PRINT_FLAGS_UPPERCASE; + idx = fb_json_ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#if defined(FB_JSON_PRINT_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g') || (*format == 'G')) + flags |= FB_JSON_PRINT_FLAGS_ADAPT_EXP; + if ((*format == 'E') || (*format == 'G')) + flags |= FB_JSON_PRINT_FLAGS_UPPERCASE; + idx = fb_json_ftoa_exp(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#endif // FB_JSON_PRINT_SUPPORT_EXPONENTIAL +#endif // FB_JSON_PRINT_SUPPORT_FLOAT + case 'c': + { + unsigned int l = 1U; + // pre padding + if (!(flags & FB_JSON_PRINT_FLAGS_LEFT)) + { + while (l++ < width) + { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FB_JSON_PRINT_FLAGS_LEFT) + { + while (l++ < width) + { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's': + { + const char *p = va_arg(va, char *); + unsigned int l = fb_json_strlen(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FB_JSON_PRINT_FLAGS_PRECISION) + { + l = (l < precision ? l : precision); + } + if (!(flags & FB_JSON_PRINT_FLAGS_LEFT)) + { + while (l++ < width) + { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FB_JSON_PRINT_FLAGS_PRECISION) || precision--)) + { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FB_JSON_PRINT_FLAGS_LEFT) + { + while (l++ < width) + { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p': + { + width = sizeof(void *) * 2U; + flags |= FB_JSON_PRINT_FLAGS_ZEROPAD | FB_JSON_PRINT_FLAGS_UPPERCASE; +#if defined(FB_JSON_PRINT_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) + { + idx = fb_json_itoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void *), false, 16U, precision, width, flags); + } + else + { +#endif + idx = fb_json_itoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void *)), false, 16U, precision, width, flags); +#if defined(FB_JSON_PRINT_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%': + out('%', buffer, idx++, maxlen); + format++; + break; + + default: + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + +/////////////////////////////////////////////////////////////////////////////// + +int fb_json_printf(const char *format, ...) +{ + va_list va; + va_start(va, format); + char buffer[1]; + const int ret = fb_json_vsnprintf_int(fb_json_out_char, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int fb_json_sprintf(char *buffer, const char *format, ...) +{ + va_list va; + va_start(va, format); + const int ret = fb_json_vsnprintf_int(fb_json_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int fb_json_snprintf_(char *buffer, size_t count, const char *format, ...) +{ + va_list va; + va_start(va, format); + const int ret = fb_json_vsnprintf_int(fb_json_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + +int fb_json_vprintf(const char *format, va_list va) +{ + char buffer[1]; + return fb_json_vsnprintf_int(fb_json_out_char, buffer, (size_t)-1, format, va); +} + +int fb_json_vsnprintf_(char *buffer, size_t count, const char *format, va_list va) +{ + return fb_json_vsnprintf_int(fb_json_out_buffer, buffer, count, format, va); +} + +int fb_json_fnprintf(void (*out)(char character, void *arg), void *arg, const char *format, ...) +{ + va_list va; + va_start(va, format); + const fb_json_out_fn_wrap_type out_fct_wrap = {out, arg}; + const int ret = fb_json_vsnprintf_int(fb_json_out_fn, (char *)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); + va_end(va); + return ret; +} + +#endif \ No newline at end of file diff --git a/src/lib/ESPSigner/json/extras/print/fb_json_print.h b/src/lib/ESPSigner/json/extras/print/fb_json_print.h new file mode 100644 index 0000000..db050bf --- /dev/null +++ b/src/lib/ESPSigner/json/extras/print/fb_json_print.h @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant. +// +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#ifndef FB_JSON_PRINT_H +#define FB_JSON_PRINT_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /** + * Output a character to a custom device like UART, used by the printf() function + * This function is declared here only. You have to write your custom implementation somewhere + * \param character Character to output + */ + void fb_json_putchar(char character) __attribute__((used)); + + /** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * To avoid conflicts with the regular printf() API it is overridden by macro defines + * and internal underscore-appended functions like printf_() are used + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not counting the terminating null character + */ + int fb_json_printf(const char *format, ...) __attribute__((used)); + + /** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! + * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ + int fb_json_sprintf(char *buffer, const char *format, ...) __attribute__((used)); + + /** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that COULD have been written into the buffer, not counting the terminating + * null character. A value equal or larger than count indicates truncation. Only when the returned value + * is non-negative and less than count, the string has been completely written. + */ +#define fb_json_snprintf fb_json_snprintf_ +#define fb_json_vsnprintf fb_json_vsnprintf_ + int fb_json_snprintf_(char *buffer, size_t count, const char *format, ...) __attribute__((used)); + int fb_json_vsnprintf_(char *buffer, size_t count, const char *format, va_list va) __attribute__((used)); + + /** + * Tiny vprintf implementation + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ + int fb_json_vprintf(const char *format, va_list va) __attribute__((used)); + + /** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() output + * \param out An output function which takes one character and an argument pointer + * \param arg An argument pointer for user data passed to output function + * \param format A string that specifies the format of the output + * \return The number of characters that are sent to the output function, not counting the terminating null character + */ + int fb_json_fnprintf(void (*out)(char character, void *arg), void *arg, const char *format, ...) __attribute__((used)); + +#ifdef __cplusplus +} +#endif + +#endif // _PRINTF_H_ \ No newline at end of file diff --git a/src/lib/ESPSigner/wcs/HTTPCode.h b/src/lib/ESPSigner/wcs/HTTPCode.h index bc4e573..16271e4 100644 --- a/src/lib/ESPSigner/wcs/HTTPCode.h +++ b/src/lib/ESPSigner/wcs/HTTPCode.h @@ -1,11 +1,11 @@ /** - * Created December 11, 2021 + * Created April 18, 2022 * * This work is a part of ESP Signer library - * Copyright (c) 2021, K. Suwatchai (Mobizt) + * Copyright (c) 2022, K. Suwatchai (Mobizt) * * The MIT License (MIT) - * Copyright (c) 2021, K. Suwatchai (Mobizt) + * Copyright (c) 2022, K. Suwatchai (Mobizt) * * * Permission is hereby granted, free of charge, to any person returning a copy of diff --git a/src/lib/ESPSigner/wcs/esp32/FB_TCP_Client.cpp b/src/lib/ESPSigner/wcs/esp32/ESP_Signer_TCP_Client.cpp similarity index 96% rename from src/lib/ESPSigner/wcs/esp32/FB_TCP_Client.cpp rename to src/lib/ESPSigner/wcs/esp32/ESP_Signer_TCP_Client.cpp index 9a5db50..c7edcee 100644 --- a/src/lib/ESPSigner/wcs/esp32/FB_TCP_Client.cpp +++ b/src/lib/ESPSigner/wcs/esp32/ESP_Signer_TCP_Client.cpp @@ -1,10 +1,10 @@ /** - * ESP Signer TCP Client v1.0.0 + * ESP Signer TCP Client v1.0.1 * - * Created December 11, 2021 + * Created April 18, 2022 * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2022 K. Suwatchai (Mobizt) * * * Copyright (c) 2015 Markus Sattler. All rights reserved. @@ -45,8 +45,8 @@ ESP_SIGNER_TCP_Client::~ESP_SIGNER_TCP_Client() _wcs.reset(nullptr); _wcs.release(); } - MBSTRING().swap(_host); - MBSTRING().swap(_CAFile); + MB_String().swap(_host); + MB_String().swap(_CAFile); } bool ESP_SIGNER_TCP_Client::begin(const char *host, uint16_t port) diff --git a/src/lib/ESPSigner/wcs/esp32/ESP_Signer_TCP_Client.h b/src/lib/ESPSigner/wcs/esp32/ESP_Signer_TCP_Client.h index ab8bea4..6624377 100644 --- a/src/lib/ESPSigner/wcs/esp32/ESP_Signer_TCP_Client.h +++ b/src/lib/ESPSigner/wcs/esp32/ESP_Signer_TCP_Client.h @@ -1,10 +1,10 @@ /** - * ESP Signer TCP Client v1.0.0 + * ESP Signer TCP Client v1.0.1 * - * Created December 11, 2021 + * Created April 18, 2022 * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2022 K. Suwatchai (Mobizt) * * * Copyright (c) 2015 Markus Sattler. All rights reserved. @@ -151,13 +151,13 @@ class ESP_SIGNER_TCP_Client private: std::unique_ptr _wcs = std::unique_ptr(new ESP_SIGNER_WCS()); - MBSTRING _host; + MB_String _host; uint16_t _port = 0; //lwIP socket connection and ssl handshake timeout unsigned long timeout = 10 * 1000; - MBSTRING _CAFile; + MB_String _CAFile; uint8_t _CAFileStoreageType = 0; int _certType = -1; bool _clockReady = false; diff --git a/src/lib/ESPSigner/wcs/esp8266/ESP_Signer_TCP_Client.cpp b/src/lib/ESPSigner/wcs/esp8266/ESP_Signer_TCP_Client.cpp index e82239d..242b2e3 100644 --- a/src/lib/ESPSigner/wcs/esp8266/ESP_Signer_TCP_Client.cpp +++ b/src/lib/ESPSigner/wcs/esp8266/ESP_Signer_TCP_Client.cpp @@ -1,29 +1,29 @@ /** - * ESP Signer TCP Client v1.0.0 - * - * Created December 11, 2021 - * + * ESP Signer TCP Client v1.0.1 + * + * Created April 18, 2022 + * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * + * Copyright (c) 2022 K. Suwatchai (Mobizt) + * + * * Permission is hereby granted, free of charge, to any person returning a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ + */ #ifndef ESP_SIGNER_TCP_Client_CPP #define ESP_SIGNER_TCP_Client_CPP @@ -39,33 +39,16 @@ ESP_SIGNER_TCP_Client::ESP_SIGNER_TCP_Client() ESP_SIGNER_TCP_Client::~ESP_SIGNER_TCP_Client() { release(); - MBSTRING().swap(_host); - MBSTRING().swap(_CAFile); + MB_String().swap(_host); + MB_String().swap(_CAFile); } bool ESP_SIGNER_TCP_Client::begin(const char *host, uint16_t port) { - if (strcmp(_host.c_str(), host) != 0) - mflnChecked = false; _host = host; _port = port; - - //probe for fragmentation support at the specified size - if (!mflnChecked) - { - fragmentable = _wcs->probeMaxFragmentLength(_host.c_str(), _port, chunkSize); - if (fragmentable) - { - _bsslRxSize = chunkSize; - _bsslTxSize = chunkSize; - _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); - } - mflnChecked = true; - } - - if (!fragmentable) - _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); + _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); return true; } @@ -118,6 +101,19 @@ bool ESP_SIGNER_TCP_Client::connect(void) return connected(); } +void ESP_SIGNER_TCP_Client::setInsecure() +{ + if (_wcs) + _wcs->setInsecure(); +} + +void ESP_SIGNER_TCP_Client::setBufferSizes(int rx, int tx) +{ + _bsslRxSize = rx; + _bsslTxSize = tx; + _wcs->setBufferSizes(rx, tx); +} + void ESP_SIGNER_TCP_Client::release() { if (_wcs) @@ -135,7 +131,7 @@ void ESP_SIGNER_TCP_Client::setCACert(const char *caCert) release(); - _wcs = std::unique_ptr(new ESP_SIGNER_ESP_SSL_CLIENT()); + _wcs = std::unique_ptr(new ESP_SIGNER_WCS()); _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); diff --git a/src/lib/ESPSigner/wcs/esp8266/ESP_Signer_TCP_Client.h b/src/lib/ESPSigner/wcs/esp8266/ESP_Signer_TCP_Client.h index bae0cc5..a26a958 100644 --- a/src/lib/ESPSigner/wcs/esp8266/ESP_Signer_TCP_Client.h +++ b/src/lib/ESPSigner/wcs/esp8266/ESP_Signer_TCP_Client.h @@ -1,29 +1,29 @@ /** - * ESP Signer TCP Client v1.0.0 - * - * Created December 11, 2021 - * + * ESP Signer TCP Client v1.0.1 + * + * Created April 18, 2022 + * * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * + * Copyright (c) 2022 K. Suwatchai (Mobizt) + * + * * Permission is hereby granted, free of charge, to any person returning a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ + */ #ifndef ESP_SIGNER_TCP_Client_H #define ESP_SIGNER_TCP_Client_H @@ -49,7 +49,7 @@ #error Your ESP8266 Arduino Core SDK is outdated, please update. From Arduino IDE go to Boards Manager and search 'esp8266' then select the latest version. #endif -//2.6.1 BearSSL bug +// 2.6.1 BearSSL bug #if ARDUINO_ESP8266_GIT_VER == 0x482516e3 #error Due to bugs in BearSSL in ESP8266 Arduino Core SDK version 2.6.1, please update ESP8266 Arduino Core SDK to newer version. The issue was found here https:\/\/github.com/esp8266/Arduino/issues/6811. #endif @@ -112,6 +112,13 @@ struct esp_signer_sd_config_info_t int ss = -1; }; +class ESP_SIGNER_WCS : public BearSSL::WiFiClientSecure +{ +public: + ESP_SIGNER_WCS(){}; + ~ESP_SIGNER_WCS(){}; +}; + class ESP_SIGNER_TCP_Client { @@ -126,47 +133,48 @@ class ESP_SIGNER_TCP_Client * \param host - Host name without protocols. * \param port - Server's port. * \return True as default. - * If no certificate string provided, use (const char*)NULL to CAcert param - */ + * If no certificate string provided, use (const char*)NULL to CAcert param + */ bool begin(const char *host, uint16_t port); /** * Check the http connection status. * \return True if connected. - */ + */ bool connected(void); /** - * Establish TCP connection when required and send data. - * \param data - The data to send. - * \param len - The length of data to send. - * - * \return TCP status code, Return zero if new TCP connection and data sent. - */ + * Establish TCP connection when required and send data. + * \param data - The data to send. + * \param len - The length of data to send. + * + * \return TCP status code, Return zero if new TCP connection and data sent. + */ int send(const char *data, size_t len = 0); /** * Get the WiFi client pointer. * \return WiFi client pointer. - */ + */ WiFiClient *stream(void); void setCACert(const char *caCert); void setCACertFile(const char *caCertFile, uint8_t storageType, struct esp_signer_sd_config_info_t sd_config); bool connect(void); void setInsecure(); + void setBufferSizes(int rx, int tx); private: - std::unique_ptr _wcs = std::unique_ptr(new ESP_SIGNER_ESP_SSL_CLIENT()); - MBSTRING _host; + std::unique_ptr _wcs = std::unique_ptr(new ESP_SIGNER_WCS()); + MB_String _host; uint16_t _port = 0; - //Actually Arduino base Stream (char read) timeout. - //This will override internally by WiFiClientSecureCtx::_connectSSL - //to 5000 after SSL handshake was done with success. + // Actually Arduino base Stream (char read) timeout. + // This will override internally by WiFiClientSecureCtx::_connectSSL + // to 5000 after SSL handshake was done with success. unsigned long timeout = 10 * 1000; - MBSTRING _CAFile; + MB_String _CAFile; uint8_t _CAFileStoreageType = 0; int _certType = -1; uint8_t _sdPin = 15; @@ -174,8 +182,6 @@ class ESP_SIGNER_TCP_Client uint16_t _bsslRxSize = 512; uint16_t _bsslTxSize = 512; bool fragmentable = false; - int chunkSize = 1024; - bool mflnChecked = false; X509List *x509 = nullptr; void release();