diff options
author | William Wilgus <wilgus.william@gmail.com> | 2023-11-06 17:22:36 -0500 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2023-11-09 21:03:25 -0500 |
commit | 7ac4d34dd61547db97712dc608c9eb19c9a42e3c (patch) | |
tree | 1fb4bf7e2be5c7b281958654d8c6ccee31db615a | |
parent | 7f455af9053894241291f094865aee8808a1d3df (diff) | |
download | rockbox-7ac4d34dd61547db97712dc608c9eb19c9a42e3c.tar.gz rockbox-7ac4d34dd61547db97712dc608c9eb19c9a42e3c.zip |
Playlist slight optimizations for playlist_resume
Change-Id: I766ce032a9b6b36d750a9231ff9f5d5a0167e5a5
-rw-r--r-- | apps/playlist.c | 287 | ||||
-rw-r--r-- | apps/playlist.h | 3 | ||||
-rw-r--r-- | firmware/common/pathfuncs.c | 29 | ||||
-rw-r--r-- | firmware/export/pathfuncs.h | 2 |
4 files changed, 172 insertions, 149 deletions
diff --git a/apps/playlist.c b/apps/playlist.c index 8c9bfb4a04..bd2d33ea78 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -536,6 +536,7 @@ int update_playlist_flags_unlocked(struct playlist_info *playlist, | |||
536 | * dest: output buffer | 536 | * dest: output buffer |
537 | * src: the file name from the playlist | 537 | * src: the file name from the playlist |
538 | * dir: the absolute path to the directory where the playlist resides | 538 | * dir: the absolute path to the directory where the playlist resides |
539 | * dlen used to truncate dir -- supply -1u to ignore | ||
539 | * | 540 | * |
540 | * The type of path in "src" determines what will be written to "dest": | 541 | * The type of path in "src" determines what will be written to "dest": |
541 | * | 542 | * |
@@ -548,11 +549,10 @@ int update_playlist_flags_unlocked(struct playlist_info *playlist, | |||
548 | * the drive letter is accepted but ignored. | 549 | * the drive letter is accepted but ignored. |
549 | */ | 550 | */ |
550 | static ssize_t format_track_path(char *dest, char *src, int buf_length, | 551 | static ssize_t format_track_path(char *dest, char *src, int buf_length, |
551 | const char *dir) | 552 | const char *dir, size_t dlen) |
552 | { | 553 | { |
553 | /* Look for the end of the string (includes NULL) */ | 554 | /* Look for the end of the string (includes NULL) */ |
554 | size_t len = strcspn(src, "\r\n");; | 555 | size_t len = strcspn(src, "\r\n");; |
555 | |||
556 | /* Now work back killing white space */ | 556 | /* Now work back killing white space */ |
557 | while (len > 0) | 557 | while (len > 0) |
558 | { | 558 | { |
@@ -574,18 +574,25 @@ static ssize_t format_track_path(char *dest, char *src, int buf_length, | |||
574 | #ifdef HAVE_MULTIVOLUME | 574 | #ifdef HAVE_MULTIVOLUME |
575 | const char *p; | 575 | const char *p; |
576 | path_strip_last_volume(dir, &p, false); | 576 | path_strip_last_volume(dir, &p, false); |
577 | dir = strmemdupa(dir, p - dir); /* empty if no volspec on dir */ | 577 | //dir = strmemdupa(dir, p - dir); |
578 | dlen = (p-dir); /* empty if no volspec on dir */ | ||
578 | #else | 579 | #else |
579 | dir = ""; /* only volume is root */ | 580 | dir = ""; /* only volume is root */ |
580 | #endif | 581 | #endif |
581 | } | 582 | } |
582 | 583 | ||
583 | len = path_append(dest, *dir ? dir : PATH_ROOTSTR, src, buf_length); | 584 | if (*dir == '\0') |
585 | { | ||
586 | dir = PATH_ROOTSTR; | ||
587 | dlen = -1u; | ||
588 | } | ||
589 | |||
590 | len = path_append_ex(dest, dir, dlen, src, buf_length); | ||
584 | if (len >= (size_t)buf_length) | 591 | if (len >= (size_t)buf_length) |
585 | return -1; /* buffer too small */ | 592 | return -1; /* buffer too small */ |
586 | 593 | ||
587 | path_remove_dot_segments (dest, dest); | 594 | path_remove_dot_segments (dest, dest); |
588 | 595 | logf("%s %s", __func__, dest); | |
589 | return strlen (dest); | 596 | return strlen (dest); |
590 | } | 597 | } |
591 | 598 | ||
@@ -1033,6 +1040,9 @@ static int get_track_filename(struct playlist_info* playlist, int index, | |||
1033 | char dir_buf[MAX_PATH+1]; | 1040 | char dir_buf[MAX_PATH+1]; |
1034 | bool utf8 = playlist->utf8; | 1041 | bool utf8 = playlist->utf8; |
1035 | 1042 | ||
1043 | if (index < 0 || index >= playlist->amount) | ||
1044 | return -1; | ||
1045 | |||
1036 | playlist_write_lock(playlist); | 1046 | playlist_write_lock(playlist); |
1037 | 1047 | ||
1038 | bool control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; | 1048 | bool control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; |
@@ -1102,10 +1112,10 @@ static int get_track_filename(struct playlist_info* playlist, int index, | |||
1102 | } | 1112 | } |
1103 | } | 1113 | } |
1104 | 1114 | ||
1105 | strmemccpy(dir_buf, playlist->filename, playlist->dirlen); | ||
1106 | playlist_write_unlock(playlist); | 1115 | playlist_write_unlock(playlist); |
1107 | 1116 | ||
1108 | if (format_track_path(buf, tmp_buf, buf_length, dir_buf) < 0) | 1117 | if (format_track_path(buf, tmp_buf, buf_length, |
1118 | playlist->filename, playlist->dirlen) < 0) | ||
1109 | return -1; | 1119 | return -1; |
1110 | 1120 | ||
1111 | return 0; | 1121 | return 0; |
@@ -1776,7 +1786,7 @@ static void dc_thread_playlist(void) | |||
1776 | } | 1786 | } |
1777 | 1787 | ||
1778 | /* Load the filename from playlist file. */ | 1788 | /* Load the filename from playlist file. */ |
1779 | if (get_track_filename(playlist, index, tmp, sizeof(tmp))) | 1789 | if (get_track_filename(playlist, index, tmp, sizeof(tmp)) != 0) |
1780 | break; | 1790 | break; |
1781 | 1791 | ||
1782 | /* Obtain the dircache file entry cookie. */ | 1792 | /* Obtain the dircache file entry cookie. */ |
@@ -2217,16 +2227,20 @@ int playlist_get_display_index(void) | |||
2217 | unsigned int playlist_get_filename_crc32(struct playlist_info *playlist, | 2227 | unsigned int playlist_get_filename_crc32(struct playlist_info *playlist, |
2218 | int index) | 2228 | int index) |
2219 | { | 2229 | { |
2220 | struct playlist_track_info track_info; | ||
2221 | if (playlist_get_track_info(playlist, index, &track_info) == -1) | ||
2222 | return -1; | ||
2223 | const char *basename; | 2230 | const char *basename; |
2231 | char filename[MAX_PATH]; /* path name of mp3 file */ | ||
2232 | if (!playlist) | ||
2233 | playlist = ¤t_playlist; | ||
2234 | |||
2235 | if (get_track_filename(playlist, index, filename, sizeof(filename)) != 0) | ||
2236 | return -1; | ||
2237 | |||
2224 | #ifdef HAVE_MULTIVOLUME | 2238 | #ifdef HAVE_MULTIVOLUME |
2225 | /* remove the volume identifier it might change just use the relative part*/ | 2239 | /* remove the volume identifier it might change just use the relative part*/ |
2226 | path_strip_volume(track_info.filename, &basename, false); | 2240 | path_strip_volume(filename, &basename, false); |
2227 | if (basename == NULL) | 2241 | if (basename == NULL) |
2228 | #endif | 2242 | #endif |
2229 | basename = track_info.filename; | 2243 | basename = filename; |
2230 | NOTEF("%s: %s", __func__, basename); | 2244 | NOTEF("%s: %s", __func__, basename); |
2231 | return crc_32(basename, strlen(basename), -1); | 2245 | return crc_32(basename, strlen(basename), -1); |
2232 | } | 2246 | } |
@@ -2298,11 +2312,8 @@ int playlist_get_track_info(struct playlist_info* playlist, int index, | |||
2298 | if (!playlist) | 2312 | if (!playlist) |
2299 | playlist = ¤t_playlist; | 2313 | playlist = ¤t_playlist; |
2300 | 2314 | ||
2301 | if (index < 0 || index >= playlist->amount) | ||
2302 | return -1; | ||
2303 | |||
2304 | if (get_track_filename(playlist, index, | 2315 | if (get_track_filename(playlist, index, |
2305 | info->filename, sizeof(info->filename))) | 2316 | info->filename, sizeof(info->filename)) != 0) |
2306 | return -1; | 2317 | return -1; |
2307 | 2318 | ||
2308 | info->attr = 0; | 2319 | info->attr = 0; |
@@ -2482,7 +2493,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
2482 | 2493 | ||
2483 | /* we need the directory name for formatting purposes */ | 2494 | /* we need the directory name for formatting purposes */ |
2484 | size_t dirlen = path_dirname(filename, (const char **)&dir); | 2495 | size_t dirlen = path_dirname(filename, (const char **)&dir); |
2485 | dir = strmemdupa(dir, dirlen); | 2496 | //dir = strmemdupa(dir, dirlen); |
2486 | 2497 | ||
2487 | while ((max = read_line(fd, temp_buf, sizeof(temp_buf))) > 0) | 2498 | while ((max = read_line(fd, temp_buf, sizeof(temp_buf))) > 0) |
2488 | { | 2499 | { |
@@ -2502,7 +2513,8 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
2502 | 2513 | ||
2503 | /* we need to format so that relative paths are correctly | 2514 | /* we need to format so that relative paths are correctly |
2504 | handled */ | 2515 | handled */ |
2505 | if (format_track_path(trackname, temp_buf, sizeof(trackname), dir) < 0) | 2516 | if (format_track_path(trackname, temp_buf, |
2517 | sizeof(trackname), dir, dirlen) < 0) | ||
2506 | { | 2518 | { |
2507 | goto out; | 2519 | goto out; |
2508 | } | 2520 | } |
@@ -2683,7 +2695,7 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index) | |||
2683 | 2695 | ||
2684 | queue = playlist->indices[index] & PLAYLIST_QUEUED; | 2696 | queue = playlist->indices[index] & PLAYLIST_QUEUED; |
2685 | 2697 | ||
2686 | if (get_track_filename(playlist, index, filename, sizeof(filename))) | 2698 | if (get_track_filename(playlist, index, filename, sizeof(filename)) != 0) |
2687 | goto out; | 2699 | goto out; |
2688 | 2700 | ||
2689 | /* We want to insert the track at the position that was specified by | 2701 | /* We want to insert the track at the position that was specified by |
@@ -2891,9 +2903,8 @@ const char* playlist_peek(int steps, char* buf, size_t buf_size) | |||
2891 | { | 2903 | { |
2892 | struct playlist_info* playlist = ¤t_playlist; | 2904 | struct playlist_info* playlist = ¤t_playlist; |
2893 | char *temp_ptr; | 2905 | char *temp_ptr; |
2894 | int index; | 2906 | int index = get_next_index(playlist, steps, -1); |
2895 | 2907 | ||
2896 | index = get_next_index(playlist, steps, -1); | ||
2897 | if (index < 0) | 2908 | if (index < 0) |
2898 | return NULL; | 2909 | return NULL; |
2899 | 2910 | ||
@@ -2901,7 +2912,7 @@ const char* playlist_peek(int steps, char* buf, size_t buf_size) | |||
2901 | if (!buf || !buf_size) | 2912 | if (!buf || !buf_size) |
2902 | return ""; | 2913 | return ""; |
2903 | 2914 | ||
2904 | if (get_track_filename(playlist, index, buf, buf_size)) | 2915 | if (get_track_filename(playlist, index, buf, buf_size) != 0) |
2905 | return NULL; | 2916 | return NULL; |
2906 | 2917 | ||
2907 | temp_ptr = buf; | 2918 | temp_ptr = buf; |
@@ -2979,6 +2990,48 @@ int playlist_remove_all_tracks(struct playlist_info *playlist) | |||
2979 | return result; | 2990 | return result; |
2980 | } | 2991 | } |
2981 | 2992 | ||
2993 | /* playlist_resume helper function | ||
2994 | * only allows comments (#) and PLAYLIST_COMMAND_PLAYLIST (P) | ||
2995 | */ | ||
2996 | static enum playlist_command pl_cmds_start(char cmd) | ||
2997 | { | ||
2998 | if (cmd == 'P') | ||
2999 | return PLAYLIST_COMMAND_PLAYLIST; | ||
3000 | if (cmd == '#') | ||
3001 | return PLAYLIST_COMMAND_COMMENT; | ||
3002 | |||
3003 | return PLAYLIST_COMMAND_ERROR; | ||
3004 | } | ||
3005 | |||
3006 | /* playlist resume helper function excludes PLAYLIST_COMMAND_PLAYLIST (P) */ | ||
3007 | static enum playlist_command pl_cmds_run(char cmd) | ||
3008 | { | ||
3009 | switch (cmd) | ||
3010 | { | ||
3011 | case 'A': | ||
3012 | return PLAYLIST_COMMAND_ADD; | ||
3013 | case 'Q': | ||
3014 | return PLAYLIST_COMMAND_QUEUE; | ||
3015 | case 'D': | ||
3016 | return PLAYLIST_COMMAND_DELETE; | ||
3017 | case 'S': | ||
3018 | return PLAYLIST_COMMAND_SHUFFLE; | ||
3019 | case 'U': | ||
3020 | return PLAYLIST_COMMAND_UNSHUFFLE; | ||
3021 | case 'R': | ||
3022 | return PLAYLIST_COMMAND_RESET; | ||
3023 | case 'C': | ||
3024 | return PLAYLIST_COMMAND_CLEAR; | ||
3025 | case 'F': | ||
3026 | return PLAYLIST_COMMAND_FLAGS; | ||
3027 | case '#': | ||
3028 | return PLAYLIST_COMMAND_COMMENT; | ||
3029 | default: /* ERROR */ | ||
3030 | break; | ||
3031 | } | ||
3032 | return PLAYLIST_COMMAND_ERROR; | ||
3033 | } | ||
3034 | |||
2982 | /* | 3035 | /* |
2983 | * Restore the playlist state based on control file commands. Called to | 3036 | * Restore the playlist state based on control file commands. Called to |
2984 | * resume playback after shutdown. | 3037 | * resume playback after shutdown. |
@@ -2992,9 +3045,9 @@ int playlist_resume(void) | |||
2992 | int nread; | 3045 | int nread; |
2993 | int total_read = 0; | 3046 | int total_read = 0; |
2994 | int control_file_size = 0; | 3047 | int control_file_size = 0; |
2995 | bool first = true; | ||
2996 | bool sorted = true; | 3048 | bool sorted = true; |
2997 | int result = -1; | 3049 | int result = -1; |
3050 | enum playlist_command (*pl_cmd)(char) = &pl_cmds_start; | ||
2998 | 3051 | ||
2999 | splash(0, ID2P(LANG_WAIT)); | 3052 | splash(0, ID2P(LANG_WAIT)); |
3000 | cpu_boost(true); | 3053 | cpu_boost(true); |
@@ -3060,13 +3113,12 @@ int playlist_resume(void) | |||
3060 | bool newline = true; | 3113 | bool newline = true; |
3061 | bool exit_loop = false; | 3114 | bool exit_loop = false; |
3062 | char *p = buffer; | 3115 | char *p = buffer; |
3063 | char *str1 = NULL; | 3116 | char *strp[3] = {NULL}; |
3064 | char *str2 = NULL; | ||
3065 | char *str3 = NULL; | ||
3066 | 3117 | ||
3067 | unsigned long last_tick = current_tick; | 3118 | unsigned long last_tick = current_tick; |
3068 | splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ | 3119 | splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ |
3069 | bool useraborted = false; | 3120 | bool useraborted = false; |
3121 | bool queue = false; | ||
3070 | 3122 | ||
3071 | for(count=0; count<nread && !exit_loop; count++,p++) | 3123 | for(count=0; count<nread && !exit_loop; count++,p++) |
3072 | { | 3124 | { |
@@ -3090,25 +3142,35 @@ int playlist_resume(void) | |||
3090 | 3142 | ||
3091 | switch (current_command) | 3143 | switch (current_command) |
3092 | { | 3144 | { |
3145 | case PLAYLIST_COMMAND_ERROR: | ||
3146 | { | ||
3147 | /* first non-comment line does not specify playlist */ | ||
3148 | /* ( below handled by pl_cmds_run() ) */ | ||
3149 | /* OR playlist is specified more than once */ | ||
3150 | /* OR unknown command -- pl corrupted?? */ | ||
3151 | result = -12; | ||
3152 | exit_loop = true; | ||
3153 | break; | ||
3154 | } | ||
3093 | case PLAYLIST_COMMAND_PLAYLIST: | 3155 | case PLAYLIST_COMMAND_PLAYLIST: |
3094 | { | 3156 | { |
3095 | /* str1=version str2=dir str3=file */ | 3157 | /* strp[0]=version strp[1]=dir strp[2]=file */ |
3096 | int version; | 3158 | int version; |
3097 | 3159 | ||
3098 | if (!str1) | 3160 | if (!strp[0]) |
3099 | { | 3161 | { |
3100 | result = -2; | 3162 | result = -2; |
3101 | exit_loop = true; | 3163 | exit_loop = true; |
3102 | break; | 3164 | break; |
3103 | } | 3165 | } |
3104 | 3166 | ||
3105 | if (!str2) | 3167 | if (!strp[1]) |
3106 | str2 = ""; | 3168 | strp[1] = ""; |
3107 | 3169 | ||
3108 | if (!str3) | 3170 | if (!strp[2]) |
3109 | str3 = ""; | 3171 | strp[2] = ""; |
3110 | 3172 | ||
3111 | version = atoi(str1); | 3173 | version = atoi(strp[0]); |
3112 | 3174 | ||
3113 | /* | 3175 | /* |
3114 | * TODO: Playlist control file version upgrades | 3176 | * TODO: Playlist control file version upgrades |
@@ -3126,72 +3188,68 @@ int playlist_resume(void) | |||
3126 | goto out; | 3188 | goto out; |
3127 | } | 3189 | } |
3128 | 3190 | ||
3129 | update_playlist_filename_unlocked(playlist, str2, str3); | 3191 | update_playlist_filename_unlocked(playlist, strp[1], strp[2]); |
3130 | 3192 | ||
3131 | if (str3[0] != '\0') | 3193 | if (strp[2][0] != '\0') |
3132 | { | 3194 | { |
3133 | /* NOTE: add_indices_to_playlist() overwrites the | 3195 | /* NOTE: add_indices_to_playlist() overwrites the |
3134 | audiobuf so we need to reload control file | 3196 | audiobuf so we need to reload control file |
3135 | data */ | 3197 | data */ |
3136 | add_indices_to_playlist(playlist, buffer, buflen); | 3198 | add_indices_to_playlist(playlist, buffer, buflen); |
3137 | } | 3199 | } |
3138 | else if (str2[0] != '\0') | 3200 | else if (strp[1][0] != '\0') |
3139 | { | 3201 | { |
3140 | playlist->flags |= PLAYLIST_FLAG_DIRPLAY; | 3202 | playlist->flags |= PLAYLIST_FLAG_DIRPLAY; |
3141 | } | 3203 | } |
3142 | 3204 | ||
3143 | /* load the rest of the data */ | 3205 | /* load the rest of the data */ |
3144 | first = false; | ||
3145 | exit_loop = true; | 3206 | exit_loop = true; |
3146 | readsize = buflen; | 3207 | readsize = buflen; |
3208 | pl_cmd = &pl_cmds_run; | ||
3147 | break; | 3209 | break; |
3148 | } | 3210 | } |
3149 | case PLAYLIST_COMMAND_ADD: | ||
3150 | case PLAYLIST_COMMAND_QUEUE: | 3211 | case PLAYLIST_COMMAND_QUEUE: |
3212 | queue = true; | ||
3213 | /*Fall-through*/ | ||
3214 | case PLAYLIST_COMMAND_ADD: | ||
3151 | { | 3215 | { |
3152 | /* str1=position str2=last_position str3=file */ | 3216 | /* strp[0]=position strp[1]=last_position strp[2]=file */ |
3153 | int position, last_position; | 3217 | if (!strp[0] || !strp[1] || !strp[2]) |
3154 | bool queue; | ||
3155 | |||
3156 | if (!str1 || !str2 || !str3) | ||
3157 | { | 3218 | { |
3158 | result = -4; | 3219 | result = -4; |
3159 | exit_loop = true; | 3220 | exit_loop = true; |
3160 | break; | 3221 | break; |
3161 | } | 3222 | } |
3162 | 3223 | ||
3163 | position = atoi(str1); | 3224 | int position = atoi(strp[0]); |
3164 | last_position = atoi(str2); | 3225 | int last_position = atoi(strp[1]); |
3165 | 3226 | ||
3166 | queue = (current_command == PLAYLIST_COMMAND_ADD)? | 3227 | /* seek position is based on strp[2]'s position in |
3167 | false:true; | ||
3168 | |||
3169 | /* seek position is based on str3's position in | ||
3170 | buffer */ | 3228 | buffer */ |
3171 | if (add_track_to_playlist_unlocked(playlist, str3, | 3229 | if (add_track_to_playlist_unlocked(playlist, strp[2], |
3172 | position, queue, total_read+(str3-buffer)) < 0) | 3230 | position, queue, total_read+(strp[2]-buffer)) < 0) |
3173 | { | 3231 | { |
3174 | result = -5; | 3232 | result = -5; |
3175 | goto out; | 3233 | goto out; |
3176 | } | 3234 | } |
3177 | 3235 | ||
3178 | playlist->last_insert_pos = last_position; | 3236 | playlist->last_insert_pos = last_position; |
3179 | 3237 | queue = false; | |
3180 | break; | 3238 | break; |
3181 | } | 3239 | } |
3182 | case PLAYLIST_COMMAND_DELETE: | 3240 | case PLAYLIST_COMMAND_DELETE: |
3183 | { | 3241 | { |
3184 | /* str1=position */ | 3242 | /* strp[0]=position */ |
3185 | int position; | 3243 | int position; |
3186 | 3244 | ||
3187 | if (!str1) | 3245 | if (!strp[0]) |
3188 | { | 3246 | { |
3189 | result = -6; | 3247 | result = -6; |
3190 | exit_loop = true; | 3248 | exit_loop = true; |
3191 | break; | 3249 | break; |
3192 | } | 3250 | } |
3193 | 3251 | ||
3194 | position = atoi(str1); | 3252 | position = atoi(strp[0]); |
3195 | 3253 | ||
3196 | if (remove_track_unlocked(playlist, position, false) < 0) | 3254 | if (remove_track_unlocked(playlist, position, false) < 0) |
3197 | { | 3255 | { |
@@ -3203,10 +3261,10 @@ int playlist_resume(void) | |||
3203 | } | 3261 | } |
3204 | case PLAYLIST_COMMAND_SHUFFLE: | 3262 | case PLAYLIST_COMMAND_SHUFFLE: |
3205 | { | 3263 | { |
3206 | /* str1=seed str2=first_index */ | 3264 | /* strp[0]=seed strp[1]=first_index */ |
3207 | int seed; | 3265 | int seed; |
3208 | 3266 | ||
3209 | if (!str1 || !str2) | 3267 | if (!strp[0] || !strp[1]) |
3210 | { | 3268 | { |
3211 | result = -8; | 3269 | result = -8; |
3212 | exit_loop = true; | 3270 | exit_loop = true; |
@@ -3219,8 +3277,8 @@ int playlist_resume(void) | |||
3219 | sort_playlist_unlocked(playlist, false, false); | 3277 | sort_playlist_unlocked(playlist, false, false); |
3220 | } | 3278 | } |
3221 | 3279 | ||
3222 | seed = atoi(str1); | 3280 | seed = atoi(strp[0]); |
3223 | playlist->first_index = atoi(str2); | 3281 | playlist->first_index = atoi(strp[1]); |
3224 | 3282 | ||
3225 | if (randomise_playlist_unlocked(playlist, seed, false, | 3283 | if (randomise_playlist_unlocked(playlist, seed, false, |
3226 | false) < 0) | 3284 | false) < 0) |
@@ -3234,15 +3292,15 @@ int playlist_resume(void) | |||
3234 | } | 3292 | } |
3235 | case PLAYLIST_COMMAND_UNSHUFFLE: | 3293 | case PLAYLIST_COMMAND_UNSHUFFLE: |
3236 | { | 3294 | { |
3237 | /* str1=first_index */ | 3295 | /* strp[0]=first_index */ |
3238 | if (!str1) | 3296 | if (!strp[0]) |
3239 | { | 3297 | { |
3240 | result = -10; | 3298 | result = -10; |
3241 | exit_loop = true; | 3299 | exit_loop = true; |
3242 | break; | 3300 | break; |
3243 | } | 3301 | } |
3244 | 3302 | ||
3245 | playlist->first_index = atoi(str1); | 3303 | playlist->first_index = atoi(strp[0]); |
3246 | 3304 | ||
3247 | if (sort_playlist_unlocked(playlist, false, false) < 0) | 3305 | if (sort_playlist_unlocked(playlist, false, false) < 0) |
3248 | { | 3306 | { |
@@ -3269,8 +3327,14 @@ int playlist_resume(void) | |||
3269 | } | 3327 | } |
3270 | case PLAYLIST_COMMAND_FLAGS: | 3328 | case PLAYLIST_COMMAND_FLAGS: |
3271 | { | 3329 | { |
3272 | unsigned int setf = atoi(str1); | 3330 | if (!strp[0] || !strp[1]) |
3273 | unsigned int clearf = atoi(str2); | 3331 | { |
3332 | result = -18; | ||
3333 | exit_loop = true; | ||
3334 | break; | ||
3335 | } | ||
3336 | unsigned int setf = atoi(strp[0]); | ||
3337 | unsigned int clearf = atoi(strp[1]); | ||
3274 | 3338 | ||
3275 | playlist->flags = (playlist->flags & ~clearf) | setf; | 3339 | playlist->flags = (playlist->flags & ~clearf) | setf; |
3276 | break; | 3340 | break; |
@@ -3290,69 +3354,13 @@ int playlist_resume(void) | |||
3290 | else if(newline) | 3354 | else if(newline) |
3291 | { | 3355 | { |
3292 | newline = false; | 3356 | newline = false; |
3293 | 3357 | current_command = (*pl_cmd)(*p); | |
3294 | switch (*p) | ||
3295 | { | ||
3296 | case 'P': | ||
3297 | /* playlist can only be specified once */ | ||
3298 | if (!first) | ||
3299 | { | ||
3300 | result = -13; | ||
3301 | exit_loop = true; | ||
3302 | break; | ||
3303 | } | ||
3304 | |||
3305 | current_command = PLAYLIST_COMMAND_PLAYLIST; | ||
3306 | break; | ||
3307 | case 'A': | ||
3308 | current_command = PLAYLIST_COMMAND_ADD; | ||
3309 | break; | ||
3310 | case 'Q': | ||
3311 | current_command = PLAYLIST_COMMAND_QUEUE; | ||
3312 | break; | ||
3313 | case 'D': | ||
3314 | current_command = PLAYLIST_COMMAND_DELETE; | ||
3315 | break; | ||
3316 | case 'S': | ||
3317 | current_command = PLAYLIST_COMMAND_SHUFFLE; | ||
3318 | break; | ||
3319 | case 'U': | ||
3320 | current_command = PLAYLIST_COMMAND_UNSHUFFLE; | ||
3321 | break; | ||
3322 | case 'R': | ||
3323 | current_command = PLAYLIST_COMMAND_RESET; | ||
3324 | break; | ||
3325 | case 'C': | ||
3326 | current_command = PLAYLIST_COMMAND_CLEAR; | ||
3327 | break; | ||
3328 | case 'F': | ||
3329 | current_command = PLAYLIST_COMMAND_FLAGS; | ||
3330 | break; | ||
3331 | case '#': | ||
3332 | current_command = PLAYLIST_COMMAND_COMMENT; | ||
3333 | break; | ||
3334 | default: | ||
3335 | result = -14; | ||
3336 | exit_loop = true; | ||
3337 | break; | ||
3338 | } | ||
3339 | |||
3340 | /* first non-comment line must always specify playlist */ | ||
3341 | if (first && | ||
3342 | (current_command != PLAYLIST_COMMAND_PLAYLIST) && | ||
3343 | (current_command != PLAYLIST_COMMAND_COMMENT)) | ||
3344 | { | ||
3345 | result = -12; | ||
3346 | exit_loop = true; | ||
3347 | break; | ||
3348 | } | ||
3349 | |||
3350 | str_count = -1; | 3358 | str_count = -1; |
3351 | str1 = NULL; | 3359 | strp[0] = NULL; |
3352 | str2 = NULL; | 3360 | strp[1] = NULL; |
3353 | str3 = NULL; | 3361 | strp[2] = NULL; |
3354 | } | 3362 | } |
3355 | else if(current_command != PLAYLIST_COMMAND_COMMENT) | 3363 | else if(current_command < PLAYLIST_COMMAND_COMMENT) |
3356 | { | 3364 | { |
3357 | /* all control file strings are separated with a colon. | 3365 | /* all control file strings are separated with a colon. |
3358 | Replace the colon with 0 to get proper strings that can be | 3366 | Replace the colon with 0 to get proper strings that can be |
@@ -3367,13 +3375,9 @@ int playlist_resume(void) | |||
3367 | switch (str_count) | 3375 | switch (str_count) |
3368 | { | 3376 | { |
3369 | case 0: | 3377 | case 0: |
3370 | str1 = p+1; | ||
3371 | break; | ||
3372 | case 1: | 3378 | case 1: |
3373 | str2 = p+1; | ||
3374 | break; | ||
3375 | case 2: | 3379 | case 2: |
3376 | str3 = p+1; | 3380 | strp[str_count] = p+1; |
3377 | break; | 3381 | break; |
3378 | default: | 3382 | default: |
3379 | /* allow last string to contain colons */ | 3383 | /* allow last string to contain colons */ |
@@ -3385,7 +3389,7 @@ int playlist_resume(void) | |||
3385 | } | 3389 | } |
3386 | } | 3390 | } |
3387 | 3391 | ||
3388 | if (result < 0) | 3392 | if (result < 0 || current_command == PLAYLIST_COMMAND_ERROR) |
3389 | { | 3393 | { |
3390 | splashf(HZ*2, "Err: %d, %s", result, str(LANG_PLAYLIST_CONTROL_INVALID)); | 3394 | splashf(HZ*2, "Err: %d, %s", result, str(LANG_PLAYLIST_CONTROL_INVALID)); |
3391 | goto out; | 3395 | goto out; |
@@ -3443,20 +3447,14 @@ void playlist_resume_track(int start_index, unsigned int crc, | |||
3443 | unsigned int tmp_crc; | 3447 | unsigned int tmp_crc; |
3444 | struct playlist_info* playlist = ¤t_playlist; | 3448 | struct playlist_info* playlist = ¤t_playlist; |
3445 | 3449 | ||
3446 | tmp_crc = playlist_get_filename_crc32(playlist, start_index); | ||
3447 | |||
3448 | if (tmp_crc == crc) | ||
3449 | { | ||
3450 | playlist_start(start_index, elapsed, offset); | ||
3451 | return; | ||
3452 | } | ||
3453 | |||
3454 | for (i = 0 ; i < playlist->amount; i++) | 3450 | for (i = 0 ; i < playlist->amount; i++) |
3455 | { | 3451 | { |
3456 | tmp_crc = playlist_get_filename_crc32(playlist, i); | 3452 | int index = (i + start_index) % playlist->amount; |
3453 | |||
3454 | tmp_crc = playlist_get_filename_crc32(playlist, index); | ||
3457 | if (tmp_crc == crc) | 3455 | if (tmp_crc == crc) |
3458 | { | 3456 | { |
3459 | playlist_start(i, elapsed, offset); | 3457 | playlist_start(index, elapsed, offset); |
3460 | return; | 3458 | return; |
3461 | } | 3459 | } |
3462 | } | 3460 | } |
@@ -3739,7 +3737,7 @@ static int pl_save_playlist(struct playlist_info* playlist, | |||
3739 | if (playlist->indices[index] & PLAYLIST_QUEUED) | 3737 | if (playlist->indices[index] & PLAYLIST_QUEUED) |
3740 | continue; | 3738 | continue; |
3741 | 3739 | ||
3742 | if (get_track_filename(playlist, index, tmpbuf, tmpsize)) | 3740 | if (get_track_filename(playlist, index, tmpbuf, tmpsize) != 0) |
3743 | { | 3741 | { |
3744 | err = -2; | 3742 | err = -2; |
3745 | goto error; | 3743 | goto error; |
@@ -3914,7 +3912,8 @@ int playlist_save(struct playlist_info* playlist, char *filename) | |||
3914 | if (!playlist) | 3912 | if (!playlist) |
3915 | playlist = ¤t_playlist; | 3913 | playlist = ¤t_playlist; |
3916 | 3914 | ||
3917 | pathlen = format_track_path(save_path, filename, sizeof(save_path), PATH_ROOTSTR); | 3915 | pathlen = format_track_path(save_path, filename, |
3916 | sizeof(save_path), PATH_ROOTSTR, -1u); | ||
3918 | if (pathlen < 0) | 3917 | if (pathlen < 0) |
3919 | return -1; | 3918 | return -1; |
3920 | 3919 | ||
diff --git a/apps/playlist.h b/apps/playlist.h index c7b672a2ef..5ad90db6f1 100644 --- a/apps/playlist.h +++ b/apps/playlist.h | |||
@@ -51,7 +51,8 @@ enum playlist_command { | |||
51 | PLAYLIST_COMMAND_RESET, | 51 | PLAYLIST_COMMAND_RESET, |
52 | PLAYLIST_COMMAND_CLEAR, | 52 | PLAYLIST_COMMAND_CLEAR, |
53 | PLAYLIST_COMMAND_FLAGS, | 53 | PLAYLIST_COMMAND_FLAGS, |
54 | PLAYLIST_COMMAND_COMMENT | 54 | PLAYLIST_COMMAND_COMMENT, |
55 | PLAYLIST_COMMAND_ERROR = PLAYLIST_COMMAND_COMMENT + 1 /* Internal */ | ||
55 | }; | 56 | }; |
56 | 57 | ||
57 | enum { | 58 | enum { |
diff --git a/firmware/common/pathfuncs.c b/firmware/common/pathfuncs.c index b942fdf022..6b70078eb1 100644 --- a/firmware/common/pathfuncs.c +++ b/firmware/common/pathfuncs.c | |||
@@ -448,6 +448,10 @@ void path_remove_dot_segments (char *dstpath, const char *path) | |||
448 | } | 448 | } |
449 | 449 | ||
450 | /* Appends one path to another, adding separators between components if needed. | 450 | /* Appends one path to another, adding separators between components if needed. |
451 | * basepath_max can be used to truncate the basepath if desired | ||
452 | * NOTE: basepath is truncated after copying to the buffer so there must be enough | ||
453 | * free space for the entirety of the basepath even if the resulting string would fit | ||
454 | * | ||
451 | * Return value and behavior is otherwise as strlcpy so that truncation may be | 455 | * Return value and behavior is otherwise as strlcpy so that truncation may be |
452 | * detected. | 456 | * detected. |
453 | * | 457 | * |
@@ -455,9 +459,11 @@ void path_remove_dot_segments (char *dstpath, const char *path) | |||
455 | * PA_SEP_HARD adds a separator even if the base path is empty | 459 | * PA_SEP_HARD adds a separator even if the base path is empty |
456 | * PA_SEP_SOFT adds a separator only if the base path is not empty | 460 | * PA_SEP_SOFT adds a separator only if the base path is not empty |
457 | */ | 461 | */ |
458 | size_t path_append(char *buf, const char *basepath, | 462 | size_t path_append_ex(char *buf, const char *basepath, size_t basepath_max, |
459 | const char *component, size_t bufsize) | 463 | const char *component, size_t bufsize) |
460 | { | 464 | { |
465 | size_t len; | ||
466 | bool separate = false; | ||
461 | const char *base = basepath && basepath[0] ? basepath : buf; | 467 | const char *base = basepath && basepath[0] ? basepath : buf; |
462 | if (!base) | 468 | if (!base) |
463 | return bufsize; /* won't work to get lengths from buf */ | 469 | return bufsize; /* won't work to get lengths from buf */ |
@@ -474,11 +480,20 @@ size_t path_append(char *buf, const char *basepath, | |||
474 | 480 | ||
475 | /* if basepath is not null or empty, buffer contents are replaced, | 481 | /* if basepath is not null or empty, buffer contents are replaced, |
476 | otherwise buf contains the base path */ | 482 | otherwise buf contains the base path */ |
477 | size_t len = base == buf ? strlen(buf) : strlcpy(buf, basepath, bufsize); | ||
478 | 483 | ||
479 | bool separate = false; | 484 | if (base == buf) |
485 | len = strlen(buf); | ||
486 | else | ||
487 | { | ||
488 | len = strlcpy(buf, basepath, bufsize); | ||
489 | if (basepath_max < len && basepath != component) | ||
490 | { | ||
491 | len = basepath_max; | ||
492 | buf[basepath_max] = '\0'; | ||
493 | } | ||
494 | } | ||
480 | 495 | ||
481 | if (!basepath || !component) | 496 | if (!basepath || !component || basepath_max == 0) |
482 | separate = !len || base[len-1] != PATH_SEPCH; | 497 | separate = !len || base[len-1] != PATH_SEPCH; |
483 | else if (component[0]) | 498 | else if (component[0]) |
484 | separate = len && base[len-1] != PATH_SEPCH; | 499 | separate = len && base[len-1] != PATH_SEPCH; |
@@ -496,6 +511,12 @@ size_t path_append(char *buf, const char *basepath, | |||
496 | return len + strlcpy(buf, component ?: "", bufsize); | 511 | return len + strlcpy(buf, component ?: "", bufsize); |
497 | } | 512 | } |
498 | 513 | ||
514 | |||
515 | size_t path_append(char *buf, const char *basepath, | ||
516 | const char *component, size_t bufsize) | ||
517 | { | ||
518 | return path_append_ex(buf, basepath, -1u, component, bufsize); | ||
519 | } | ||
499 | /* Returns the location and length of the next path component, consuming the | 520 | /* Returns the location and length of the next path component, consuming the |
500 | * input in the process. | 521 | * input in the process. |
501 | * | 522 | * |
diff --git a/firmware/export/pathfuncs.h b/firmware/export/pathfuncs.h index d4fa4eb460..1b18f22d06 100644 --- a/firmware/export/pathfuncs.h +++ b/firmware/export/pathfuncs.h | |||
@@ -94,6 +94,8 @@ void path_remove_dot_segments(char *dstpath, const char *path); | |||
94 | /* constants useable in basepath and component */ | 94 | /* constants useable in basepath and component */ |
95 | #define PA_SEP_HARD NULL /* separate even if base is empty */ | 95 | #define PA_SEP_HARD NULL /* separate even if base is empty */ |
96 | #define PA_SEP_SOFT "" /* separate only if base is nonempty */ | 96 | #define PA_SEP_SOFT "" /* separate only if base is nonempty */ |
97 | size_t path_append_ex(char *buf, const char *basepath, size_t basepath_max, | ||
98 | const char *component, size_t bufsize); | ||
97 | size_t path_append(char *buffer, const char *basepath, const char *component, | 99 | size_t path_append(char *buffer, const char *basepath, const char *component, |
98 | size_t bufsize); | 100 | size_t bufsize); |
99 | ssize_t parse_path_component(const char **pathp, const char **namep); | 101 | ssize_t parse_path_component(const char **pathp, const char **namep); |