Skip to content

Commit 64ebd41

Browse files
willmmilesclaude
andcommitted
Factor out streaming JSON primitives
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 67be835 commit 64ebd41

1 file changed

Lines changed: 42 additions & 12 deletions

File tree

wled00/json.cpp

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,42 @@ void serializeModeNames(JsonArray arr)
11761176
}
11771177
}
11781178

1179+
// Writes a JSON-escaped string (with surrounding quotes) into dest[0..maxLen-1].
1180+
// Returns bytes written, or 0 if the buffer was too small.
1181+
static size_t writeJSONString(uint8_t* dest, size_t maxLen, const char* src) {
1182+
size_t pos = 0;
1183+
1184+
auto emit = [&](char c) -> bool {
1185+
if (pos >= maxLen) return false;
1186+
dest[pos++] = (uint8_t)c;
1187+
return true;
1188+
};
1189+
1190+
if (!emit('"')) return 0;
1191+
1192+
for (const char* p = src; *p; ++p) {
1193+
char esc = ARDUINOJSON_NAMESPACE::EscapeSequence::escapeChar(*p);
1194+
if (esc) {
1195+
if (!emit('\\') || !emit(esc)) return 0;
1196+
} else {
1197+
if (!emit(*p)) return 0;
1198+
}
1199+
}
1200+
1201+
if (!emit('"')) return 0;
1202+
return pos;
1203+
}
1204+
1205+
// Writes ,"<escaped_src>" into dest[0..maxLen-1] (no null terminator).
1206+
// Returns bytes written, or 0 if the buffer was too small.
1207+
static size_t writeJSONStringElement(uint8_t* dest, size_t maxLen, const char* src) {
1208+
if (maxLen == 0) return 0;
1209+
dest[0] = ',';
1210+
size_t n = writeJSONString(dest + 1, maxLen - 1, src);
1211+
if (n == 0) return 0;
1212+
return 1 + n;
1213+
}
1214+
11791215
// Generate a streamed JSON response for the mode data
11801216
// This uses sendChunked to send the reply in blocks based on how much fit in the outbound
11811217
// packet buffer, minimizing the required state (ie. just the next index to send). This
@@ -1187,19 +1223,13 @@ void respondModeData(AsyncWebServerRequest* request) {
11871223
[fx_index](uint8_t* data, size_t len, size_t) mutable {
11881224
size_t bytes_written = 0;
11891225
char lineBuffer[256];
1190-
while (fx_index < strip.getModeCount() && (len > 5)) {
1191-
strncpy_P(lineBuffer, strip.getModeData(fx_index), sizeof(lineBuffer)/sizeof(char)-1); // Copy to stack buffer for strchr
1226+
while (fx_index < strip.getModeCount()) {
1227+
strncpy_P(lineBuffer, strip.getModeData(fx_index), sizeof(lineBuffer)-1); // Copy to stack buffer for strchr
11921228
if (lineBuffer[0] != 0) {
1193-
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
1194-
char* dataPtr = strchr(lineBuffer,'@'); // Find '@', if there is one
1195-
size_t mode_bytes;
1196-
if (dataPtr) {
1197-
mode_bytes = snprintf_P((char*) data, len, PSTR(",\"%s\""), dataPtr + 1);
1198-
if (mode_bytes >= len) break; // didn't fit; break loop and try again next packet
1199-
} else {
1200-
strncpy_P((char*)data, PSTR(",\"\""), len);
1201-
mode_bytes = 3;
1202-
}
1229+
lineBuffer[sizeof(lineBuffer)-1] = '\0'; // terminate string (only needed if strncpy filled the buffer)
1230+
const char* dataPtr = strchr(lineBuffer,'@'); // Find '@', if there is one
1231+
size_t mode_bytes = writeJSONStringElement(data, len, dataPtr ? dataPtr + 1 : "");
1232+
if (mode_bytes == 0) break; // didn't fit; break loop and try again next packet
12031233
if (fx_index == 0) *data = '[';
12041234
data += mode_bytes;
12051235
len -= mode_bytes;

0 commit comments

Comments
 (0)