summaryrefslogtreecommitdiff
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
45 45
46 46
47#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d) 47#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d)
48#define CHUNK_INFO 0x0001
49#define CHUNK_DATA 0x0002
50#define CHUNK_NEND 0x0004
51#define CHUNK_plst 0x0008
52#define CHUNK_time 0x0010
53#define CHUNK_fade 0x0020
54#define CHUNK_tlbl 0x0040
55#define CHUNK_auth 0x0080
56#define CHUNK_BANK 0x0100
48 57
49static bool parse_nsfe(int fd, struct mp3entry *id3) 58static bool parse_nsfe(int fd, struct mp3entry *id3)
50{ 59{
51 bool info_found = false; 60 unsigned int chunks_found = 0;
52 bool end_found = false; 61 long track_count = 0;
53 bool data_found = false; 62 long playlist_count = 0;
54 63
55 struct NSFE_INFOCHUNK info; 64 struct NSFE_INFOCHUNK info;
56 memset(&info, 0, sizeof(struct NSFE_INFOCHUNK)); 65 memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));
@@ -60,9 +69,9 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
60 id3->length = 2*1000*60; 69 id3->length = 2*1000*60;
61 70
62 /* begin reading chunks */ 71 /* begin reading chunks */
63 while (!end_found) 72 while (!(chunks_found & CHUNK_NEND))
64 { 73 {
65 int32_t chunk_size, chunk_type; 74 uint32_t chunk_size, chunk_type;
66 75
67 if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t)) 76 if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
68 return false; 77 return false;
@@ -72,36 +81,63 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
72 81
73 switch (chunk_type) 82 switch (chunk_type)
74 { 83 {
84 /* first three types are mandatory (but don't worry about NEND
85 anyway) */
75 case CHAR4_CONST('I', 'N', 'F', 'O'): 86 case CHAR4_CONST('I', 'N', 'F', 'O'):
76 { 87 {
77 /* only one info chunk permitted */ 88 if (chunks_found & CHUNK_INFO)
78 if (info_found) 89 return false; /* only one info chunk permitted */
79 return false;
80 90
81 info_found = true; 91 chunks_found |= CHUNK_INFO;
82 92
83 /* minimum size */ 93 /* minimum size */
84 if (chunk_size < 8) 94 if (chunk_size < 8)
85 return false; 95 return false;
86 96
87 ssize_t size = MIN((ssize_t)sizeof(struct NSFE_INFOCHUNK), 97 ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size);
88 chunk_size);
89 98
90 if (read(fd, &info, size) != size) 99 if (read(fd, &info, size) != size)
91 return false; 100 return false;
92 101
93 if (size >= 9) 102 if (size >= 9)
94 id3->length = info.nTrackCount*1000; 103 track_count = info.nTrackCount;
95 104
96 lseek(fd, chunk_size - size, SEEK_CUR); 105 chunk_size -= size;
97 break; 106 break;
98 } 107 }
99 108
100 case CHAR4_CONST('a', 'u', 't', 'h'): 109 case CHAR4_CONST('D', 'A', 'T', 'A'):
101 { 110 {
102 if (!info_found) 111 if (!(chunks_found & CHUNK_INFO))
112 return false;
113
114 if (chunks_found & CHUNK_DATA)
115 return false; /* only one may exist */
116
117 if (chunk_size < 1)
103 return false; 118 return false;
104 119
120 chunks_found |= CHUNK_DATA;
121 break;
122 }
123
124 case CHAR4_CONST('N', 'E', 'N', 'D'):
125 {
126 /* just end parsing regardless of whether or not this really is the
127 last chunk/data (but it _should_ be) */
128 chunks_found |= CHUNK_NEND;
129 continue;
130 }
131
132 /* remaining types are optional */
133
134 case CHAR4_CONST('a', 'u', 't', 'h'):
135 {
136 if (chunks_found & CHUNK_auth)
137 return false; /* only one may exist */
138
139 chunks_found |= CHUNK_auth;
140
105 /* szGameTitle, szArtist, szCopyright */ 141 /* szGameTitle, szArtist, szCopyright */
106 char ** const ar[] = { &id3->title, &id3->artist, &id3->album }; 142 char ** const ar[] = { &id3->title, &id3->artist, &id3->album };
107 143
@@ -120,39 +156,37 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
120 p += len; 156 p += len;
121 buf_rem -= len; 157 buf_rem -= len;
122 158
123 if (chunk_size >= len) 159 if (chunk_size >= (uint32_t)len)
124 chunk_size -= len; 160 chunk_size -= len;
125 else 161 else
126 chunk_size = 0; 162 chunk_size = 0;
127 } 163 }
128 164
129 lseek(fd, chunk_size, SEEK_CUR);
130 break; 165 break;
131 } 166 }
132 167
133
134 case CHAR4_CONST('D', 'A', 'T', 'A'):
135 if (chunk_size < 1)
136 return false;
137
138 data_found = true;
139 /* fall through */
140 case CHAR4_CONST('f', 'a', 'd', 'e'):
141 case CHAR4_CONST('t', 'i', 'm', 'e'):
142 case CHAR4_CONST('B', 'A', 'N', 'K'):
143 case CHAR4_CONST('p', 'l', 's', 't'): 168 case CHAR4_CONST('p', 'l', 's', 't'):
144 case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
145 { 169 {
146 if (!info_found) 170 if (chunks_found & CHUNK_plst)
147 return false; 171 return false; /* only one may exist */
172
173 chunks_found |= CHUNK_plst;
148 174
149 lseek(fd, chunk_size, SEEK_CUR); 175 /* each byte is the index of one track */
176 playlist_count = chunk_size;
150 break; 177 break;
151 } 178 }
152 179
153 case CHAR4_CONST('N', 'E', 'N', 'D'): 180 case CHAR4_CONST('t', 'i', 'm', 'e'):
181 case CHAR4_CONST('f', 'a', 'd', 'e'):
182 case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
154 { 183 {
155 end_found = true; 184 /* don't care how many of these there are even though there should
185 be only one */
186 if (!(chunks_found & CHUNK_INFO))
187 return false;
188
189 case CHAR4_CONST('B', 'A', 'N', 'K'):
156 break; 190 break;
157 } 191 }
158 192
@@ -166,19 +200,24 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
166 return false; 200 return false;
167 201
168 /* otherwise, just skip it */ 202 /* otherwise, just skip it */
169 lseek(fd, chunk_size, SEEK_CUR);
170 break; 203 break;
171 } 204 }
172 } /* end switch */ 205 } /* end switch */
206
207 lseek(fd, chunk_size, SEEK_CUR);
173 } /* end while */ 208 } /* end while */
174 209
210 if (track_count | playlist_count)
211 id3->length = MAX(track_count, playlist_count)*1000;
212
175 /* 213 /*
176 * if we exited the while loop without a 'return', we must have hit an NEND 214 * if we exited the while loop without a 'return', we must have hit an NEND
177 * chunk if this is the case, the file was layed out as it was expected. 215 * chunk if this is the case, the file was layed out as it was expected.
178 * now.. make sure we found both an info chunk, AND a data chunk... since 216 * now.. make sure we found both an info chunk, AND a data chunk... since
179 * these are minimum requirements for a valid NSFE file 217 * these are minimum requirements for a valid NSFE file
180 */ 218 */
181 return info_found && data_found; 219 return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) ==
220 (CHUNK_INFO | CHUNK_DATA);
182} 221}
183 222
184static bool parse_nesm(int fd, struct mp3entry *id3) 223static bool parse_nesm(int fd, struct mp3entry *id3)