Skip to content

Commit 0801df8

Browse files
committed
fix URLdecode in VLC m3u files #136
add: urldecode() del: UTF8toASCII() del: ASCIItoUTF8()
1 parent b24a419 commit 0801df8

File tree

2 files changed

+79
-79
lines changed

2 files changed

+79
-79
lines changed

src/common.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// created: 10.02.2022
2-
// updated: 20.12.2022
1+
// created: 10.Feb.2022
2+
// updated: 14.Mar.2023
33

44
#pragma once
55

@@ -138,9 +138,8 @@
138138
// //prototypes (main.cpp)
139139
boolean defaultsettings();
140140
boolean saveStationsToNVS();
141+
void urldecode(char *str);
141142
void setTFTbrightness(uint8_t duty);
142-
const char* UTF8toASCII(const char* str);
143-
const char* ASCIItoUTF8(const char* str);
144143
void showHeadlineVolume();
145144
void showHeadlineTime(bool complete = true);
146145
void showHeadlineItem(uint8_t idx);
@@ -165,6 +164,7 @@ const char* listAudioFile();
165164
bool sendAudioList2Web(const char* audioDir);
166165
bool connectToWiFi();
167166
const char* byte_to_binary(int8_t x);
167+
void trim(char *s);
168168
bool startsWith (const char* base, const char* str);
169169
bool endsWith (const char* base, const char* str);
170170
int indexOf (const char* base, const char* str, int startIndex);

src/main.cpp

Lines changed: 75 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
MiniWebRadio -- Webradio receiver for ESP32
33
44
first release on 03/2017
5-
Version 2.4d, Mar 13/2022
5+
Version 2.5, Mar 14/2022
66
77
2.8" color display (320x240px) with controller ILI9341 or HX8347D (SPI) or
88
3.5" color display (480x320px) wiht controller ILI9486 or ILI9488 (SPI)
@@ -371,60 +371,41 @@ inline uint8_t getBrightness(){
371371
return pref.getUShort("brightness");
372372
}
373373
/***********************************************************************************************************************
374-
* A S C I I *
374+
* U R L d e c o d e *
375375
***********************************************************************************************************************/
376-
const char* UTF8toASCII(const char* str){
377-
uint16_t i = 0, j = 0;
378-
char tab[96] = {
379-
96, 173, 155, 156, 32, 157, 32, 32, 32, 32, 166, 174, 170, 32, 32, 32, 248, 241, 253, 32,
380-
32, 230, 32, 250, 32, 32, 167, 175, 172, 171, 32, 168, 32, 32, 32, 32, 142, 143, 146, 128,
381-
32, 144, 32, 32, 32, 32, 32, 32, 32, 165, 32, 32, 32, 32, 153, 32, 32, 32, 32, 32,
382-
154, 32, 32, 225, 133, 160, 131, 32, 132, 134, 145, 135, 138, 130, 136, 137, 141, 161, 140, 139,
383-
32, 164, 149, 162, 147, 32, 148, 246, 32, 151, 163, 150, 129, 32, 32, 152
384-
};
385-
while((str[i] != 0) && (j < 1020)){
386-
_chbuf[j] = str[i];
387-
if(str[i] == 0xC2){ // compute unicode from utf8
388-
i++;
389-
if((str[i] > 159) && (str[i] < 192)) _chbuf[j] = tab[str[i] - 160];
390-
else _chbuf[j] = 32;
391-
}
392-
else if(str[i] == 0xC3){
393-
i++;
394-
if((str[i] > 127) && (str[i] < 192)) _chbuf[j] = tab[str[i] - 96];
395-
else _chbuf[j] = 32;
396-
}
397-
i++; j++;
398-
}
399-
_chbuf[j] = 0;
400-
return (_chbuf);
401-
}
402-
const char* ASCIItoUTF8(const char* str){
403-
uint16_t i = 0, j = 0, uni = 0;
404-
uint16_t tab[128] = {
405-
199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197,
406-
201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 162, 163, 165, 8359, 402,
407-
225, 237, 243, 250, 241, 209, 170, 186, 191, 8976, 172, 189, 188, 161, 171, 187,
408-
9617, 9618, 9619, 9474, 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564, 9563, 9488,
409-
9492, 9524, 9516, 9500, 9472, 9532, 9566, 9567, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575,
410-
9576, 9572, 9573, 9561, 9560, 9554, 9555, 9579, 9578, 9496, 9484, 9608, 9604, 9612, 9616, 9600,
411-
945, 223, 915, 960, 931, 963, 181, 964, 934, 920, 937, 948, 8734, 966, 949, 8745,
412-
8801, 177, 8805, 8804, 8992, 8993, 247, 8776, 176, 8729, 183, 8730, 8319, 178, 9632, 160
413-
};
414-
while((str[i] != 0) && (j < 1020)){
415-
uni = str[i];
416-
if(uni >= 128){uni -= 128; uni = tab[uni];}
417-
// uni=UTF8fromASCII(str[i]);
418-
switch(uni){
419-
case 0 ... 127:{_chbuf[j] = str[i]; i++; j++; break;}
420-
case 160 ... 191:{_chbuf[j] = 0xC2; _chbuf[j+1] = uni; j += 2; i++; break;}
421-
case 192 ... 255:{_chbuf[j] = 0xC3; _chbuf[j+1] = uni - 64; j += 2; i++; break;}
422-
default:{_chbuf[j] = ' '; i++; j++; break;} // ignore all other
376+
// In m3u playlists, file names can be URL encoded.
377+
// Since UTF-8 is always shorter than URI, the same memory is used for decoding
378+
// e.g. Born%20On%20The%20B.mp3 --> Born On The B.mp3
379+
// e.g. %D0%B8%D1%81%D0%BF%D1%8B%D1%82%D0%B0%D0%BD%D0%B8%D0%B5.mp3 --> испытание.mp3
380+
void urldecode(char *str){
381+
uint16_t p1 = 0, p2 = 0;
382+
char a, b;
383+
while (str[p1]) {
384+
if ((str[p1] == '%') && ((a = str[p1 + 1]) && (b = str[p1 + 2])) && (isxdigit(a) && isxdigit(b))) {
385+
if (a >= 'a')
386+
a -= 'a'-'A';
387+
if (a >= 'A')
388+
a -= ('A' - 10);
389+
else
390+
a -= '0';
391+
if (b >= 'a')
392+
b -= 'a'-'A';
393+
if (b >= 'A')
394+
b -= ('A' - 10);
395+
else
396+
b -= '0';
397+
str[p2++] = 16*a+b;
398+
p1+=3;
399+
} else if (str[p1] == '+') {
400+
str[p2++] = ' ';
401+
p1++;
402+
} else {
403+
str[p2++] = str[p1++];
423404
}
424405
}
425-
_chbuf[j] = 0;
426-
return _chbuf;
406+
str[p2++] = '\0';
427407
}
408+
428409
/***********************************************************************************************************************
429410
* T I M E R *
430411
***********************************************************************************************************************/
@@ -681,7 +662,7 @@ void showLogoAndStationName(){
681662
}
682663
display_info(SN_utf8.c_str(), _winName.x, _winName.y, TFT_CYAN, 10, _winName.h);
683664

684-
String logo = "/logo/" + String(UTF8toASCII(SN_ascii.c_str())) +".jpg";
665+
String logo = "/logo/" + (String) SN_ascii.c_str() +".jpg";
685666
if(drawImage(logo.c_str(), 0, _winName.y + 2) == false){
686667
drawImage("/common/unknown.jpg", 0, _winName.y + 2); // if no draw unknown
687668
}
@@ -1209,6 +1190,23 @@ const char* byte_to_binary(int8_t x){
12091190
}
12101191
return b;
12111192
}
1193+
void trim(char *s) {
1194+
//fb trim in place
1195+
char *pe;
1196+
char *p = s;
1197+
while ( isspace(*p) ) p++; //left
1198+
pe = p; //right
1199+
while ( *pe != '\0' ) pe++;
1200+
do {
1201+
pe--;
1202+
} while ( (pe > p) && isspace(*pe) );
1203+
if (p == s) {
1204+
*++pe = '\0';
1205+
} else { //move
1206+
while ( p <= pe ) *s++ = *p++;
1207+
*s = '\0';
1208+
}
1209+
}
12121210
bool startsWith (const char* base, const char* str) {
12131211
char c;
12141212
while ( (c = *str++) != '\0' )
@@ -1263,7 +1261,7 @@ void SerialPrintflnCut(const char* item, const char* color, const char* str){
12631261

12641262
const char* scaleImage(const char* path){
12651263
if((!endsWith(path, "bmp")) && (!endsWith(path, "jpg"))){ // not a image
1266-
return UTF8toASCII(path);
1264+
return path;
12671265
}
12681266
static char pathBuff[256];
12691267
memset(pathBuff, 0, sizeof(pathBuff));
@@ -1280,7 +1278,7 @@ const char* scaleImage(const char* path){
12801278
else strcat(pathBuff, _prefix); // medium pic, 480x320px
12811279
strcat(pathBuff, path);
12821280
}
1283-
return UTF8toASCII(pathBuff);
1281+
return pathBuff;
12841282
}
12851283
inline uint8_t getvolume(){
12861284
return pref.getUShort("volume");
@@ -1414,7 +1412,7 @@ void savefile(const char* fileName, uint32_t contentLength){ //save the uploadfi
14141412
strcat(fn, _prefix);
14151413
if(!startsWith(fileName, "/")) strcat(fn, "/");
14161414
strcat(fn, fileName);
1417-
if(webSrv.uploadB64image(SD_MMC, UTF8toASCII(fn), contentLength)){
1415+
if(webSrv.uploadB64image(SD_MMC, fn, contentLength)){
14181416
SerialPrintfln("save image " ANSI_ESC_CYAN "%s" ANSI_ESC_WHITE " to SD card was successfully", fn);
14191417
webSrv.reply("OK");
14201418
}
@@ -1428,7 +1426,7 @@ void savefile(const char* fileName, uint32_t contentLength){ //save the uploadfi
14281426
else{
14291427
strcpy(fn, fileName);
14301428
}
1431-
if(webSrv.uploadfile(SD_MMC, UTF8toASCII(fn), contentLength)){
1429+
if(webSrv.uploadfile(SD_MMC, fn, contentLength)){
14321430
SerialPrintfln("save file " ANSI_ESC_CYAN "%s" ANSI_ESC_WHITE " to SD card was successfully", fn);
14331431
webSrv.reply("OK");
14341432
}
@@ -1486,16 +1484,16 @@ void audiotrack(const char* fileName, uint32_t resumeFilePos){
14861484
}
14871485

14881486
void processPlaylist(boolean first){
1489-
String f = "";
14901487
String t = "";
14911488
_playlistTime = millis();
14921489
while(playlistFile.available() > 0){
1493-
f = playlistFile.readStringUntil('\n');
1494-
if(f.length() < 5) continue; // line is # or space or nothing, smallest filename "1.mp3" < 5
1495-
if(f.startsWith("#")) SerialPrintfln("Playlist: " ANSI_ESC_GREEN "%s", f.c_str());
1496-
f.trim();
1490+
size_t bytesRead = playlistFile.readBytesUntil('\n', _chbuf, 512);
1491+
_chbuf[bytesRead] = '\0';
1492+
if(bytesRead < 5) continue; // line is # or space or nothing, smallest filename "1.mp3" < 5
1493+
if(startsWith(_chbuf, "#"))SerialPrintfln("Playlist: " ANSI_ESC_GREEN "%s", _chbuf);
1494+
trim(_chbuf);
14971495
if(first){
1498-
if(f.startsWith("#EXTM3U")){
1496+
if(startsWith(_chbuf, "#EXTM3U")){
14991497
first = false;
15001498
_f_playlistEnabled = true;
15011499
continue;
@@ -1506,34 +1504,35 @@ void processPlaylist(boolean first){
15061504
return;
15071505
}
15081506
}
1509-
if(f.startsWith("#EXTINF")){
1510-
int8_t idx = f.indexOf(",");
1507+
if(startsWith(_chbuf, "#EXTINF")){
1508+
int8_t idx = indexOf(",", _chbuf, 0);
15111509
if(idx > 8){
1512-
t = f.substring(idx + 1);
1510+
t = _chbuf[idx + 1];
15131511
t.trim();
15141512
}
15151513
continue;
15161514
}
1517-
if(!f.startsWith("#")){
1518-
if(f.startsWith("http")){
1519-
SerialPrintflnCut("Playlist: ", ANSI_ESC_YELLOW, f.c_str());
1515+
if(!startsWith(_chbuf, "#")){
1516+
if(startsWith(_chbuf, "http")){
1517+
SerialPrintflnCut("Playlist: ", ANSI_ESC_YELLOW, _chbuf);
15201518
clearFName();
15211519
showVolumeBar();
15221520
if(t.length() > 0){
15231521
showFileName(t.c_str());
15241522
webSrv.send("audiotrack=" + t);
15251523
}
15261524
else{
1527-
showFileName(f.c_str());
1528-
webSrv.send("audiotrack=" + f);
1525+
showFileName(_chbuf);
1526+
webSrv.send((String)"audiotrack=" + _chbuf);
15291527
}
15301528
changeState(PLAYERico);
1531-
audioConnecttohost(f.c_str());
1529+
audioConnecttohost(_chbuf);
15321530
}
15331531
else{
1534-
SerialPrintfln("Playlist: " ANSI_ESC_YELLOW "%s", f.c_str());
1535-
webSrv.send("audiotrack=" + f);
1536-
audiotrack(f.c_str());
1532+
urldecode(_chbuf);
1533+
SerialPrintfln("Playlist: " ANSI_ESC_YELLOW "%s", _chbuf);
1534+
webSrv.send((String)"audiotrack=" + _chbuf);
1535+
audiotrack(_chbuf);
15371536
}
15381537
return;
15391538
}
@@ -2374,7 +2373,8 @@ void WEBSRV_onCommand(const String cmd, const String param, const String arg){
23742373

23752374
if(cmd == "change_state"){ changeState(param.toInt()); return;}
23762375

2377-
if(cmd == "stopfile"){ _resumeFilePos = audioStopSong(); webSrv.send("stopfile=audiofile stopped"); return;}
2376+
if(cmd == "stopfile"){ _resumeFilePos = audioStopSong(); webSrv.send("stopfile=audiofile stopped");
2377+
if(playlistFile) playlistFile.close(); return;}
23782378

23792379
if(cmd == "resumefile"){ if(!_lastconnectedfile) webSrv.send("resumefile=nothing to resume");
23802380
else {audiotrack(_lastconnectedfile, _resumeFilePos);

0 commit comments

Comments
 (0)