Files
product-vamp/src/vamp_pico/remote_display.cpp
T
khodowany 82349cf897
ci / checks (push) Failing after 23m37s
Playback
2026-10-05 23:41:11 -05:00

110 lines
3.7 KiB
C++

#include <algorithm>
#include <charconv>
#include <cstring>
#include <limits>
#include <system_error>
#include <vamp_pico/http_client.hpp>
namespace {
auto copy_value(std::string_view value, std::char_t *output, std::size_t capacity) -> void {
if (capacity == 0U) {
return;
}
auto count = std::min(capacity - 1U, value.size());
std::memcpy(output, value.data(), count);
output[count] = '\0';
}
auto parse_uint(std::string_view value, std::uint32_t &output) -> std::bool_t {
if (value.empty()) {
return false;
}
auto parsed = std::uint64_t{};
auto const *begin = value.data();
auto const *end = value.data() + value.size();
auto result = std::from_chars(begin, end, parsed, 10);
if (result.ec != std::errc{} || result.ptr != end || parsed > std::numeric_limits<std::uint32_t>::max()) {
return false;
}
output = static_cast<std::uint32_t>(parsed);
return true;
}
auto strip_cr(std::string_view line) -> std::string_view {
if (!line.empty() && line.back() == '\r') {
line.remove_suffix(1U);
}
return line;
}
}
auto vamp_pico::parse_remote_display_body(std::string_view body, vamp_pico::remote_display_state &state) -> std::bool_t {
auto parsed = vamp_pico::remote_display_state{};
auto cursor = std::size_t{};
while (cursor <= body.size()) {
auto line_end = body.find('\n', cursor);
auto line = line_end == std::string_view::npos ? body.substr(cursor) : body.substr(cursor, line_end - cursor);
line = strip_cr(line);
auto equals = line.find('=');
if (equals != std::string_view::npos) {
auto key = line.substr(0U, equals);
auto value = line.substr(equals + 1U);
if (key == "active") {
parsed.active = value == "1";
} else if (key == "title") {
copy_value(value, parsed.title, sizeof(parsed.title));
} else if (key == "title_image") {
if (!value.empty() && !vamp_protocol::valid_title_id(value)) {
return false;
}
copy_value(value, parsed.title_image.data(), parsed.title_image.size());
} else if (key == "part") {
copy_value(value, parsed.part, sizeof(parsed.part));
} else if (key == "mode") {
copy_value(value, parsed.mode, sizeof(parsed.mode));
} else if (key == "focus") {
if (value.size() >= sizeof(parsed.focus)) {
return false;
}
copy_value(value, parsed.focus, sizeof(parsed.focus));
} else if (key == "phase") {
if (value.size() >= parsed.phase.size()) {
return false;
}
std::copy(value.begin(), value.end(), parsed.phase.begin());
} else if (key == "backing" || key == "metronome" || key == "editing" || key == "error" || key == "backing_available") {
if (value != "0" && value != "1") {
return false;
}
auto &flag = key == "backing_available" ? parsed.backing_available : key == "error" ? parsed.error
: key == "backing" ? parsed.backing
: key == "metronome" ? parsed.metronome
: parsed.editing;
flag = value == "1";
} else if (key == "bpm") {
if (!parse_uint(value, parsed.bpm) || parsed.bpm == 0U || parsed.bpm > 400U) {
return false;
}
} else if (key == "page") {
if (!parse_uint(value, parsed.page)) {
return false;
}
} else if (key == "pages") {
if (!parse_uint(value, parsed.pages)) {
return false;
}
}
}
if (line_end == std::string_view::npos) {
break;
}
cursor = line_end + 1U;
}
state = parsed;
return true;
}