diff options
Diffstat (limited to 'apps/playlist.c')
-rwxr-xr-x | apps/playlist.c | 237 |
1 files changed, 94 insertions, 143 deletions
diff --git a/apps/playlist.c b/apps/playlist.c index 43aa97790b..db93344ef1 100755 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -86,7 +86,7 @@ | |||
86 | #include "screens.h" | 86 | #include "screens.h" |
87 | #include "core_alloc.h" | 87 | #include "core_alloc.h" |
88 | #include "misc.h" | 88 | #include "misc.h" |
89 | #include "filefuncs.h" | 89 | #include "pathfuncs.h" |
90 | #include "button.h" | 90 | #include "button.h" |
91 | #include "filetree.h" | 91 | #include "filetree.h" |
92 | #include "abrepeat.h" | 92 | #include "abrepeat.h" |
@@ -107,6 +107,8 @@ | |||
107 | #include "panic.h" | 107 | #include "panic.h" |
108 | #include "logdiskf.h" | 108 | #include "logdiskf.h" |
109 | 109 | ||
110 | #undef HAVE_DIRCACHE | ||
111 | |||
110 | #define PLAYLIST_CONTROL_FILE_VERSION 2 | 112 | #define PLAYLIST_CONTROL_FILE_VERSION 2 |
111 | 113 | ||
112 | /* | 114 | /* |
@@ -180,8 +182,8 @@ static int get_next_directory(char *dir); | |||
180 | static int get_next_dir(char *dir, bool is_forward); | 182 | static int get_next_dir(char *dir, bool is_forward); |
181 | static int get_previous_directory(char *dir); | 183 | static int get_previous_directory(char *dir); |
182 | static int check_subdir_for_music(char *dir, const char *subdir, bool recurse); | 184 | static int check_subdir_for_music(char *dir, const char *subdir, bool recurse); |
183 | static int format_track_path(char *dest, char *src, int buf_length, int max, | 185 | static ssize_t format_track_path(char *dest, char *src, int buf_length, |
184 | const char *dir); | 186 | const char *dir); |
185 | static void display_playlist_count(int count, const unsigned char *fmt, | 187 | static void display_playlist_count(int count, const unsigned char *fmt, |
186 | bool final); | 188 | bool final); |
187 | static void display_buffer_full(void); | 189 | static void display_buffer_full(void); |
@@ -526,7 +528,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist, | |||
526 | int result = 0; | 528 | int result = 0; |
527 | /* get emergency buffer so we don't fail horribly */ | 529 | /* get emergency buffer so we don't fail horribly */ |
528 | if (!buflen) | 530 | if (!buflen) |
529 | buffer = __builtin_alloca((buflen = 64)); | 531 | buffer = alloca((buflen = 64)); |
530 | 532 | ||
531 | if(-1 == playlist->fd) | 533 | if(-1 == playlist->fd) |
532 | playlist->fd = open_utf8(playlist->filename, O_RDONLY); | 534 | playlist->fd = open_utf8(playlist->filename, O_RDONLY); |
@@ -1429,7 +1431,7 @@ static int get_filename(struct playlist_info* playlist, int index, int seek, | |||
1429 | 1431 | ||
1430 | strlcpy(dir_buf, playlist->filename, playlist->dirlen); | 1432 | strlcpy(dir_buf, playlist->filename, playlist->dirlen); |
1431 | 1433 | ||
1432 | return (format_track_path(buf, tmp_buf, buf_length, max, dir_buf)); | 1434 | return format_track_path(buf, tmp_buf, buf_length, dir_buf); |
1433 | } | 1435 | } |
1434 | 1436 | ||
1435 | static int get_next_directory(char *dir){ | 1437 | static int get_next_directory(char *dir){ |
@@ -1629,7 +1631,7 @@ static int get_next_dir(char *dir, bool is_forward) | |||
1629 | static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) | 1631 | static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) |
1630 | { | 1632 | { |
1631 | int result = -1; | 1633 | int result = -1; |
1632 | int dirlen = strlen(dir); | 1634 | size_t dirlen = strlen(dir); |
1633 | int num_files = 0; | 1635 | int num_files = 0; |
1634 | int i; | 1636 | int i; |
1635 | struct entry *files; | 1637 | struct entry *files; |
@@ -1637,12 +1639,11 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) | |||
1637 | bool has_subdir = false; | 1639 | bool has_subdir = false; |
1638 | struct tree_context* tc = tree_get_context(); | 1640 | struct tree_context* tc = tree_get_context(); |
1639 | 1641 | ||
1640 | snprintf( | 1642 | if (path_append(dir + dirlen, PA_SEP_HARD, subdir, MAX_PATH - dirlen) >= |
1641 | dir + dirlen, MAX_PATH - dirlen, | 1643 | MAX_PATH - dirlen) |
1642 | /* only add a trailing slash if we need one */ | 1644 | { |
1643 | dirlen && dir[dirlen - 1] == '/' ? "%s" : "/%s", | 1645 | return 0; |
1644 | subdir | 1646 | } |
1645 | ); | ||
1646 | 1647 | ||
1647 | if (ft_load(tc, dir) < 0) | 1648 | if (ft_load(tc, dir) < 0) |
1648 | { | 1649 | { |
@@ -1695,7 +1696,7 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) | |||
1695 | } | 1696 | } |
1696 | else | 1697 | else |
1697 | { | 1698 | { |
1698 | strcpy(dir, "/"); | 1699 | strcpy(dir, PATH_ROOTSTR); |
1699 | } | 1700 | } |
1700 | 1701 | ||
1701 | /* we now need to reload our current directory */ | 1702 | /* we now need to reload our current directory */ |
@@ -1708,79 +1709,31 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) | |||
1708 | /* | 1709 | /* |
1709 | * Returns absolute path of track | 1710 | * Returns absolute path of track |
1710 | */ | 1711 | */ |
1711 | static int format_track_path(char *dest, char *src, int buf_length, int max, | 1712 | static ssize_t format_track_path(char *dest, char *src, int buf_length, |
1712 | const char *dir) | 1713 | const char *dir) |
1713 | { | 1714 | { |
1714 | int i = 0; | 1715 | size_t len; |
1715 | int j; | ||
1716 | char *temp_ptr; | ||
1717 | |||
1718 | /* Look for the end of the string */ | ||
1719 | while((i < max) && | ||
1720 | (src[i] != '\n') && | ||
1721 | (src[i] != '\r') && | ||
1722 | (src[i] != '\0')) | ||
1723 | i++; | ||
1724 | |||
1725 | /* Now work back killing white space */ | ||
1726 | while((i > 0) && | ||
1727 | ((src[i-1] == ' ') || | ||
1728 | (src[i-1] == '\t'))) | ||
1729 | i--; | ||
1730 | 1716 | ||
1731 | /* Zero-terminate the file name */ | 1717 | /* strip whitespace at beginning and end */ |
1732 | src[i]=0; | 1718 | len = path_trim_whitespace(src, (const char **)&src); |
1719 | src[len] = '\0'; | ||
1733 | 1720 | ||
1734 | /* replace backslashes with forward slashes */ | 1721 | /* replace backslashes with forward slashes */ |
1735 | for ( j=0; j<i; j++ ) | 1722 | path_correct_separators(src, src); |
1736 | if ( src[j] == '\\' ) | ||
1737 | src[j] = '/'; | ||
1738 | 1723 | ||
1739 | if('/' == src[0]) | 1724 | /* handle DOS style drive letter and parse non-greedily so that: |
1740 | { | 1725 | * 1) "c:/foo" becomes "/foo" and the result is absolute |
1741 | strlcpy(dest, src, buf_length); | 1726 | * 2) "c:foo becomes "foo" and the result is relative |
1742 | } | 1727 | * This is how Windows seems to handle it except drive letters are of no |
1743 | else | 1728 | * meaning here. */ |
1744 | { | 1729 | path_strip_drive(src, (const char **)&src, false); |
1745 | /* handle dos style drive letter */ | ||
1746 | if (':' == src[1]) | ||
1747 | strlcpy(dest, &src[2], buf_length); | ||
1748 | else if (!strncmp(src, "../", 3)) | ||
1749 | { | ||
1750 | /* handle relative paths */ | ||
1751 | i=3; | ||
1752 | while(!strncmp(&src[i], "../", 3)) | ||
1753 | i += 3; | ||
1754 | for (j=0; j<i/3; j++) { | ||
1755 | temp_ptr = strrchr(dir, '/'); | ||
1756 | if (temp_ptr) | ||
1757 | *temp_ptr = '\0'; | ||
1758 | else | ||
1759 | break; | ||
1760 | } | ||
1761 | snprintf(dest, buf_length, "%s/%s", dir, &src[i]); | ||
1762 | } | ||
1763 | else if ( '.' == src[0] && '/' == src[1] ) { | ||
1764 | snprintf(dest, buf_length, "%s/%s", dir, &src[2]); | ||
1765 | } | ||
1766 | else { | ||
1767 | snprintf(dest, buf_length, "%s/%s", dir, src); | ||
1768 | } | ||
1769 | } | ||
1770 | #ifdef HAVE_MULTIVOLUME | ||
1771 | 1730 | ||
1772 | char vol_string[VOL_ENUM_POS + 8]; | 1731 | /* prepends directory only if src is relative */ |
1773 | snprintf(vol_string, sizeof(vol_string), "/"VOL_NAMES, 1); | 1732 | len = path_append(dest, *dir ? dir : PATH_ROOTSTR, src, buf_length); |
1733 | if (len >= (size_t)buf_length) | ||
1734 | return -1; /* buffer too small */ | ||
1774 | 1735 | ||
1775 | /*check if the playlist is on a external card, and correct path if needed */ | 1736 | return len; |
1776 | if(strstr(dir, vol_string) && (strstr(dest, vol_string) == NULL)){ | ||
1777 | char temp[buf_length]; | ||
1778 | strlcpy(temp, dest, buf_length); | ||
1779 | snprintf(dest, buf_length, "%s%s", vol_string, temp); | ||
1780 | } | ||
1781 | #endif | ||
1782 | |||
1783 | return 0; | ||
1784 | } | 1737 | } |
1785 | 1738 | ||
1786 | /* | 1739 | /* |
@@ -3113,8 +3066,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
3113 | { | 3066 | { |
3114 | int fd; | 3067 | int fd; |
3115 | int max; | 3068 | int max; |
3116 | char *temp_ptr; | 3069 | char *dir; |
3117 | const char *dir; | ||
3118 | unsigned char *count_str; | 3070 | unsigned char *count_str; |
3119 | char temp_buf[MAX_PATH+1]; | 3071 | char temp_buf[MAX_PATH+1]; |
3120 | char trackname[MAX_PATH+1]; | 3072 | char trackname[MAX_PATH+1]; |
@@ -3139,13 +3091,8 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
3139 | } | 3091 | } |
3140 | 3092 | ||
3141 | /* we need the directory name for formatting purposes */ | 3093 | /* we need the directory name for formatting purposes */ |
3142 | dir = filename; | 3094 | size_t dirlen = path_dirname(filename, (const char **)&dir); |
3143 | 3095 | dir = strmemdupa(dir, dirlen); | |
3144 | temp_ptr = strrchr(filename+1,'/'); | ||
3145 | if (temp_ptr) | ||
3146 | *temp_ptr = 0; | ||
3147 | else | ||
3148 | dir = "/"; | ||
3149 | 3096 | ||
3150 | if (queue) | 3097 | if (queue) |
3151 | count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT); | 3098 | count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT); |
@@ -3183,8 +3130,8 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
3183 | 3130 | ||
3184 | /* we need to format so that relative paths are correctly | 3131 | /* we need to format so that relative paths are correctly |
3185 | handled */ | 3132 | handled */ |
3186 | if (format_track_path(trackname, temp_buf, sizeof(trackname), max, | 3133 | if (format_track_path(trackname, temp_buf, sizeof(trackname), |
3187 | dir) < 0) | 3134 | dir) < 0) |
3188 | { | 3135 | { |
3189 | result = -1; | 3136 | result = -1; |
3190 | break; | 3137 | break; |
@@ -3223,9 +3170,6 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
3223 | 3170 | ||
3224 | close(fd); | 3171 | close(fd); |
3225 | 3172 | ||
3226 | if (temp_ptr) | ||
3227 | *temp_ptr = '/'; | ||
3228 | |||
3229 | sync_control(playlist, false); | 3173 | sync_control(playlist, false); |
3230 | 3174 | ||
3231 | cpu_boost(false); | 3175 | cpu_boost(false); |
@@ -3537,9 +3481,9 @@ int playlist_save(struct playlist_info* playlist, char *filename, | |||
3537 | char path[MAX_PATH+1]; | 3481 | char path[MAX_PATH+1]; |
3538 | char tmp_buf[MAX_PATH+1]; | 3482 | char tmp_buf[MAX_PATH+1]; |
3539 | int result = 0; | 3483 | int result = 0; |
3540 | bool overwrite_current = false; | ||
3541 | int *seek_buf; | 3484 | int *seek_buf; |
3542 | bool reparse; | 3485 | bool reparse; |
3486 | ssize_t pathlen; | ||
3543 | 3487 | ||
3544 | ALIGN_BUFFER(temp_buffer, temp_buffer_size, sizeof(int)); | 3488 | ALIGN_BUFFER(temp_buffer, temp_buffer_size, sizeof(int)); |
3545 | seek_buf = temp_buffer; | 3489 | seek_buf = temp_buffer; |
@@ -3557,22 +3501,18 @@ int playlist_save(struct playlist_info* playlist, char *filename, | |||
3557 | return -1; | 3501 | return -1; |
3558 | 3502 | ||
3559 | /* use current working directory as base for pathname */ | 3503 | /* use current working directory as base for pathname */ |
3560 | if (format_track_path(path, filename, sizeof(tmp_buf), | 3504 | pathlen = format_track_path(path, filename, sizeof(path), PATH_ROOTSTR); |
3561 | strlen(filename)+1, "/") < 0) | 3505 | if (pathlen < 0) |
3506 | return -1; | ||
3507 | |||
3508 | /* Use temporary pathname and overwrite/rename later */ | ||
3509 | if (strlcat(path, "_temp", sizeof(path)) >= sizeof (path)) | ||
3562 | return -1; | 3510 | return -1; |
3563 | 3511 | ||
3564 | /* can ignore volatile here, because core_get_data() is called later */ | 3512 | /* can ignore volatile here, because core_get_data() is called later */ |
3565 | char* old_buffer = (char*)playlist->buffer; | 3513 | char* old_buffer = (char*)playlist->buffer; |
3566 | size_t old_buffer_size = playlist->buffer_size; | 3514 | size_t old_buffer_size = playlist->buffer_size; |
3567 | 3515 | ||
3568 | if (!strncmp(playlist->filename, path, strlen(path))) | ||
3569 | { | ||
3570 | /* Attempting to overwrite current playlist file. | ||
3571 | * use temporary pathname and overwrite later */ | ||
3572 | strlcat(path, "_temp", sizeof(path)); | ||
3573 | overwrite_current = true; | ||
3574 | } | ||
3575 | |||
3576 | if (is_m3u8(path)) | 3516 | if (is_m3u8(path)) |
3577 | { | 3517 | { |
3578 | fd = open_utf8(path, O_CREAT|O_WRONLY|O_TRUNC); | 3518 | fd = open_utf8(path, O_CREAT|O_WRONLY|O_TRUNC); |
@@ -3621,8 +3561,8 @@ int playlist_save(struct playlist_info* playlist, char *filename, | |||
3621 | break; | 3561 | break; |
3622 | } | 3562 | } |
3623 | 3563 | ||
3624 | if (overwrite_current && !reparse) | 3564 | if (!reparse) |
3625 | seek_buf[count] = lseek(fd, 0, SEEK_CUR); | 3565 | seek_buf[count] = filesize(fd); |
3626 | 3566 | ||
3627 | if (fdprintf(fd, "%s\n", tmp_buf) < 0) | 3567 | if (fdprintf(fd, "%s\n", tmp_buf) < 0) |
3628 | { | 3568 | { |
@@ -3647,57 +3587,61 @@ int playlist_save(struct playlist_info* playlist, char *filename, | |||
3647 | index = (index+1)%playlist->amount; | 3587 | index = (index+1)%playlist->amount; |
3648 | } | 3588 | } |
3649 | 3589 | ||
3650 | display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true); | ||
3651 | |||
3652 | close(fd); | 3590 | close(fd); |
3591 | fd = -1; | ||
3653 | 3592 | ||
3654 | if (overwrite_current && result >= 0) | 3593 | display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true); |
3594 | |||
3595 | if (result >= 0) | ||
3655 | { | 3596 | { |
3656 | result = -1; | 3597 | strmemcpy(tmp_buf, path, pathlen); /* remove "_temp" */ |
3657 | 3598 | ||
3658 | mutex_lock(playlist->control_mutex); | 3599 | mutex_lock(playlist->control_mutex); |
3659 | 3600 | ||
3660 | /* Replace the current playlist with the new one and update indices */ | 3601 | if (!rename(path, tmp_buf)) |
3661 | close(playlist->fd); | ||
3662 | playlist->fd = -1; | ||
3663 | if (remove(playlist->filename) >= 0) | ||
3664 | { | 3602 | { |
3665 | if (rename(path, playlist->filename) >= 0) | 3603 | fd = open_utf8(tmp_buf, O_RDONLY); |
3604 | if (fsamefile(fd, playlist->fd) > 0) | ||
3666 | { | 3605 | { |
3667 | playlist->fd = open_utf8(playlist->filename, O_RDONLY); | 3606 | /* Replace the current playlist with the new one and update |
3668 | if (playlist->fd >= 0) | 3607 | indices */ |
3608 | close(playlist->fd); | ||
3609 | playlist->fd = fd; | ||
3610 | fd = -1; | ||
3611 | |||
3612 | if (!reparse) | ||
3669 | { | 3613 | { |
3670 | if (!reparse) | 3614 | index = playlist->first_index; |
3615 | for (i=0, count=0; i<playlist->amount; i++) | ||
3671 | { | 3616 | { |
3672 | index = playlist->first_index; | 3617 | if (!(playlist->indices[index] & PLAYLIST_QUEUE_MASK)) |
3673 | for (i=0, count=0; i<playlist->amount; i++) | ||
3674 | { | 3618 | { |
3675 | if (!(playlist->indices[index] & PLAYLIST_QUEUE_MASK)) | 3619 | playlist->indices[index] = seek_buf[count]; |
3676 | { | 3620 | count++; |
3677 | playlist->indices[index] = seek_buf[count]; | ||
3678 | count++; | ||
3679 | } | ||
3680 | index = (index+1)%playlist->amount; | ||
3681 | } | 3621 | } |
3622 | index = (index+1)%playlist->amount; | ||
3682 | } | 3623 | } |
3683 | else | ||
3684 | { | ||
3685 | NOTEF("reparsing current playlist (slow)"); | ||
3686 | playlist->amount = 0; | ||
3687 | add_indices_to_playlist(playlist, temp_buffer, temp_buffer_size); | ||
3688 | } | ||
3689 | /* we need to recreate control because inserted tracks are | ||
3690 | now part of the playlist and shuffle has been | ||
3691 | invalidated */ | ||
3692 | result = recreate_control(playlist); | ||
3693 | } | 3624 | } |
3694 | } | 3625 | else |
3695 | } | 3626 | { |
3627 | NOTEF("reparsing current playlist (slow)"); | ||
3628 | playlist->amount = 0; | ||
3629 | add_indices_to_playlist(playlist, temp_buffer, | ||
3630 | temp_buffer_size); | ||
3631 | } | ||
3696 | 3632 | ||
3697 | mutex_unlock(playlist->control_mutex); | 3633 | /* we need to recreate control because inserted tracks are |
3634 | now part of the playlist and shuffle has been invalidated */ | ||
3635 | result = recreate_control(playlist); | ||
3636 | } | ||
3637 | } | ||
3698 | 3638 | ||
3639 | mutex_unlock(playlist->control_mutex); | ||
3699 | } | 3640 | } |
3700 | 3641 | ||
3642 | if (fd >= 0) | ||
3643 | close(fd); | ||
3644 | |||
3701 | cpu_boost(false); | 3645 | cpu_boost(false); |
3702 | 3646 | ||
3703 | reset_old_buffer: | 3647 | reset_old_buffer: |
@@ -3759,8 +3703,12 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse, | |||
3759 | if (recurse) | 3703 | if (recurse) |
3760 | { | 3704 | { |
3761 | /* recursively add directories */ | 3705 | /* recursively add directories */ |
3762 | snprintf(buf, sizeof(buf), "%s/%s", | 3706 | if (path_append(buf, dirname, files[i].name, sizeof(buf)) |
3763 | dirname[1]? dirname: "", files[i].name); | 3707 | >= sizeof(buf)) |
3708 | { | ||
3709 | continue; | ||
3710 | } | ||
3711 | |||
3764 | result = playlist_directory_tracksearch(buf, recurse, | 3712 | result = playlist_directory_tracksearch(buf, recurse, |
3765 | callback, context); | 3713 | callback, context); |
3766 | if (result < 0) | 3714 | if (result < 0) |
@@ -3785,8 +3733,11 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse, | |||
3785 | } | 3733 | } |
3786 | else if ((files[i].attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO) | 3734 | else if ((files[i].attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO) |
3787 | { | 3735 | { |
3788 | snprintf(buf, sizeof(buf), "%s/%s", | 3736 | if (path_append(buf, dirname, files[i].name, sizeof(buf)) |
3789 | dirname[1]? dirname: "", files[i].name); | 3737 | >= sizeof(buf)) |
3738 | { | ||
3739 | continue; | ||
3740 | } | ||
3790 | 3741 | ||
3791 | if (callback(buf, context) != 0) | 3742 | if (callback(buf, context) != 0) |
3792 | { | 3743 | { |