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.c278
1 files changed, 0 insertions, 278 deletions
diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c
deleted file mode 100644
index 2fa6f36b12..0000000000
--- a/apps/metadata/nsf.c
+++ /dev/null
@@ -1,278 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12#include "string-extra.h"
13
14/* NOTE: This file was modified to work properly with the new nsf codec based
15 on Game_Music_Emu */
16
17struct NESM_HEADER
18{
19 uint32_t nHeader;
20 uint8_t nHeaderExtra;
21 uint8_t nVersion;
22 uint8_t nTrackCount;
23 uint8_t nInitialTrack;
24 uint16_t nLoadAddress;
25 uint16_t nInitAddress;
26 uint16_t nPlayAddress;
27 uint8_t szGameTitle[32];
28 uint8_t szArtist[32];
29 uint8_t szCopyright[32];
30 uint16_t nSpeedNTSC;
31 uint8_t nBankSwitch[8];
32 uint16_t nSpeedPAL;
33 uint8_t nNTSC_PAL;
34 uint8_t nExtraChip;
35 uint8_t nExpansion[4];
36} __attribute__((packed));
37
38struct NSFE_INFOCHUNK
39{
40 uint16_t nLoadAddress;
41 uint16_t nInitAddress;
42 uint16_t nPlayAddress;
43 uint8_t nIsPal;
44 uint8_t nExt;
45 uint8_t nTrackCount;
46 uint8_t nStartingTrack;
47} __attribute__((packed));
48
49
50#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d)
51#define CHUNK_INFO 0x0001
52#define CHUNK_DATA 0x0002
53#define CHUNK_NEND 0x0004
54#define CHUNK_plst 0x0008
55#define CHUNK_time 0x0010
56#define CHUNK_fade 0x0020
57#define CHUNK_tlbl 0x0040
58#define CHUNK_auth 0x0080
59#define CHUNK_BANK 0x0100
60
61static bool parse_nsfe(int fd, struct mp3entry *id3)
62{
63 unsigned int chunks_found = 0;
64 long track_count = 0;
65 long playlist_count = 0;
66
67 struct NSFE_INFOCHUNK info;
68 memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));
69
70 /* default values */
71 info.nTrackCount = 1;
72 id3->length = 150 * 1000;
73
74 /* begin reading chunks */
75 while (!(chunks_found & CHUNK_NEND))
76 {
77 uint32_t chunk_size, chunk_type;
78
79 if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
80 return false;
81
82 if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t))
83 return false;
84
85 switch (chunk_type)
86 {
87 /* first three types are mandatory (but don't worry about NEND
88 anyway) */
89 case CHAR4_CONST('I', 'N', 'F', 'O'):
90 {
91 if (chunks_found & CHUNK_INFO)
92 return false; /* only one info chunk permitted */
93
94 chunks_found |= CHUNK_INFO;
95
96 /* minimum size */
97 if (chunk_size < 8)
98 return false;
99
100 ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size);
101
102 if (read(fd, &info, size) != size)
103 return false;
104
105 if (size >= 9)
106 track_count = info.nTrackCount;
107
108 chunk_size -= size;
109 break;
110 }
111
112 case CHAR4_CONST('D', 'A', 'T', 'A'):
113 {
114 if (!(chunks_found & CHUNK_INFO))
115 return false;
116
117 if (chunks_found & CHUNK_DATA)
118 return false; /* only one may exist */
119
120 if (chunk_size < 1)
121 return false;
122
123 chunks_found |= CHUNK_DATA;
124 break;
125 }
126
127 case CHAR4_CONST('N', 'E', 'N', 'D'):
128 {
129 /* just end parsing regardless of whether or not this really is the
130 last chunk/data (but it _should_ be) */
131 chunks_found |= CHUNK_NEND;
132 continue;
133 }
134
135 /* remaining types are optional */
136
137 case CHAR4_CONST('a', 'u', 't', 'h'):
138 {
139 if (chunks_found & CHUNK_auth)
140 return false; /* only one may exist */
141
142 chunks_found |= CHUNK_auth;
143
144 /* szGameTitle, szArtist, szCopyright */
145 char ** const ar[] = { &id3->title, &id3->artist, &id3->album };
146
147 char *p = id3->id3v2buf;
148 long buf_rem = sizeof (id3->id3v2buf);
149 unsigned int i;
150
151 for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++)
152 {
153 long len = read_string(fd, p, buf_rem, '\0', chunk_size);
154
155 if (len < 0)
156 return false;
157
158 *ar[i] = p;
159 p += len;
160 buf_rem -= len;
161
162 if (chunk_size >= (uint32_t)len)
163 chunk_size -= len;
164 else
165 chunk_size = 0;
166 }
167
168 break;
169 }
170
171 case CHAR4_CONST('p', 'l', 's', 't'):
172 {
173 if (chunks_found & CHUNK_plst)
174 return false; /* only one may exist */
175
176 chunks_found |= CHUNK_plst;
177
178 /* each byte is the index of one track */
179 playlist_count = chunk_size;
180 break;
181 }
182
183 case CHAR4_CONST('t', 'i', 'm', 'e'):
184 case CHAR4_CONST('f', 'a', 'd', 'e'):
185 case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
186 {
187 /* don't care how many of these there are even though there should
188 be only one */
189 if (!(chunks_found & CHUNK_INFO))
190 return false;
191
192 case CHAR4_CONST('B', 'A', 'N', 'K'):
193 break;
194 }
195
196 default: /* unknown chunk */
197 {
198 /* check the first byte */
199 chunk_type = (uint8_t)chunk_type;
200
201 /* chunk is vital... don't continue */
202 if(chunk_type >= 'A' && chunk_type <= 'Z')
203 return false;
204
205 /* otherwise, just skip it */
206 break;
207 }
208 } /* end switch */
209
210 lseek(fd, chunk_size, SEEK_CUR);
211 } /* end while */
212
213 if (track_count | playlist_count)
214 id3->length = MAX(track_count, playlist_count)*1000;
215
216 /* Single subtrack files will be treated differently
217 by gme's nsf codec */
218 if (id3->length <= 1000) id3->length = 150 * 1000;
219
220 /*
221 * if we exited the while loop without a 'return', we must have hit an NEND
222 * chunk if this is the case, the file was layed out as it was expected.
223 * now.. make sure we found both an info chunk, AND a data chunk... since
224 * these are minimum requirements for a valid NSFE file
225 */
226 return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) ==
227 (CHUNK_INFO | CHUNK_DATA);
228}
229
230static bool parse_nesm(int fd, struct mp3entry *id3)
231{
232 struct NESM_HEADER hdr;
233 char *p = id3->id3v2buf;
234
235 lseek(fd, 0, SEEK_SET);
236 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
237 return false;
238
239 /* Length */
240 id3->length = (hdr.nTrackCount > 1 ? hdr.nTrackCount : 150) * 1000;
241
242 /* Title */
243 id3->title = p;
244 p += strlcpy(p, hdr.szGameTitle, 32) + 1;
245
246 /* Artist */
247 id3->artist = p;
248 p += strlcpy(p, hdr.szArtist, 32) + 1;
249
250 /* Copyright (per codec) */
251 id3->album = p;
252 strlcpy(p, hdr.szCopyright, 32);
253
254 return true;
255}
256
257bool get_nsf_metadata(int fd, struct mp3entry* id3)
258{
259 uint32_t nsf_type;
260 if (lseek(fd, 0, SEEK_SET) < 0 ||
261 read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type))
262 return false;
263
264 id3->vbr = false;
265 id3->filesize = filesize(fd);
266 /* we only render 16 bits, 44.1KHz, Mono */
267 id3->bitrate = 706;
268 id3->frequency = 44100;
269
270 if (nsf_type == CHAR4_CONST('N', 'S', 'F', 'E'))
271 return parse_nsfe(fd, id3);
272 else if (nsf_type == CHAR4_CONST('N', 'E', 'S', 'M'))
273 return parse_nesm(fd, id3);
274
275 /* not a valid format*/
276 return false;
277}
278