A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 228 lines 6.3 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2002 Linus Nielsen Feltzing 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21#include "plugin.h" 22 23/**************************************************************************** 24 * Buffer handling: 25 * 26 * We allocate the MP3 buffer for storing the text to be sorted, and then 27 * search the buffer for newlines and store an array of character pointers 28 * to the strings. 29 * 30 * The pointer array grows from the top of the buffer and downwards: 31 * 32 * |-------------| 33 * | pointers[2] |--------| 34 * | pointers[1] |------| | 35 * | pointers[0] |----| | | 36 * |-------------| | | | 37 * | | | | | 38 * | | | | | 39 * | free space | | | | 40 * | | | | | 41 * | | | | | 42 * |-------------| | | | 43 * | | | | | 44 * | line 3\0 |<---| | | 45 * | line 2\0 |<-----| | 46 * | line 1\0 |<-------| 47 * |-------------| 48 * 49 * The advantage of this method is that we optimize the buffer usage. 50 * 51 * The disadvantage is that the string pointers will be loaded in reverse 52 * order. We therefore sort the strings in reverse order as well, so we 53 * don't have to sort an already sorted buffer. 54 ****************************************************************************/ 55 56/*************************************************************************** 57 * TODO: Implement a merge sort for files larger than the buffer 58 ****************************************************************************/ 59size_t buf_size; 60static char *filename; 61static int num_entries; 62static char **pointers; 63static char *stringbuffer; 64static char crlf[2] __NONSTRING = "\r\n"; 65static int bomsize; 66 67/* Compare function for sorting backwards */ 68static int compare(const void* p1, const void* p2) 69{ 70 char *s1 = *(char **)p1; 71 char *s2 = *(char **)p2; 72 73 return rb->strcasecmp(s2, s1); 74} 75 76static void sort_buffer(void) 77{ 78 rb->qsort(pointers, num_entries, sizeof(char *), compare); 79} 80 81static int read_buffer(int offset) 82{ 83 int fd; 84 char *buf_ptr; 85 char *tmp_ptr; 86 int readsize; 87 88 fd = rb->open_utf8(filename, O_RDONLY); 89 if(fd < 0) 90 return 10 * fd - 1; 91 92 bomsize = rb->lseek(fd, 0, SEEK_CUR); 93 offset += bomsize; 94 95 /* Fill the buffer from the file */ 96 rb->lseek(fd, offset, SEEK_SET); 97 readsize = rb->read(fd, stringbuffer, buf_size); 98 rb->close(fd); 99 100 if(readsize < 0) 101 return readsize * 10 - 2; 102 103 /* Temporary fix until we can do merged sorting */ 104 if(readsize == (int)buf_size) 105 return buf_size; /* File too big */ 106 107 buf_ptr = stringbuffer; 108 num_entries = 0; 109 110 do { 111 tmp_ptr = buf_ptr; 112 while(*buf_ptr != '\n' && buf_ptr < (char *)pointers) { 113 /* Terminate the string with CR... */ 114 if(*buf_ptr == '\r') 115 *buf_ptr = 0; 116 buf_ptr++; 117 } 118 /* ...and with LF */ 119 if(*buf_ptr == '\n') 120 *buf_ptr = 0; 121 else { 122 return tmp_ptr - stringbuffer; /* Buffer is full, return 123 the point to resume at */ 124 } 125 126 pointers--; 127 *pointers = tmp_ptr; 128 num_entries++; 129 buf_ptr++; 130 } while(buf_ptr < stringbuffer + readsize); 131 132 return 0; 133} 134 135static int write_file(void) 136{ 137 char tmpfilename[MAX_PATH+1]; 138 int fd; 139 int i; 140 int rc; 141 142 /* Create a temporary file */ 143 rb->snprintf(tmpfilename, MAX_PATH+1, "%s.tmp", filename); 144 if (bomsize) 145 fd = rb->open_utf8(tmpfilename, O_WRONLY|O_CREAT|O_TRUNC); 146 else 147 fd = rb->open(tmpfilename, O_WRONLY|O_CREAT|O_TRUNC, 0666); 148 149 if(fd < 0) 150 return 10 * fd - 1; 151 152 /* Write the sorted strings, with appended CR/LF, to the temp file, 153 in reverse order */ 154 for(i = num_entries-1;i >= 0;i--) { 155 rc = rb->write(fd, pointers[i], rb->strlen(pointers[i])); 156 if(rc < 0) { 157 rb->close(fd); 158 return 10 * rc - 2; 159 } 160 161 rc = rb->write(fd, crlf, 2); 162 if(rc < 0) { 163 rb->close(fd); 164 return 10 * rc - 3; 165 } 166 } 167 168 rb->close(fd); 169 170 /* Remove the original file */ 171 rc = rb->remove(filename); 172 if(rc < 0) { 173 return 10 * rc - 4; 174 } 175 176 /* Replace the old file with the new */ 177 rc = rb->rename(tmpfilename, filename); 178 if(rc < 0) { 179 return 10 * rc - 5; 180 } 181 return 0; 182} 183 184enum plugin_status plugin_start(const void* parameter) 185{ 186 char *buf; 187 int rc; 188 if(!parameter) return PLUGIN_ERROR; 189 190 filename = (char *)parameter; 191 192 buf = rb->plugin_get_audio_buffer(&buf_size); /* start munching memory */ 193 194 stringbuffer = buf; 195 pointers = (char **)(buf + buf_size - sizeof(int)); 196 197 rb->lcd_clear_display(); 198 rb->splash(0, "Loading..."); 199 200 rc = read_buffer(0); 201 if(rc == 0) { 202 rb->lcd_clear_display(); 203 rb->splash(0, "Sorting..."); 204 sort_buffer(); 205 206 rb->lcd_clear_display(); 207 rb->splash(0, "Writing..."); 208 209 rc = write_file(); 210 if(rc < 0) { 211 rb->lcd_clear_display(); 212 rb->splashf(HZ, "Can't write file: %d", rc); 213 } else { 214 rb->lcd_clear_display(); 215 rb->splash(HZ, "Done"); 216 } 217 } else { 218 if(rc < 0) { 219 rb->lcd_clear_display(); 220 rb->splashf(HZ, "Can't read file: %d", rc); 221 } else { 222 rb->lcd_clear_display(); 223 rb->splash(HZ, "The file is too big"); 224 } 225 } 226 227 return PLUGIN_OK; 228}