@@ -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