summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
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 @@
#define CUE_DIR ROCKBOX_DIR "/cue"
-bool look_for_cuesheet_file(const char *trackpath, char *found_cue_path)
+bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cue_file)
{
/* DEBUGF("look for cue file\n"); */
char cuepath[MAX_PATH];
char *dot, *slash;
- slash = strrchr(trackpath, '/');
- if (!slash)
+ if (track_id3->embed_cuesheet.present)
{
- found_cue_path = NULL;
- return false;
+ cue_file->pos = track_id3->embed_cuesheet.pos;
+ cue_file->size = track_id3->embed_cuesheet.size;
+ cue_file->encoding = track_id3->embed_cuesheet.encoding;
+ strlcpy(cue_file->path, track_id3->path, MAX_PATH);
+ return true;
}
- strlcpy(cuepath, trackpath, MAX_PATH);
+ cue_file->pos = 0;
+ cue_file->size = 0;
+ cue_file->path[0] = '\0';
+ slash = strrchr(track_id3->path, '/');
+ if (!slash)
+ return false;
+ strlcpy(cuepath, track_id3->path, MAX_PATH);
dot = strrchr(cuepath, '.');
strcpy(dot, ".cue");
@@ -67,15 +75,10 @@ bool look_for_cuesheet_file(const char *trackpath, char *found_cue_path)
char *dot = strrchr(cuepath, '.');
strcpy(dot, ".cue");
if (!file_exists(cuepath))
- {
- if (found_cue_path)
- found_cue_path = NULL;
return false;
- }
}
- if (found_cue_path)
- strlcpy(found_cue_path, cuepath, MAX_PATH);
+ strlcpy(cue_file->path, cuepath, MAX_PATH);
return true;
}
@@ -99,29 +102,81 @@ static char *get_string(const char *line)
return start;
}
-/* parse cuesheet "file" and store the information in "cue" */
-bool parse_cuesheet(char *file, struct cuesheet *cue)
+/* parse cuesheet "cue_file" and store the information in "cue" */
+bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
{
char line[MAX_PATH];
char *s;
- bool utf8 = false;
+ unsigned char char_enc = CHAR_ENC_ISO_8859_1;
+ bool is_embedded = false;
+ int line_len;
+ int bytes_left = 0;
+ int read_bytes = MAX_PATH;
+ unsigned char utf16_buf[MAX_PATH];
+
+ int fd = open(cue_file->path, O_RDONLY, 0644);
+ if(fd < 0)
+ return false;
+ if (cue_file->pos > 0)
+ {
+ is_embedded = true;
+ lseek(fd, cue_file->pos, SEEK_SET);
+ bytes_left = cue_file->size;
+ char_enc = cue_file->encoding;
+ }
- int fd = open_utf8(file,O_RDONLY);
- if (fd < 0)
+ /* Look for a Unicode BOM */
+ unsigned char bom_read = 0;
+ read(fd, line, 3);
+ if(!memcmp(line, "\xef\xbb\xbf", 3))
{
- /* couln't open the file */
- return false;
+ char_enc = CHAR_ENC_UTF_8;
+ bom_read = 3;
+ }
+ else if(!memcmp(line, "\xff\xfe", 2))
+ {
+ char_enc = CHAR_ENC_UTF_16_LE;
+ bom_read = 2;
+ }
+ else if(!memcmp(line, "\xfe\xff", 2))
+ {
+ char_enc = CHAR_ENC_UTF_16_BE;
+ bom_read = 2;
+ }
+ if (bom_read < 3 )
+ lseek(fd, cue_file->pos + bom_read, SEEK_SET);
+ if (is_embedded)
+ {
+ if (bom_read > 0)
+ bytes_left -= bom_read;
+ if (read_bytes > bytes_left)
+ read_bytes = bytes_left;
}
- if(lseek(fd, 0, SEEK_CUR) > 0)
- utf8 = true;
/* Initialization */
memset(cue, 0, sizeof(struct cuesheet));
- strcpy(cue->path, file);
+ strcpy(cue->path, cue_file->path);
cue->curr_track = cue->tracks;
- while ( read_line(fd,line,MAX_PATH) && cue->track_count < MAX_TRACKS )
+ while ((line_len = read_line(fd, line, read_bytes)) > 0
+ && cue->track_count < MAX_TRACKS )
{
+ if (char_enc == CHAR_ENC_UTF_16_LE)
+ {
+ s = utf16LEdecode(line, utf16_buf, line_len);
+ /* terminate the string at the newline */
+ *s = '\0';
+ strcpy(line, utf16_buf);
+ /* chomp the trailing 0 after the newline */
+ lseek(fd, 1, SEEK_CUR);
+ line_len++;
+ }
+ else if (char_enc == CHAR_ENC_UTF_16_BE)
+ {
+ s = utf16BEdecode(line, utf16_buf, line_len);
+ *s = '\0';
+ strcpy(line, utf16_buf);
+ }
s = skip_whitespace(line);
if (!strncmp(s, "TRACK", 5))
@@ -169,9 +224,10 @@ bool parse_cuesheet(char *file, struct cuesheet *cue)
if (dest)
{
- if (!utf8)
+ if (char_enc == CHAR_ENC_ISO_8859_1)
{
- dest = iso_decode(string, dest, -1, MIN(strlen(string), MAX_NAME));
+ dest = iso_decode(string, dest, -1,
+ MIN(strlen(string), MAX_NAME));
*dest = '\0';
}
else
@@ -180,6 +236,14 @@ bool parse_cuesheet(char *file, struct cuesheet *cue)
}
}
}
+ if (is_embedded)
+ {
+ bytes_left -= line_len;
+ if (bytes_left <= 0)
+ break;
+ if (bytes_left < read_bytes)
+ read_bytes = bytes_left;
+ }
}
close(fd);
@@ -256,7 +320,7 @@ void browse_cuesheet(struct cuesheet *cue)
bool done = false;
int sel;
char title[MAX_PATH];
- char cuepath[MAX_PATH];
+ struct cuesheet_file cue_file;
struct mp3entry *id3 = audio_current_track();
snprintf(title, MAX_PATH, "%s: %s", cue->performer, cue->title);
@@ -283,8 +347,8 @@ void browse_cuesheet(struct cuesheet *cue)
id3 = audio_current_track();
if (id3 && *id3->path && strcmp(id3->path, "No file!"))
{
- look_for_cuesheet_file(id3->path, cuepath);
- if (id3->cuesheet && !strcmp(cue->path, cuepath))
+ look_for_cuesheet_file(id3, &cue_file);
+ if (id3->cuesheet && !strcmp(cue->path, cue_file.path))
{
sel = gui_synclist_get_sel_pos(&lists);
seek(cue->tracks[sel/2].offset);
@@ -300,11 +364,16 @@ void browse_cuesheet(struct cuesheet *cue)
bool display_cuesheet_content(char* filename)
{
size_t bufsize = 0;
+ struct cuesheet_file cue_file;
struct cuesheet *cue = (struct cuesheet *)plugin_get_buffer(&bufsize);
if (!cue || bufsize < sizeof(struct cuesheet))
return false;
- if (!parse_cuesheet(filename, cue))
+ strlcpy(cue_file.path, filename, MAX_PATH);
+ cue_file.pos = 0;
+ cue_file.size = 0;
+
+ if (!parse_cuesheet(&cue_file, cue))
return false;
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 {
struct cue_track_info *curr_track;
};
-/* looks if there is a cuesheet file that has a name matching "trackpath" */
-bool look_for_cuesheet_file(const char *trackpath, char *found_cue_path);
+struct cuesheet_file {
+ char path[MAX_PATH];
+ int size;
+ off_t pos;
+ enum character_encoding encoding;
+};
+
+/* looks if there is a cuesheet file with a name matching path of "track_id3" */
+bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cue_file);
-/* parse cuesheet "file" and store the information in "cue" */
-bool parse_cuesheet(char *file, struct cuesheet *cue);
+/* parse cuesheet_file "cue_file" and store the information in "cue" */
+bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue);
/* reads a cuesheet to find the audio track associated to it */
bool 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)
/* Take our best guess at the codec type based on file extension */
id3->codectype = probe_file_format(trackname);
+ /* default values for embedded cuesheets */
+ id3->embed_cuesheet.present = false;
+ id3->embed_cuesheet.pos = 0;
+
entry = &audio_formats[id3->codectype];
/* 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 {
};
#endif
+enum character_encoding {
+ CHAR_ENC_ISO_8859_1 = 1,
+ CHAR_ENC_UTF_8,
+ CHAR_ENC_UTF_16_LE,
+ CHAR_ENC_UTF_16_BE,
+};
+
+/* cache embedded cuesheet details */
+struct embed_cuesheet {
+ bool present;
+ int size;
+ off_t pos;
+ enum character_encoding encoding;
+};
+
struct mp3entry {
char path[MAX_PATH];
char* title;
@@ -307,6 +322,7 @@ struct mp3entry {
#endif
/* Cuesheet support */
+ struct embed_cuesheet embed_cuesheet;
struct cuesheet *cuesheet;
/* 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)
if(bytesread >= buffersize - bufferpos)
bytesread = buffersize - bufferpos - 1;
+ if ( /* Is it an embedded cuesheet? */
+ (tr->tag_length == 4 && !memcmp(header, "TXXX", 4)) &&
+ (bytesread >= 14 && !strncmp(utf8buf, "CUESHEET", 8))
+ ) {
+ unsigned char char_enc = 0;
+ /* 0CUESHEET0 = 10 bytes */
+ unsigned char cuesheet_offset = 10;
+ switch (tag[0]) {
+ case 0x00:
+ char_enc = CHAR_ENC_ISO_8859_1;
+ break;
+ case 0x01:
+ char_enc = CHAR_ENC_UTF_16_LE;
+ cuesheet_offset += cuesheet_offset+1;
+ break;
+ case 0x02:
+ char_enc = CHAR_ENC_UTF_16_BE;
+ cuesheet_offset += cuesheet_offset+1;
+ break;
+ case 0x03:
+ char_enc = CHAR_ENC_UTF_8;
+ break;
+ }
+ if (char_enc > 0) {
+ entry->embed_cuesheet.present = true;
+ entry->embed_cuesheet.pos = lseek(fd, 0, SEEK_CUR)
+ - framelen + cuesheet_offset;
+ entry->embed_cuesheet.size = totframelen
+ - cuesheet_offset;
+ entry->embed_cuesheet.encoding = char_enc;
+ }
+ break;
+ }
+
for (j = 0; j < bytesread; j++)
tag[j] = utf8buf[j];
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,
}
len -= read_len;
+ read_len = file_read_string(&file, id3->path, sizeof(id3->path), -1, len);
- if (file_read_string(&file, id3->path, sizeof(id3->path), -1, len) < 0)
+ if (read_len < 0)
{
return 0;
}
logf("Vorbis comment %d: %s=%s", i, name, id3->path);
- len = parse_tag(name, id3->path, id3, buf, buf_remaining,
- TAGTYPE_VORBIS);
+
+ /* Is it an embedded cuesheet? */
+ if (!strcasecmp(name, "CUESHEET"))
+ {
+ id3->embed_cuesheet.present = true;
+ id3->embed_cuesheet.pos = lseek(file.fd, 0, SEEK_CUR) - read_len;
+ id3->embed_cuesheet.size = len;
+ id3->embed_cuesheet.encoding = CHAR_ENC_UTF_8;
+ }
+ else
+ {
+ len = parse_tag(name, id3->path, id3, buf, buf_remaining,
+ TAGTYPE_VORBIS);
+ }
+
buf += len;
buf_remaining -= len;
}
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)
if (!checked_for_cuesheet && curr_cuesheet && id3->cuesheet == NULL)
{
checked_for_cuesheet = true; /* only check once per track */
- char cuepath[MAX_PATH];
+ struct cuesheet_file cue_file;
- if (look_for_cuesheet_file(id3->path, cuepath) &&
- parse_cuesheet(cuepath, curr_cuesheet))
+ if (look_for_cuesheet_file(id3, &cue_file)) &&
+ parse_cuesheet(&cue_file, curr_cuesheet))
{
id3->cuesheet = curr_cuesheet;
}
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,
/* If error other than a full buffer, then mark it "unsupported" to
avoid reloading attempt */
int hid = ERR_UNSUPPORTED_TYPE;
- char cuepath[MAX_PATH];
+ struct cuesheet_file cue_file;
#ifdef HAVE_IO_PRIORITY
buf_back_off_storage(true);
#endif
- if (look_for_cuesheet_file(track_id3->path, cuepath))
+ if (look_for_cuesheet_file(track_id3, &cue_file))
{
hid = bufalloc(NULL, sizeof (struct cuesheet), TYPE_CUESHEET);
@@ -1499,7 +1499,7 @@ static bool audio_load_cuesheet(struct track_info *info,
void *cuesheet = NULL;
bufgetdata(hid, sizeof (struct cuesheet), &cuesheet);
- if (parse_cuesheet(cuepath, (struct cuesheet *)cuesheet))
+ if (parse_cuesheet(&cue_file, (struct cuesheet *)cuesheet))
{
/* Indicate cuesheet is present (while track remains
buffered) */