Harden history parsing and single-point chart rendering

This commit is contained in:
2026-02-17 00:32:48 +01:00
parent 5c71bf841a
commit 8d42631045

View File

@@ -252,6 +252,40 @@ static String history_date_from_epoch(uint32_t ts_utc) {
return String(buf); return String(buf);
} }
static bool history_parse_u32_field(const char *start, size_t len, uint32_t &out) {
if (!start || len == 0 || len >= 16) {
return false;
}
char buf[16];
memcpy(buf, start, len);
buf[len] = '\0';
char *end = nullptr;
unsigned long value = strtoul(buf, &end, 10);
if (end == buf || *end != '\0' || value > static_cast<unsigned long>(UINT32_MAX)) {
return false;
}
out = static_cast<uint32_t>(value);
return true;
}
static bool history_parse_float_field(const char *start, size_t len, float &out) {
if (!start || len == 0 || len >= 24) {
return false;
}
char buf[24];
memcpy(buf, start, len);
buf[len] = '\0';
char *end = nullptr;
float value = strtof(buf, &end);
if (end == buf || *end != '\0') {
return false;
}
out = value;
return true;
}
static bool history_open_next_file() { static bool history_open_next_file() {
if (!g_history.active || g_history.done || g_history.error) { if (!g_history.active || g_history.done || g_history.error) {
return false; return false;
@@ -274,40 +308,32 @@ static bool history_parse_line(const char *line, uint32_t &ts_out, float &p_out)
if (!line || line[0] < '0' || line[0] > '9') { if (!line || line[0] < '0' || line[0] > '9') {
return false; return false;
} }
const char *comma1 = strchr(line, ','); const char *comma1 = strchr(line, ',');
if (!comma1) { if (!comma1) {
return false; return false;
} }
char ts_buf[16];
size_t ts_len = static_cast<size_t>(comma1 - line); uint32_t ts = 0;
if (ts_len >= sizeof(ts_buf)) { if (!history_parse_u32_field(line, static_cast<size_t>(comma1 - line), ts)) {
return false;
}
memcpy(ts_buf, line, ts_len);
ts_buf[ts_len] = '\0';
char *end = nullptr;
uint32_t ts = static_cast<uint32_t>(strtoul(ts_buf, &end, 10));
if (end == ts_buf) {
return false; return false;
} }
const char *comma2 = strchr(comma1 + 1, ','); const char *comma2 = strchr(comma1 + 1, ',');
if (!comma2) { if (!comma2) {
return false; return false;
} }
const char *p_start = comma2 + 1;
const char *p_end = strchr(p_start, ','); float p = 0.0f;
char p_buf[16]; if (!history_parse_float_field(comma1 + 1, static_cast<size_t>(comma2 - (comma1 + 1)), p)) {
size_t p_len = p_end ? static_cast<size_t>(p_end - p_start) : strlen(p_start); const char *p_start = comma2 + 1;
if (p_len == 0 || p_len >= sizeof(p_buf)) { const char *p_end = strchr(p_start, ',');
return false; size_t p_len = p_end ? static_cast<size_t>(p_end - p_start) : strlen(p_start);
} if (!history_parse_float_field(p_start, p_len, p)) {
memcpy(p_buf, p_start, p_len); return false;
p_buf[p_len] = '\0'; }
char *endp = nullptr;
float p = strtof(p_buf, &endp);
if (endp == p_buf) {
return false;
} }
ts_out = ts; ts_out = ts;
p_out = p; p_out = p;
return true; return true;
@@ -649,10 +675,11 @@ static void handle_sender() {
html += "if(min===max){min=0;}"; html += "if(min===max){min=0;}";
html += "ctx.strokeStyle='#333';ctx.lineWidth=1;ctx.beginPath();"; html += "ctx.strokeStyle='#333';ctx.lineWidth=1;ctx.beginPath();";
html += "let first=true;"; html += "let first=true;";
html += "const xDen=series.length>1?(series.length-1):1;";
html += "for(let i=0;i<series.length;i++){"; html += "for(let i=0;i<series.length;i++){";
html += "const v=series[i][1];"; html += "const v=series[i][1];";
html += "if(v===null)continue;"; html += "if(v===null)continue;";
html += "const x=(i/(series.length-1))* (w-2) + 1;"; html += "const x=series.length>1?((i/xDen)*(w-2)+1):(w/2);";
html += "const y=h-2-((v-min)/(max-min))*(h-4);"; html += "const y=h-2-((v-min)/(max-min))*(h-4);";
html += "if(first){ctx.moveTo(x,y);first=false;} else {ctx.lineTo(x,y);} }"; html += "if(first){ctx.moveTo(x,y);first=false;} else {ctx.lineTo(x,y);} }";
html += "ctx.stroke();"; html += "ctx.stroke();";