summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/playlist.c125
1 files changed, 91 insertions, 34 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index 676fc1e2c7..644329c5bf 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -198,6 +198,68 @@ static long playlist_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)];
198static const char playlist_thread_name[] = "playlist cachectrl"; 198static const char playlist_thread_name[] = "playlist cachectrl";
199#endif 199#endif
200 200
201#define BOM "\xef\xbb\xbf"
202#define BOM_SIZE 3
203
204/* Check if the filename suggests M3U or M3U8 format. */
205static bool is_m3u8(const char* filename)
206{
207 int len = strlen(filename);
208
209 /* Default to M3U8 unless explicitly told otherwise. */
210 return !(len > 4 && strcasecmp(&filename[len - 4], ".m3u") == 0);
211}
212
213/* Check if a strings starts with an UTF-8 byte-order mark. */
214static bool is_utf8_bom(const char* str, int len)
215{
216 return len >= BOM_SIZE && memcmp(str, BOM, BOM_SIZE) == 0;
217}
218
219/* Convert a filename in an M3U playlist to UTF-8.
220 *
221 * buf - the filename to convert; can contain more than one line from the
222 * playlist.
223 * buf_len - amount of buf that is used.
224 * buf_max - total size of buf.
225 * temp - temporary conversion buffer, at least buf_max bytes.
226 *
227 * Returns the length of the converted filename.
228 */
229static int convert_m3u(char* buf, int buf_len, int buf_max, char* temp)
230{
231 int i = 0;
232 char* dest;
233
234 /* Locate EOL. */
235 while ((buf[i] != '\n') && (buf[i] != '\r') && (i < buf_len))
236 {
237 i++;
238 }
239
240 /* Work back killing white space. */
241 while ((i > 0) && isspace(buf[i - 1]))
242 {
243 i--;
244 }
245
246 buf_len = i;
247 dest = temp;
248
249 /* Convert char by char, so as to not overflow temp (iso_decode should
250 * preferably handle this). No more than 4 bytes should be generated for
251 * each input char.
252 */
253 for (i = 0; i < buf_len && dest < (temp + buf_max - 4); i++)
254 {
255 dest = iso_decode(&buf[i], dest, -1, 1);
256 }
257
258 *dest = 0;
259 strcpy(buf, temp);
260 return dest - temp;
261}
262
201/* 263/*
202 * remove any files and indices associated with the playlist 264 * remove any files and indices associated with the playlist
203 */ 265 */
@@ -441,10 +503,8 @@ static void update_playlist_filename(struct playlist_info* playlist,
441{ 503{
442 char *sep=""; 504 char *sep="";
443 int dirlen = strlen(dir); 505 int dirlen = strlen(dir);
444 int filelen = strlen(file);
445 506
446 /* Default to utf8 unless explicitly told otherwise. */ 507 playlist->utf8 = is_m3u8(file);
447 playlist->utf8 = !(filelen > 4 && strcasecmp(&file[filelen - 4], ".m3u") == 0);
448 508
449 /* If the dir does not end in trailing slash, we use a separator. 509 /* If the dir does not end in trailing slash, we use a separator.
450 Otherwise we don't. */ 510 Otherwise we don't. */
@@ -511,11 +571,10 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
511 p = (unsigned char *)buffer; 571 p = (unsigned char *)buffer;
512 572
513 /* utf8 BOM at beginning of file? */ 573 /* utf8 BOM at beginning of file? */
514 if(i == 0 && nread > 3 574 if(i == 0 && is_utf8_bom(p, nread)) {
515 && *p == 0xef && *(p+1) == 0xbb && *(p+2) == 0xbf) { 575 nread -= BOM_SIZE;
516 nread -= 3; 576 p += BOM_SIZE;
517 p += 3; 577 i += BOM_SIZE;
518 i += 3;
519 playlist->utf8 = true; /* Override any earlier indication. */ 578 playlist->utf8 = true; /* Override any earlier indication. */
520 } 579 }
521 580
@@ -1308,6 +1367,7 @@ static int get_filename(struct playlist_info* playlist, int index, int seek,
1308 int max = -1; 1367 int max = -1;
1309 char tmp_buf[MAX_PATH+1]; 1368 char tmp_buf[MAX_PATH+1];
1310 char dir_buf[MAX_PATH+1]; 1369 char dir_buf[MAX_PATH+1];
1370 bool utf8 = playlist->utf8;
1311 1371
1312 if (buf_length > MAX_PATH+1) 1372 if (buf_length > MAX_PATH+1)
1313 buf_length = MAX_PATH+1; 1373 buf_length = MAX_PATH+1;
@@ -1336,7 +1396,10 @@ static int get_filename(struct playlist_info* playlist, int index, int seek,
1336 mutex_lock(&playlist->control_mutex); 1396 mutex_lock(&playlist->control_mutex);
1337 1397
1338 if (control_file) 1398 if (control_file)
1399 {
1339 fd = playlist->control_fd; 1400 fd = playlist->control_fd;
1401 utf8 = true;
1402 }
1340 else 1403 else
1341 { 1404 {
1342 if(-1 == playlist->fd) 1405 if(-1 == playlist->fd)
@@ -1354,33 +1417,12 @@ static int get_filename(struct playlist_info* playlist, int index, int seek,
1354 { 1417 {
1355 max = read(fd, tmp_buf, MIN((size_t) buf_length, sizeof(tmp_buf))); 1418 max = read(fd, tmp_buf, MIN((size_t) buf_length, sizeof(tmp_buf)));
1356 1419
1357 if ((max > 0) && !playlist->utf8) 1420 if ((max > 0) && !utf8)
1358 { 1421 {
1359 char* end; 1422 /* Use dir_buf as a temporary buffer. Note that dir_buf must
1360 int i = 0; 1423 * be as large as tmp_buf.
1361
1362 /* Locate EOL. */
1363 while ((tmp_buf[i] != '\n') && (tmp_buf[i] != '\r')
1364 && (i < max))
1365 {
1366 i++;
1367 }
1368
1369 /* Now work back killing white space. */
1370 while ((i > 0) && isspace(tmp_buf[i - 1]))
1371 {
1372 i--;
1373 }
1374
1375 /* Borrow dir_buf a little... */
1376 /* TODO: iso_decode can overflow dir_buf; it really
1377 * should take a dest size argument.
1378 */ 1424 */
1379 end = iso_decode(tmp_buf, dir_buf, -1, i); 1425 max = convert_m3u(tmp_buf, max, sizeof(tmp_buf), dir_buf);
1380 *end = 0;
1381 strncpy(tmp_buf, dir_buf, sizeof(tmp_buf));
1382 tmp_buf[sizeof(tmp_buf) - 1] = 0;
1383 max = strlen(tmp_buf);
1384 } 1426 }
1385 } 1427 }
1386 } 1428 }
@@ -1928,7 +1970,7 @@ void playlist_init(void)
1928 playlist->max_playlist_size * sizeof(int)); 1970 playlist->max_playlist_size * sizeof(int));
1929 create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), 1971 create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack),
1930 0, playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND) 1972 0, playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
1931 IF_COP(, CPU)); 1973 IF_COP(, CPU));
1932 queue_init(&playlist_queue, true); 1974 queue_init(&playlist_queue, true);
1933#endif 1975#endif
1934} 1976}
@@ -2938,6 +2980,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename,
2938 char trackname[MAX_PATH+1]; 2980 char trackname[MAX_PATH+1];
2939 int count = 0; 2981 int count = 0;
2940 int result = 0; 2982 int result = 0;
2983 bool utf8 = is_m3u8(filename);
2941 2984
2942 if (!playlist) 2985 if (!playlist)
2943 playlist = &current_playlist; 2986 playlist = &current_playlist;
@@ -2985,10 +3028,24 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename,
2985 /* user abort */ 3028 /* user abort */
2986 if (action_userabort(TIMEOUT_NOBLOCK)) 3029 if (action_userabort(TIMEOUT_NOBLOCK))
2987 break; 3030 break;
3031
3032 if (count == 0 && is_utf8_bom(temp_buf, max))
3033 {
3034 max -= BOM_SIZE;
3035 memmove(temp_buf, temp_buf + BOM_SIZE, max);
3036 }
2988 3037
2989 if (temp_buf[0] != '#' && temp_buf[0] != '\0') 3038 if (temp_buf[0] != '#' && temp_buf[0] != '\0')
2990 { 3039 {
2991 int insert_pos; 3040 int insert_pos;
3041
3042 if (!utf8)
3043 {
3044 /* Use trackname as a temporay buffer. Note that trackname must
3045 * be as large as temp_buf.
3046 */
3047 max = convert_m3u(temp_buf, max, sizeof(temp_buf), trackname);
3048 }
2992 3049
2993 /* we need to format so that relative paths are correctly 3050 /* we need to format so that relative paths are correctly
2994 handled */ 3051 handled */