diff options
author | Magnus Holmgren <magnushol@gmail.com> | 2007-11-13 18:49:20 +0000 |
---|---|---|
committer | Magnus Holmgren <magnushol@gmail.com> | 2007-11-13 18:49:20 +0000 |
commit | 6e06825fa09b0a8bb0f92ffe4c14ac81e9a4b28b (patch) | |
tree | d8928afbe225aa053f698ef6b092bfd914fedfb2 | |
parent | b8ddc61386c87b2e412a23c6d0546c3f58c5394e (diff) | |
download | rockbox-6e06825fa09b0a8bb0f92ffe4c14ac81e9a4b28b.tar.gz rockbox-6e06825fa09b0a8bb0f92ffe4c14ac81e9a4b28b.zip |
Improve insert of playlists. Decode M3U files using current code page and strip any BOM. Also remove a few tabs.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15608 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/playlist.c | 125 |
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)]; | |||
198 | static const char playlist_thread_name[] = "playlist cachectrl"; | 198 | static 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. */ | ||
205 | static 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. */ | ||
214 | static 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 | */ | ||
229 | static 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 = ¤t_playlist; | 2986 | playlist = ¤t_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 */ |