summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorNick Peskett <rockbox@peskett.co.uk>2011-12-16 10:09:41 +0000
committerNick Peskett <rockbox@peskett.co.uk>2011-12-16 10:09:41 +0000
commit02fd314a0b426d6d445e2c9b167681ade6b0c1d2 (patch)
treead6100925dadaae0a69b8ec87b03eb8c1c5b23ab /apps
parent014003afac4e6ab5f132df25e0e92106ed21607a (diff)
downloadrockbox-02fd314a0b426d6d445e2c9b167681ade6b0c1d2.tar.gz
rockbox-02fd314a0b426d6d445e2c9b167681ade6b0c1d2.zip
FS #12419 : Support for embedded cuesheets.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31321 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/cuesheet.c127
-rw-r--r--apps/cuesheet.h15
-rw-r--r--apps/metadata.c4
-rw-r--r--apps/metadata.h16
-rw-r--r--apps/metadata/id3tags.c34
-rw-r--r--apps/metadata/vorbis.c20
-rw-r--r--apps/mpeg.c6
-rw-r--r--apps/playback.c6
8 files changed, 186 insertions, 42 deletions
diff --git a/apps/cuesheet.c b/apps/cuesheet.c
index 935af60898..ab4063a66a 100644
--- a/apps/cuesheet.c
+++ b/apps/cuesheet.c
@@ -42,21 +42,29 @@
42 42
43#define CUE_DIR ROCKBOX_DIR "/cue" 43#define CUE_DIR ROCKBOX_DIR "/cue"
44 44
45bool look_for_cuesheet_file(const char *trackpath, char *found_cue_path) 45bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cue_file)
46{ 46{
47 /* DEBUGF("look for cue file\n"); */ 47 /* DEBUGF("look for cue file\n"); */
48 48
49 char cuepath[MAX_PATH]; 49 char cuepath[MAX_PATH];
50 char *dot, *slash; 50 char *dot, *slash;
51 51
52 slash = strrchr(trackpath, '/'); 52 if (track_id3->embed_cuesheet.present)
53 if (!slash)
54 { 53 {
55 found_cue_path = NULL; 54 cue_file->pos = track_id3->embed_cuesheet.pos;
56 return false; 55 cue_file->size = track_id3->embed_cuesheet.size;
56 cue_file->encoding = track_id3->embed_cuesheet.encoding;
57 strlcpy(cue_file->path, track_id3->path, MAX_PATH);
58 return true;
57 } 59 }
58 60
59 strlcpy(cuepath, trackpath, MAX_PATH); 61 cue_file->pos = 0;
62 cue_file->size = 0;
63 cue_file->path[0] = '\0';
64 slash = strrchr(track_id3->path, '/');
65 if (!slash)
66 return false;
67 strlcpy(cuepath, track_id3->path, MAX_PATH);
60 dot = strrchr(cuepath, '.'); 68 dot = strrchr(cuepath, '.');
61 strcpy(dot, ".cue"); 69 strcpy(dot, ".cue");
62 70
@@ -67,15 +75,10 @@ bool look_for_cuesheet_file(const char *trackpath, char *found_cue_path)
67 char *dot = strrchr(cuepath, '.'); 75 char *dot = strrchr(cuepath, '.');
68 strcpy(dot, ".cue"); 76 strcpy(dot, ".cue");
69 if (!file_exists(cuepath)) 77 if (!file_exists(cuepath))
70 {
71 if (found_cue_path)
72 found_cue_path = NULL;
73 return false; 78 return false;
74 }
75 } 79 }
76 80
77 if (found_cue_path) 81 strlcpy(cue_file->path, cuepath, MAX_PATH);
78 strlcpy(found_cue_path, cuepath, MAX_PATH);
79 return true; 82 return true;
80} 83}
81 84
@@ -99,29 +102,81 @@ static char *get_string(const char *line)
99 return start; 102 return start;
100} 103}
101 104
102/* parse cuesheet "file" and store the information in "cue" */ 105/* parse cuesheet "cue_file" and store the information in "cue" */
103bool parse_cuesheet(char *file, struct cuesheet *cue) 106bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
104{ 107{
105 char line[MAX_PATH]; 108 char line[MAX_PATH];
106 char *s; 109 char *s;
107 bool utf8 = false; 110 unsigned char char_enc = CHAR_ENC_ISO_8859_1;
111 bool is_embedded = false;
112 int line_len;
113 int bytes_left = 0;
114 int read_bytes = MAX_PATH;
115 unsigned char utf16_buf[MAX_PATH];
116
117 int fd = open(cue_file->path, O_RDONLY, 0644);
118 if(fd < 0)
119 return false;
120 if (cue_file->pos > 0)
121 {
122 is_embedded = true;
123 lseek(fd, cue_file->pos, SEEK_SET);
124 bytes_left = cue_file->size;
125 char_enc = cue_file->encoding;
126 }
108 127
109 int fd = open_utf8(file,O_RDONLY); 128 /* Look for a Unicode BOM */
110 if (fd < 0) 129 unsigned char bom_read = 0;
130 read(fd, line, 3);
131 if(!memcmp(line, "\xef\xbb\xbf", 3))
111 { 132 {
112 /* couln't open the file */ 133 char_enc = CHAR_ENC_UTF_8;
113 return false; 134 bom_read = 3;
135 }
136 else if(!memcmp(line, "\xff\xfe", 2))
137 {
138 char_enc = CHAR_ENC_UTF_16_LE;
139 bom_read = 2;
140 }
141 else if(!memcmp(line, "\xfe\xff", 2))
142 {
143 char_enc = CHAR_ENC_UTF_16_BE;
144 bom_read = 2;
145 }
146 if (bom_read < 3 )
147 lseek(fd, cue_file->pos + bom_read, SEEK_SET);
148 if (is_embedded)
149 {
150 if (bom_read > 0)
151 bytes_left -= bom_read;
152 if (read_bytes > bytes_left)
153 read_bytes = bytes_left;
114 } 154 }
115 if(lseek(fd, 0, SEEK_CUR) > 0)
116 utf8 = true;
117 155
118 /* Initialization */ 156 /* Initialization */
119 memset(cue, 0, sizeof(struct cuesheet)); 157 memset(cue, 0, sizeof(struct cuesheet));
120 strcpy(cue->path, file); 158 strcpy(cue->path, cue_file->path);
121 cue->curr_track = cue->tracks; 159 cue->curr_track = cue->tracks;
122 160
123 while ( read_line(fd,line,MAX_PATH) && cue->track_count < MAX_TRACKS ) 161 while ((line_len = read_line(fd, line, read_bytes)) > 0
162 && cue->track_count < MAX_TRACKS )
124 { 163 {
164 if (char_enc == CHAR_ENC_UTF_16_LE)
165 {
166 s = utf16LEdecode(line, utf16_buf, line_len);
167 /* terminate the string at the newline */
168 *s = '\0';
169 strcpy(line, utf16_buf);
170 /* chomp the trailing 0 after the newline */
171 lseek(fd, 1, SEEK_CUR);
172 line_len++;
173 }
174 else if (char_enc == CHAR_ENC_UTF_16_BE)
175 {
176 s = utf16BEdecode(line, utf16_buf, line_len);
177 *s = '\0';
178 strcpy(line, utf16_buf);
179 }
125 s = skip_whitespace(line); 180 s = skip_whitespace(line);
126 181
127 if (!strncmp(s, "TRACK", 5)) 182 if (!strncmp(s, "TRACK", 5))
@@ -169,9 +224,10 @@ bool parse_cuesheet(char *file, struct cuesheet *cue)
169 224
170 if (dest) 225 if (dest)
171 { 226 {
172 if (!utf8) 227 if (char_enc == CHAR_ENC_ISO_8859_1)
173 { 228 {
174 dest = iso_decode(string, dest, -1, MIN(strlen(string), MAX_NAME)); 229 dest = iso_decode(string, dest, -1,
230 MIN(strlen(string), MAX_NAME));
175 *dest = '\0'; 231 *dest = '\0';
176 } 232 }
177 else 233 else
@@ -180,6 +236,14 @@ bool parse_cuesheet(char *file, struct cuesheet *cue)
180 } 236 }
181 } 237 }
182 } 238 }
239 if (is_embedded)
240 {
241 bytes_left -= line_len;
242 if (bytes_left <= 0)
243 break;
244 if (bytes_left < read_bytes)
245 read_bytes = bytes_left;
246 }
183 } 247 }
184 close(fd); 248 close(fd);
185 249
@@ -256,7 +320,7 @@ void browse_cuesheet(struct cuesheet *cue)
256 bool done = false; 320 bool done = false;
257 int sel; 321 int sel;
258 char title[MAX_PATH]; 322 char title[MAX_PATH];
259 char cuepath[MAX_PATH]; 323 struct cuesheet_file cue_file;
260 struct mp3entry *id3 = audio_current_track(); 324 struct mp3entry *id3 = audio_current_track();
261 325
262 snprintf(title, MAX_PATH, "%s: %s", cue->performer, cue->title); 326 snprintf(title, MAX_PATH, "%s: %s", cue->performer, cue->title);
@@ -283,8 +347,8 @@ void browse_cuesheet(struct cuesheet *cue)
283 id3 = audio_current_track(); 347 id3 = audio_current_track();
284 if (id3 && *id3->path && strcmp(id3->path, "No file!")) 348 if (id3 && *id3->path && strcmp(id3->path, "No file!"))
285 { 349 {
286 look_for_cuesheet_file(id3->path, cuepath); 350 look_for_cuesheet_file(id3, &cue_file);
287 if (id3->cuesheet && !strcmp(cue->path, cuepath)) 351 if (id3->cuesheet && !strcmp(cue->path, cue_file.path))
288 { 352 {
289 sel = gui_synclist_get_sel_pos(&lists); 353 sel = gui_synclist_get_sel_pos(&lists);
290 seek(cue->tracks[sel/2].offset); 354 seek(cue->tracks[sel/2].offset);
@@ -300,11 +364,16 @@ void browse_cuesheet(struct cuesheet *cue)
300bool display_cuesheet_content(char* filename) 364bool display_cuesheet_content(char* filename)
301{ 365{
302 size_t bufsize = 0; 366 size_t bufsize = 0;
367 struct cuesheet_file cue_file;
303 struct cuesheet *cue = (struct cuesheet *)plugin_get_buffer(&bufsize); 368 struct cuesheet *cue = (struct cuesheet *)plugin_get_buffer(&bufsize);
304 if (!cue || bufsize < sizeof(struct cuesheet)) 369 if (!cue || bufsize < sizeof(struct cuesheet))
305 return false; 370 return false;
306 371
307 if (!parse_cuesheet(filename, cue)) 372 strlcpy(cue_file.path, filename, MAX_PATH);
373 cue_file.pos = 0;
374 cue_file.size = 0;
375
376 if (!parse_cuesheet(&cue_file, cue))
308 return false; 377 return false;
309 378
310 browse_cuesheet(cue); 379 browse_cuesheet(cue);
diff --git a/apps/cuesheet.h b/apps/cuesheet.h
index e8d77ca3a9..31841dacf6 100644
--- a/apps/cuesheet.h
+++ b/apps/cuesheet.h
@@ -51,11 +51,18 @@ struct cuesheet {
51 struct cue_track_info *curr_track; 51 struct cue_track_info *curr_track;
52}; 52};
53 53
54/* looks if there is a cuesheet file that has a name matching "trackpath" */ 54struct cuesheet_file {
55bool look_for_cuesheet_file(const char *trackpath, char *found_cue_path); 55 char path[MAX_PATH];
56 int size;
57 off_t pos;
58 enum character_encoding encoding;
59};
60
61/* looks if there is a cuesheet file with a name matching path of "track_id3" */
62bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cue_file);
56 63
57/* parse cuesheet "file" and store the information in "cue" */ 64/* parse cuesheet_file "cue_file" and store the information in "cue" */
58bool parse_cuesheet(char *file, struct cuesheet *cue); 65bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue);
59 66
60/* reads a cuesheet to find the audio track associated to it */ 67/* reads a cuesheet to find the audio track associated to it */
61bool get_trackname_from_cuesheet(char *filename, char *buf); 68bool get_trackname_from_cuesheet(char *filename, char *buf);
diff --git a/apps/metadata.c b/apps/metadata.c
index 7479de105f..898436781b 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -438,6 +438,10 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
438 /* Take our best guess at the codec type based on file extension */ 438 /* Take our best guess at the codec type based on file extension */
439 id3->codectype = probe_file_format(trackname); 439 id3->codectype = probe_file_format(trackname);
440 440
441 /* default values for embedded cuesheets */
442 id3->embed_cuesheet.present = false;
443 id3->embed_cuesheet.pos = 0;
444
441 entry = &audio_formats[id3->codectype]; 445 entry = &audio_formats[id3->codectype];
442 446
443 /* Load codec specific track tag information and confirm the codec type. */ 447 /* Load codec specific track tag information and confirm the codec type. */
diff --git a/apps/metadata.h b/apps/metadata.h
index 3676bd8e24..0c6768d3d9 100644
--- a/apps/metadata.h
+++ b/apps/metadata.h
@@ -217,6 +217,21 @@ struct mp3_albumart {
217}; 217};
218#endif 218#endif
219 219
220enum character_encoding {
221 CHAR_ENC_ISO_8859_1 = 1,
222 CHAR_ENC_UTF_8,
223 CHAR_ENC_UTF_16_LE,
224 CHAR_ENC_UTF_16_BE,
225};
226
227/* cache embedded cuesheet details */
228struct embed_cuesheet {
229 bool present;
230 int size;
231 off_t pos;
232 enum character_encoding encoding;
233};
234
220struct mp3entry { 235struct mp3entry {
221 char path[MAX_PATH]; 236 char path[MAX_PATH];
222 char* title; 237 char* title;
@@ -307,6 +322,7 @@ struct mp3entry {
307#endif 322#endif
308 323
309 /* Cuesheet support */ 324 /* Cuesheet support */
325 struct embed_cuesheet embed_cuesheet;
310 struct cuesheet *cuesheet; 326 struct cuesheet *cuesheet;
311 327
312 /* Musicbrainz Track ID */ 328 /* Musicbrainz Track ID */
diff --git a/apps/metadata/id3tags.c b/apps/metadata/id3tags.c
index dcf71f71bf..e9b59e012a 100644
--- a/apps/metadata/id3tags.c
+++ b/apps/metadata/id3tags.c
@@ -995,6 +995,40 @@ void setid3v2title(int fd, struct mp3entry *entry)
995 if(bytesread >= buffersize - bufferpos) 995 if(bytesread >= buffersize - bufferpos)
996 bytesread = buffersize - bufferpos - 1; 996 bytesread = buffersize - bufferpos - 1;
997 997
998 if ( /* Is it an embedded cuesheet? */
999 (tr->tag_length == 4 && !memcmp(header, "TXXX", 4)) &&
1000 (bytesread >= 14 && !strncmp(utf8buf, "CUESHEET", 8))
1001 ) {
1002 unsigned char char_enc = 0;
1003 /* 0CUESHEET0 = 10 bytes */
1004 unsigned char cuesheet_offset = 10;
1005 switch (tag[0]) {
1006 case 0x00:
1007 char_enc = CHAR_ENC_ISO_8859_1;
1008 break;
1009 case 0x01:
1010 char_enc = CHAR_ENC_UTF_16_LE;
1011 cuesheet_offset += cuesheet_offset+1;
1012 break;
1013 case 0x02:
1014 char_enc = CHAR_ENC_UTF_16_BE;
1015 cuesheet_offset += cuesheet_offset+1;
1016 break;
1017 case 0x03:
1018 char_enc = CHAR_ENC_UTF_8;
1019 break;
1020 }
1021 if (char_enc > 0) {
1022 entry->embed_cuesheet.present = true;
1023 entry->embed_cuesheet.pos = lseek(fd, 0, SEEK_CUR)
1024 - framelen + cuesheet_offset;
1025 entry->embed_cuesheet.size = totframelen
1026 - cuesheet_offset;
1027 entry->embed_cuesheet.encoding = char_enc;
1028 }
1029 break;
1030 }
1031
998 for (j = 0; j < bytesread; j++) 1032 for (j = 0; j < bytesread; j++)
999 tag[j] = utf8buf[j]; 1033 tag[j] = utf8buf[j];
1000 1034
diff --git a/apps/metadata/vorbis.c b/apps/metadata/vorbis.c
index f6d3af1cef..29848daa19 100644
--- a/apps/metadata/vorbis.c
+++ b/apps/metadata/vorbis.c
@@ -341,15 +341,29 @@ long read_vorbis_tags(int fd, struct mp3entry *id3,
341 } 341 }
342 342
343 len -= read_len; 343 len -= read_len;
344 read_len = file_read_string(&file, id3->path, sizeof(id3->path), -1, len);
344 345
345 if (file_read_string(&file, id3->path, sizeof(id3->path), -1, len) < 0) 346 if (read_len < 0)
346 { 347 {
347 return 0; 348 return 0;
348 } 349 }
349 350
350 logf("Vorbis comment %d: %s=%s", i, name, id3->path); 351 logf("Vorbis comment %d: %s=%s", i, name, id3->path);
351 len = parse_tag(name, id3->path, id3, buf, buf_remaining, 352
352 TAGTYPE_VORBIS); 353 /* Is it an embedded cuesheet? */
354 if (!strcasecmp(name, "CUESHEET"))
355 {
356 id3->embed_cuesheet.present = true;
357 id3->embed_cuesheet.pos = lseek(file.fd, 0, SEEK_CUR) - read_len;
358 id3->embed_cuesheet.size = len;
359 id3->embed_cuesheet.encoding = CHAR_ENC_UTF_8;
360 }
361 else
362 {
363 len = parse_tag(name, id3->path, id3, buf, buf_remaining,
364 TAGTYPE_VORBIS);
365 }
366
353 buf += len; 367 buf += len;
354 buf_remaining -= len; 368 buf_remaining -= len;
355 } 369 }
diff --git a/apps/mpeg.c b/apps/mpeg.c
index 698695b72d..4fbc40ff1e 100644
--- a/apps/mpeg.c
+++ b/apps/mpeg.c
@@ -2170,10 +2170,10 @@ struct mp3entry* audio_current_track(void)
2170 if (!checked_for_cuesheet && curr_cuesheet && id3->cuesheet == NULL) 2170 if (!checked_for_cuesheet && curr_cuesheet && id3->cuesheet == NULL)
2171 { 2171 {
2172 checked_for_cuesheet = true; /* only check once per track */ 2172 checked_for_cuesheet = true; /* only check once per track */
2173 char cuepath[MAX_PATH]; 2173 struct cuesheet_file cue_file;
2174 2174
2175 if (look_for_cuesheet_file(id3->path, cuepath) && 2175 if (look_for_cuesheet_file(id3, &cue_file)) &&
2176 parse_cuesheet(cuepath, curr_cuesheet)) 2176 parse_cuesheet(&cue_file, curr_cuesheet))
2177 { 2177 {
2178 id3->cuesheet = curr_cuesheet; 2178 id3->cuesheet = curr_cuesheet;
2179 } 2179 }
diff --git a/apps/playback.c b/apps/playback.c
index 2739118aeb..36fbd88832 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -1485,12 +1485,12 @@ static bool audio_load_cuesheet(struct track_info *info,
1485 /* If error other than a full buffer, then mark it "unsupported" to 1485 /* If error other than a full buffer, then mark it "unsupported" to
1486 avoid reloading attempt */ 1486 avoid reloading attempt */
1487 int hid = ERR_UNSUPPORTED_TYPE; 1487 int hid = ERR_UNSUPPORTED_TYPE;
1488 char cuepath[MAX_PATH]; 1488 struct cuesheet_file cue_file;
1489 1489
1490#ifdef HAVE_IO_PRIORITY 1490#ifdef HAVE_IO_PRIORITY
1491 buf_back_off_storage(true); 1491 buf_back_off_storage(true);
1492#endif 1492#endif
1493 if (look_for_cuesheet_file(track_id3->path, cuepath)) 1493 if (look_for_cuesheet_file(track_id3, &cue_file))
1494 { 1494 {
1495 hid = bufalloc(NULL, sizeof (struct cuesheet), TYPE_CUESHEET); 1495 hid = bufalloc(NULL, sizeof (struct cuesheet), TYPE_CUESHEET);
1496 1496
@@ -1499,7 +1499,7 @@ static bool audio_load_cuesheet(struct track_info *info,
1499 void *cuesheet = NULL; 1499 void *cuesheet = NULL;
1500 bufgetdata(hid, sizeof (struct cuesheet), &cuesheet); 1500 bufgetdata(hid, sizeof (struct cuesheet), &cuesheet);
1501 1501
1502 if (parse_cuesheet(cuepath, (struct cuesheet *)cuesheet)) 1502 if (parse_cuesheet(&cue_file, (struct cuesheet *)cuesheet))
1503 { 1503 {
1504 /* Indicate cuesheet is present (while track remains 1504 /* Indicate cuesheet is present (while track remains
1505 buffered) */ 1505 buffered) */