summaryrefslogtreecommitdiffstats
path: root/apps/metadata/nsf.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/metadata/nsf.c')
-rw-r--r--apps/metadata/nsf.c109
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)