diff --git a/Software/components/core/src/AudioProfileJson.cpp b/Software/components/core/src/AudioProfileJson.cpp index 3edcb72..89e3511 100644 --- a/Software/components/core/src/AudioProfileJson.cpp +++ b/Software/components/core/src/AudioProfileJson.cpp @@ -58,15 +58,24 @@ namespace { std::string_view key, bool& out) { - const std::string trueNeedle = - std::string("\"") + std::string(key) + "\":true"; - const std::string falseNeedle = - std::string("\"") + std::string(key) + "\":false"; - if (json.find(trueNeedle) != std::string_view::npos) { + const std::string needle = + std::string("\"") + std::string(key) + "\":"; + const std::size_t needlePos = json.find(needle); + if (needlePos == std::string_view::npos) { + return false; + } + std::size_t start = needlePos + needle.size(); + while (start < json.size() + && (json[start] == ' ' || json[start] == '\t' + || json[start] == '\r' || json[start] == '\n')) { + ++start; + } + const std::string_view rest = json.substr(start); + if (rest.starts_with("true")) { out = true; return true; } - if (json.find(falseNeedle) != std::string_view::npos) { + if (rest.starts_with("false")) { out = false; return true; } diff --git a/Software/components/core/src/BluetoothJson.cpp b/Software/components/core/src/BluetoothJson.cpp index a126130..4f53950 100644 --- a/Software/components/core/src/BluetoothJson.cpp +++ b/Software/components/core/src/BluetoothJson.cpp @@ -150,12 +150,21 @@ parseBluetoothConnectJson(std::string_view json) if (json.find('{') == std::string_view::npos) { return std::unexpected(ParseError::InvalidJson); } - const std::string needle = "\"mac\":\""; - const std::size_t start = json.find(needle); - if (start == std::string_view::npos) { + const std::string needle = "\"mac\":"; + const std::size_t needlePos = json.find(needle); + if (needlePos == std::string_view::npos) { return std::unexpected(ParseError::MissingField); } - const std::size_t valueStart = start + needle.size(); + std::size_t start = needlePos + needle.size(); + while (start < json.size() + && (json[start] == ' ' || json[start] == '\t' + || json[start] == '\r' || json[start] == '\n')) { + ++start; + } + if (start >= json.size() || json[start] != '"') { + return std::unexpected(ParseError::InvalidJson); + } + const std::size_t valueStart = start + 1U; const std::size_t valueEnd = json.find('"', valueStart); if (valueEnd == std::string_view::npos) { return std::unexpected(ParseError::InvalidJson); @@ -183,17 +192,35 @@ BluetoothConnectRequest parseBluetoothConnectRequest(std::string_view json) if (auto mac = parseBluetoothConnectJson(json); mac) { request.mac = std::move(*mac); } - const std::string nameNeedle = "\"name\":\""; - const std::size_t nameStart = json.find(nameNeedle); - if (nameStart != std::string_view::npos) { - const std::size_t valueStart = nameStart + nameNeedle.size(); - const std::size_t valueEnd = json.find('"', valueStart); - if (valueEnd != std::string_view::npos) { - request.name.assign(json.substr(valueStart, valueEnd - valueStart)); + const std::string nameNeedle = "\"name\":"; + const std::size_t nameNeedlePos = json.find(nameNeedle); + if (nameNeedlePos != std::string_view::npos) { + std::size_t nameStart = nameNeedlePos + nameNeedle.size(); + while (nameStart < json.size() + && (json[nameStart] == ' ' || json[nameStart] == '\t' + || json[nameStart] == '\r' || json[nameStart] == '\n')) { + ++nameStart; + } + if (nameStart < json.size() && json[nameStart] == '"') { + const std::size_t valueStart = nameStart + 1U; + const std::size_t valueEnd = json.find('"', valueStart); + if (valueEnd != std::string_view::npos) { + request.name.assign( + json.substr(valueStart, valueEnd - valueStart)); + } } } - request.save = json.find("\"save\":true") != std::string_view::npos - || json.find("\"save\": true") != std::string_view::npos; + const std::string saveNeedle = "\"save\":"; + const std::size_t saveNeedlePos = json.find(saveNeedle); + if (saveNeedlePos != std::string_view::npos) { + std::size_t saveStart = saveNeedlePos + saveNeedle.size(); + while (saveStart < json.size() + && (json[saveStart] == ' ' || json[saveStart] == '\t' + || json[saveStart] == '\r' || json[saveStart] == '\n')) { + ++saveStart; + } + request.save = json.substr(saveStart).starts_with("true"); + } return request; } @@ -219,13 +246,22 @@ parseBluetoothSpeakerJson(std::string_view json) return std::unexpected(mac.error()); } BtSpeakerTarget target{.mac = *mac, .name = {}}; - const std::string nameNeedle = "\"name\":\""; - const std::size_t nameStart = json.find(nameNeedle); - if (nameStart != std::string_view::npos) { - const std::size_t valueStart = nameStart + nameNeedle.size(); - const std::size_t valueEnd = json.find('"', valueStart); - if (valueEnd != std::string_view::npos) { - target.name.assign(json.substr(valueStart, valueEnd - valueStart)); + const std::string nameNeedle = "\"name\":"; + const std::size_t nameNeedlePos = json.find(nameNeedle); + if (nameNeedlePos != std::string_view::npos) { + std::size_t nameStart = nameNeedlePos + nameNeedle.size(); + while (nameStart < json.size() + && (json[nameStart] == ' ' || json[nameStart] == '\t' + || json[nameStart] == '\r' || json[nameStart] == '\n')) { + ++nameStart; + } + if (nameStart < json.size() && json[nameStart] == '"') { + const std::size_t valueStart = nameStart + 1U; + const std::size_t valueEnd = json.find('"', valueStart); + if (valueEnd != std::string_view::npos) { + target.name.assign( + json.substr(valueStart, valueEnd - valueStart)); + } } } return target; diff --git a/Software/components/core/src/DspParamJson.cpp b/Software/components/core/src/DspParamJson.cpp index 4868f6c..00be98e 100644 --- a/Software/components/core/src/DspParamJson.cpp +++ b/Software/components/core/src/DspParamJson.cpp @@ -24,12 +24,21 @@ namespace { std::string_view key) { const std::string needle = - std::string("\"") + std::string(key) + "\":\""; - const std::size_t start = json.find(needle); - if (start == std::string_view::npos) { + std::string("\"") + std::string(key) + "\":"; + const std::size_t needlePos = json.find(needle); + if (needlePos == std::string_view::npos) { return {}; } - const std::size_t valueStart = start + needle.size(); + std::size_t start = needlePos + needle.size(); + while (start < json.size() + && (json[start] == ' ' || json[start] == '\t' + || json[start] == '\r' || json[start] == '\n')) { + ++start; + } + if (start >= json.size() || json[start] != '"') { + return {}; + } + const std::size_t valueStart = start + 1U; const std::size_t valueEnd = json.find('"', valueStart); if (valueEnd == std::string_view::npos) { return {}; diff --git a/Software/components/core/src/StationListJson.cpp b/Software/components/core/src/StationListJson.cpp index a46287c..faba0fc 100644 --- a/Software/components/core/src/StationListJson.cpp +++ b/Software/components/core/src/StationListJson.cpp @@ -24,12 +24,21 @@ namespace { std::string_view key) { const std::string needle = - std::string("\"") + std::string(key) + "\":\""; - const std::size_t start = json.find(needle); - if (start == std::string_view::npos) { + std::string("\"") + std::string(key) + "\":"; + const std::size_t needlePos = json.find(needle); + if (needlePos == std::string_view::npos) { return {}; } - const std::size_t valueStart = start + needle.size(); + std::size_t start = needlePos + needle.size(); + while (start < json.size() + && (json[start] == ' ' || json[start] == '\t' + || json[start] == '\r' || json[start] == '\n')) { + ++start; + } + if (start >= json.size() || json[start] != '"') { + return {}; + } + const std::size_t valueStart = start + 1U; const std::size_t valueEnd = json.find('"', valueStart); if (valueEnd == std::string_view::npos) { return {}; diff --git a/Software/components/core/src/TunerJson.cpp b/Software/components/core/src/TunerJson.cpp index 84297ad..b69e1fc 100644 --- a/Software/components/core/src/TunerJson.cpp +++ b/Software/components/core/src/TunerJson.cpp @@ -24,12 +24,21 @@ namespace { std::string_view key) { const std::string needle = - std::string("\"") + std::string(key) + "\":\""; - const std::size_t start = json.find(needle); - if (start == std::string_view::npos) { + std::string("\"") + std::string(key) + "\":"; + const std::size_t needlePos = json.find(needle); + if (needlePos == std::string_view::npos) { return {}; } - const std::size_t valueStart = start + needle.size(); + std::size_t start = needlePos + needle.size(); + while (start < json.size() + && (json[start] == ' ' || json[start] == '\t' + || json[start] == '\r' || json[start] == '\n')) { + ++start; + } + if (start >= json.size() || json[start] != '"') { + return {}; + } + const std::size_t valueStart = start + 1U; const std::size_t valueEnd = json.find('"', valueStart); if (valueEnd == std::string_view::npos) { return {}; diff --git a/Software/components/core/src/WebRadioJson.cpp b/Software/components/core/src/WebRadioJson.cpp index fee4b2f..5f4c870 100644 --- a/Software/components/core/src/WebRadioJson.cpp +++ b/Software/components/core/src/WebRadioJson.cpp @@ -24,12 +24,21 @@ constexpr std::string_view kHttpPrefix = "http://"; std::string_view key) { const std::string needle = - std::string("\"") + std::string(key) + "\":\""; - const std::size_t start = json.find(needle); - if (start == std::string_view::npos) { + std::string("\"") + std::string(key) + "\":"; + const std::size_t needlePos = json.find(needle); + if (needlePos == std::string_view::npos) { return {}; } - const std::size_t valueStart = start + needle.size(); + std::size_t start = needlePos + needle.size(); + while (start < json.size() + && (json[start] == ' ' || json[start] == '\t' + || json[start] == '\r' || json[start] == '\n')) { + ++start; + } + if (start >= json.size() || json[start] != '"') { + return {}; + } + const std::size_t valueStart = start + 1U; const std::size_t valueEnd = json.find('"', valueStart); if (valueEnd == std::string_view::npos) { return {}; @@ -40,15 +49,24 @@ constexpr std::string_view kHttpPrefix = "http://"; [[nodiscard]] bool extractJsonBool(std::string_view json, std::string_view key, bool& out) { - const std::string trueNeedle = - std::string("\"") + std::string(key) + "\":true"; - const std::string falseNeedle = - std::string("\"") + std::string(key) + "\":false"; - if (json.find(trueNeedle) != std::string_view::npos) { + const std::string needle = + std::string("\"") + std::string(key) + "\":"; + const std::size_t needlePos = json.find(needle); + if (needlePos == std::string_view::npos) { + return false; + } + std::size_t start = needlePos + needle.size(); + while (start < json.size() + && (json[start] == ' ' || json[start] == '\t' + || json[start] == '\r' || json[start] == '\n')) { + ++start; + } + const std::string_view rest = json.substr(start); + if (rest.starts_with("true")) { out = true; return true; } - if (json.find(falseNeedle) != std::string_view::npos) { + if (rest.starts_with("false")) { out = false; return true; } diff --git a/Software/components/core/src/WifiProvisionJson.cpp b/Software/components/core/src/WifiProvisionJson.cpp index f3590e0..1739dc9 100644 --- a/Software/components/core/src/WifiProvisionJson.cpp +++ b/Software/components/core/src/WifiProvisionJson.cpp @@ -37,12 +37,21 @@ namespace { [[nodiscard]] std::string_view extractJsonString(std::string_view json, std::string_view key) { - const std::string needle = std::string("\"") + std::string(key) + "\":\""; - const std::size_t start = json.find(needle); - if (start == std::string_view::npos) { + const std::string needle = std::string("\"") + std::string(key) + "\":"; + const std::size_t needlePos = json.find(needle); + if (needlePos == std::string_view::npos) { return {}; } - const std::size_t valueStart = start + needle.size(); + std::size_t start = needlePos + needle.size(); + while (start < json.size() + && (json[start] == ' ' || json[start] == '\t' + || json[start] == '\r' || json[start] == '\n')) { + ++start; + } + if (start >= json.size() || json[start] != '"') { + return {}; + } + const std::size_t valueStart = start + 1U; const std::size_t valueEnd = json.find('"', valueStart); if (valueEnd == std::string_view::npos) { return {}; diff --git a/Software/components/secure_store/src/NvsAudioProfileStore.cpp b/Software/components/secure_store/src/NvsAudioProfileStore.cpp index 01c2b5a..9cacbea 100644 --- a/Software/components/secure_store/src/NvsAudioProfileStore.cpp +++ b/Software/components/secure_store/src/NvsAudioProfileStore.cpp @@ -26,7 +26,12 @@ namespace secure_store { namespace { constexpr char kTag[] = "NvsAudioProfileStore"; constexpr char kNamespace[] = "digiradio"; -constexpr char kProfileKey[] = "audio_profile_json"; +// NVS key names are capped at 15 chars (NVS_KEY_NAME_MAX_SIZE=16 incl. NUL); +// the previous "audio_profile_json" (18 chars) made every nvs_set_str call +// fail with ESP_ERR_NVS_KEY_TOO_LONG (0x1109), silently -- applyProfile() +// always updated live audio correctly but persistProfile() never actually +// wrote anything, so nothing survived a reboot. +constexpr char kProfileKey[] = "audio_profile"; } // namespace bool NvsAudioProfileStore::hasProfile() const