diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2011-04-28 02:56:28 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2011-04-28 02:56:28 +0000 |
commit | ac724cca19b8e0564c921db7a2e1a1fc52ccbe18 (patch) | |
tree | 5a65db56eb1c921afd49188d938c7218baf04b08 /apps/metadata | |
parent | fa65362a42675d9d84a7ec57fdf5d8e1b575a4cd (diff) | |
download | rockbox-ac724cca19b8e0564c921db7a2e1a1fc52ccbe18.tar.gz rockbox-ac724cca19b8e0564c921db7a2e1a1fc52ccbe18.zip |
Get the NSF internal playlists working again. Fix a few wrongdoings in the metadata parser. Use the larger of track or playlist count to determine 'duration' so that the repeat-one switching to access the raw tracks works.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29793 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/metadata')
-rw-r--r-- | apps/metadata/nsf.c | 109 |
1 files changed, 74 insertions, 35 deletions
diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c index daffeb27ed..29fd8475bb 100644 --- a/apps/metadata/nsf.c +++ b/apps/metadata/nsf.c @@ -45,12 +45,21 @@ struct NSFE_INFOCHUNK #define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d) +#define CHUNK_INFO 0x0001 +#define CHUNK_DATA 0x0002 +#define CHUNK_NEND 0x0004 +#define CHUNK_plst 0x0008 +#define CHUNK_time 0x0010 +#define CHUNK_fade 0x0020 +#define CHUNK_tlbl 0x0040 +#define CHUNK_auth 0x0080 +#define CHUNK_BANK 0x0100 static bool parse_nsfe(int fd, struct mp3entry *id3) { - bool info_found = false; - bool end_found = false; - bool data_found = false; + unsigned int chunks_found = 0; + long track_count = 0; + long playlist_count = 0; struct NSFE_INFOCHUNK info; memset(&info, 0, sizeof(struct NSFE_INFOCHUNK)); @@ -60,9 +69,9 @@ static bool parse_nsfe(int fd, struct mp3entry *id3) id3->length = 2*1000*60; /* begin reading chunks */ - while (!end_found) + while (!(chunks_found & CHUNK_NEND)) { - int32_t chunk_size, chunk_type; + uint32_t chunk_size, chunk_type; if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t)) return false; @@ -72,36 +81,63 @@ static bool parse_nsfe(int fd, struct mp3entry *id3) switch (chunk_type) { + /* first three types are mandatory (but don't worry about NEND + anyway) */ case CHAR4_CONST('I', 'N', 'F', 'O'): { - /* only one info chunk permitted */ - if (info_found) - return false; + if (chunks_found & CHUNK_INFO) + return false; /* only one info chunk permitted */ - info_found = true; + chunks_found |= CHUNK_INFO; /* minimum size */ if (chunk_size < 8) return false; - ssize_t size = MIN((ssize_t)sizeof(struct NSFE_INFOCHUNK), - chunk_size); + ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size); if (read(fd, &info, size) != size) return false; if (size >= 9) - id3->length = info.nTrackCount*1000; + track_count = info.nTrackCount; - lseek(fd, chunk_size - size, SEEK_CUR); + chunk_size -= size; break; } - case CHAR4_CONST('a', 'u', 't', 'h'): + case CHAR4_CONST('D', 'A', 'T', 'A'): { - if (!info_found) + if (!(chunks_found & CHUNK_INFO)) + return false; + + if (chunks_found & CHUNK_DATA) + return false; /* only one may exist */ + + if (chunk_size < 1) return false; + chunks_found |= CHUNK_DATA; + break; + } + + case CHAR4_CONST('N', 'E', 'N', 'D'): + { + /* just end parsing regardless of whether or not this really is the + last chunk/data (but it _should_ be) */ + chunks_found |= CHUNK_NEND; + continue; + } + + /* remaining types are optional */ + + case CHAR4_CONST('a', 'u', 't', 'h'): + { + if (chunks_found & CHUNK_auth) + return false; /* only one may exist */ + + chunks_found |= CHUNK_auth; + /* szGameTitle, szArtist, szCopyright */ char ** const ar[] = { &id3->title, &id3->artist, &id3->album }; @@ -120,39 +156,37 @@ static bool parse_nsfe(int fd, struct mp3entry *id3) p += len; buf_rem -= len; - if (chunk_size >= len) + if (chunk_size >= (uint32_t)len) chunk_size -= len; else chunk_size = 0; } - lseek(fd, chunk_size, SEEK_CUR); break; } - - case CHAR4_CONST('D', 'A', 'T', 'A'): - if (chunk_size < 1) - return false; - - data_found = true; - /* fall through */ - case CHAR4_CONST('f', 'a', 'd', 'e'): - case CHAR4_CONST('t', 'i', 'm', 'e'): - case CHAR4_CONST('B', 'A', 'N', 'K'): case CHAR4_CONST('p', 'l', 's', 't'): - case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */ { - if (!info_found) - return false; + if (chunks_found & CHUNK_plst) + return false; /* only one may exist */ + + chunks_found |= CHUNK_plst; - lseek(fd, chunk_size, SEEK_CUR); + /* each byte is the index of one track */ + playlist_count = chunk_size; break; } - case CHAR4_CONST('N', 'E', 'N', 'D'): + case CHAR4_CONST('t', 'i', 'm', 'e'): + case CHAR4_CONST('f', 'a', 'd', 'e'): + case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */ { - end_found = true; + /* don't care how many of these there are even though there should + be only one */ + if (!(chunks_found & CHUNK_INFO)) + return false; + + case CHAR4_CONST('B', 'A', 'N', 'K'): break; } @@ -166,19 +200,24 @@ static bool parse_nsfe(int fd, struct mp3entry *id3) return false; /* otherwise, just skip it */ - lseek(fd, chunk_size, SEEK_CUR); break; } } /* end switch */ + + lseek(fd, chunk_size, SEEK_CUR); } /* end while */ + if (track_count | playlist_count) + id3->length = MAX(track_count, playlist_count)*1000; + /* * if we exited the while loop without a 'return', we must have hit an NEND * chunk if this is the case, the file was layed out as it was expected. * now.. make sure we found both an info chunk, AND a data chunk... since * these are minimum requirements for a valid NSFE file */ - return info_found && data_found; + return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) == + (CHUNK_INFO | CHUNK_DATA); } static bool parse_nesm(int fd, struct mp3entry *id3) |